<?php  if (! defined('BASEPATH')) exit('No direct script access allowed');
/**
* Name: Facebook Login Library
*
* Author: appleboy
*
*/
require 'vendor/autoload.php';
//require_once 'vendor/facebook/php-sdk-v4/src/Facebook/autoload.php';
use Facebook\Facebook;
use Facebook\FacebookRequestException;
use Facebook\FacebookRedirectLoginHelper;
class Lib_login
{
    /**
     * CodeIgniter global
     *
     * @var string
     **/
    protected $ci;
    /**
     * @var FB
     */
    private $fb;

    private $helper;
    private $facebook_default_scope;
    private $facebook_login_url;
    private $facebook_logout_url;

    /**
     * __construct
     *
     * @return void
     * @author Ben
     **/
    public function __construct()
    {
        if (!session_id()) {
            session_start();
        } 
        $this->ci =& get_instance();
        $this->ci->load->library('session');
        $this->ci->config->load('facebook');
        $this->ci->load->helper('url');
        if (! isset($_SESSION)) {
            session_start();
        }
        $this->facebook_default_scope = explode(',', $this->ci->config->item("facebook_default_scope"));
        $facebook_app_id = $this->ci->config->item("facebook_app_id");
        $facebook_app_secret = $this->ci->config->item("facebook_app_secret");
        $this->facebook_login_url = base_url() . $this->ci->config->item("facebook_login_redirect_url").'/';
        $this->facebook_logout_url = base_url() . $this->ci->config->item("facebook_logout_redirect_url").'/';
        // init app with app id and secret
        $this->fb = new Facebook([
          'app_id' => $facebook_app_id, // Replace {app-id} with your app id
          'app_secret' => $facebook_app_secret,
          'default_graph_version' => 'v2.2',
        ]);
        $this->helper = $this->fb->getRedirectLoginHelper();
    }

    /**
     * @return FB
     */
    public function object()
    {
        return $this->fb;
    }

    /**
     * Check if user are logged in by checking if we have a Facebook
     * session active.
     *
     * @return mixed|boolean
     */
    public function is_authenticated()
    {
        $access_token = $this->authenticate();
        if (isset($access_token))
        {
            return $access_token;
        }
        return false;
    }

    /**
     * Destroy our local Facebook session
     */
    public function destroy_session()
    {
        $this->session->unset_userdata('fb_access_token');
    }

    public function getLoginUrl() {
        return $this->helper->getLoginUrl($this->facebook_login_url, $this->facebook_default_scope);
    }

    public function getLogoutUrl() {
        return $this->helper->getLogoutUrl($this->get_access_token(), $this->facebook_logout_url);
    }

    public function get_access_token() {
        return $this->session->userdata('fb_access_token');
    }

    /**
     * @return mixed
     */
    private function get_expire_time()
    {
        return $this->session->userdata('fb_expire');
    }
    /**
     * @param DateTime $time
     */
    private function set_expire_time(DateTime $time = null)
    {
        if ($time) {
            $this->session->set_userdata('fb_expire', $time->getTimestamp());
        }
    }

    public function authenticate()
    {
        $accessToken = $this->get_access_token();
        if ($accessToken && $this->get_expire_time() > (time() + 30) || $accessToken && !$this->get_expire_time())
        {
            $this->fb->setDefaultAccessToken($accessToken);
            return $accessToken;
        }
        // If we did not have a stored access token or if it has expired, try get a new access token
        try {
          $accessToken = $this->helper->getAccessToken($this->facebook_login_url);
        } catch(Facebook\Exceptions\FacebookResponseException $e) {
          // When Graph returns an error
          return $this->constructResult(NULL, 'Graph returned an error: ' . $e->getMessage());
        } catch(Facebook\Exceptions\FacebookSDKException $e) {
          // When validation fails or other local issues
          return $this->constructResult(NULL, 'Facebook SDK returned an error: ' . $e->getMessage());
        }

        if (! isset($accessToken)) {
          if ($this->helper->getError()) {
            /*header('HTTP/1.0 401 Unauthorized');
            echo "Error: " . $helper->getError() . "\n";
            echo "Error Code: " . $helper->getErrorCode() . "\n";
            echo "Error Reason: " . $helper->getErrorReason() . "\n";
            echo "Error Description: " . $helper->getErrorDescription() . "\n";
            */
            return $this->constructResult(NULL, 'Unauthorized: '.$this->helper->getErrorDescription());
          } else {
            return $this->constructResult(NULL, 'Bad request');
          }
        }
        // The OAuth 2.0 client handler helps us manage access tokens
        $oAuth2Client = $this->fb->getOAuth2Client();
        // Get the access token metadata from /debug_token
        ///$tokenMetadata = $oAuth2Client->debugToken($accessToken);

        if (! $accessToken->isLongLived()) {
            // Exchanges a short-lived access token for a long-lived one
            try {
                $accessToken = $oAuth2Client->getLongLivedAccessToken($accessToken);
                $this->set_expire_time($accessToken->getExpiresAt());
                $this->set_access_token($accessToken);
                $this->fb->setDefaultAccessToken($accessToken);
            } catch (Facebook\Exceptions\FacebookSDKException $e) {
                return $this->constructResult(NULL, "<p>Error getting long-lived access token: " . $this->helper->getMessage() . "</p>\n\n");
            }
            //var_dump($accessToken->getValue());
        }
        $_SESSION['fb_access_token'] = (string) $accessToken;

        return $accessToken;
    }

    public function getData($accessToken) {
        $user = NULL;
        try {
            // Returns a `Facebook\FacebookResponse` object
            if ($accessToken!="") {
                $response = $this->fb->get('/me?fields=id,name,email', $accessToken);
                $user = $response->getGraphUser();
            }
        } catch(Facebook\Exceptions\FacebookResponseException $e) {
            return $this->constructResult(NULL,'Graph returned an error: ' . $e->getMessage());
        } catch(Facebook\Exceptions\FacebookSDKException $e) {
            return $this->constructResult(NULL,'Facebook SDK returned an error: ' . $e->getMessage());
        }
        return $this->constructResult($user, NULL);
    }

    private function constructResult($me,$error) {
        $fb_data = array(
            'me' => $me,
            'error' => $error
        );
        $this->ci->session->set_userdata('fb_data', $fb_data);
        return $fb_data;
    }

    /**
     * Enables the use of CI super-global without having to define an extra variable.
     * I can't remember where I first saw this, so thank you if you are the original author.
     *
     * Borrowed from the Ion Auth library (http://benedmunds.com/ion_auth/)
     *
     * @param $var
     *
     * @return mixed
     */
    public function __get($var)
    {
        return get_instance()->$var;
    }
}
