<?php
namespace App\Models;

use CodeIgniter\Model;

class ExternalOAuth2Model extends Model
{
    public function prepareOauthEndPointData($endpoint, $in, &$call_backend=true,&$local_out=[]){
        log_message('critical', "Started prepareOauthEndPointData -> ".$endpoint );
        switch ($endpoint) {
            case 'authstart':
                // may not need to call back end , juet get the configurations
                switch($in["auth_type"]){
                    case 'GOOGLE':
                      log_message('critical', "Reading prepareOauthEndPointData -> ".$endpoint );
                      // Skip token exchange if we habe the access token already
                      if (isset($in["access_token"]) && $in["access_token"]!="") {
                        $local_out["access_token"] = $in["access_token"];
                      } else {
                          $this->gooleOAuthCodeExchange($in, $local_out);
                      }
                      log_message('critical', "LET SEEEEE TOKEN prepareOauthEndPointData -> ".$local_out["access_token"] );
                      if ( isset($local_out["access_token"])){
                          log_message('critical', "XXXXXXXXXXXXXXXXX prepareOauthEndPointData -> ".$endpoint );
                          $l_out =[];
                          $local_out["user_info"]  = $this->gooleOAuthGetUser($local_out["access_token"], $l_out);
                          log_message('critical', "prepareOauthEndPointDataL FINAL DATALOGIN  DATA STEP 889993".serialize( $local_out["user_info"] ) );
                          $this->provisionGoogleAccount($local_out["user_info"] , $local_out);
                      }
                      break;

                      case 'FACEBOOK':
                        log_message('critical', "Reading prepareOauthEndPointData -> ".$endpoint );
                        // Skip token exchange if we habe the access token already
                        if (isset($in["access_token"]) && $in["access_token"]!="") {
                            $local_out["access_token"] = $in["access_token"];
                        } else {
                            $this->facebookOAuthCodeExchange($in, $local_out);
                        }
                        log_message('critical', "LET SEEEEE TOKEN prepareOauthEndPointData -> ".$local_out["access_token"] );
                        if ( isset($local_out["access_token"])){
                            log_message('critical', "XXXXXXXXXXXXXXXXX prepareOauthEndPointData -> ".$endpoint );
                            $l_out =[];
                            $local_out["user_info"]  = $this->facebookOAuthGetUser($local_out["access_token"], $l_out);
                            log_message('critical', "prepareOauthEndPointDataL FINAL DATALOGIN  DATA STEP 889993".serialize( $local_out["user_info"] ) );
                            $this->provisionFacebookAccount($local_out["user_info"] , $local_out);
                        }
                        break;

                        case 'APPLE':
                            log_message('critical', "Reading prepareOauthEndPointData -> ".$endpoint );
                            if (array_key_exists("identityToken",$in) && trim($in["identityToken"])!="") {
                                // User info is already present
                                $local_out["user_info"] = $in;
                            } else {
                                $this->appleOAuthCodeExchange($in, $local_out);
                                if ( isset($local_out["access_token"])){
                                    log_message('critical', "XXXXXXXXXXXXXXXXX prepareOauthEndPointData -> ".$endpoint );
                                    $l_out =[];
                                    $local_out["user_info"] = $this->appleOAuthGetUser($local_out["access_token"], $l_out);
                                    log_message('critical', "prepareOauthEndPointDataL FINAL DATALOGIN  DATA STEP 889993".serialize( $local_out["user_info"] ) );
                                }
                            }
                            log_message('critical', "LET SEEEEE TOKEN prepareOauthEndPointData -> ".$local_out["access_token"] );
                            if (is_array($local_out["user_info"])) {
                                $this->provisionAppleAccount($local_out["user_info"] , $local_out);
                            }
                            break;                        
                }
                log_message('critical', "prepareOauthEndPointDataL FINAL DATA".serialize($local_out) );
                $call_backend=false;
                break;
            case 'authlogin':
                // not really implemented

                switch($in["auth_type"]){
                    case 'GOOGLE33':
                        log_message('critical', "prepareOauthEndPointDataL LOGIN  DATA STEP 2".serialize($in) );
                        $local_out["user_info"] =  $this->gooleOAuthGetUser($in["access_token"], $local_out);
                        log_message('critical', "prepareOauthEndPointDataL FINAL DATALOGIN  DATA STEP 3".serialize($local_out) );
                        $this->provisionGoogleAccount($local_out["user_info"] , $local_out);
                        break;
                }

                $in["action"] = WRENCHBOARD_ACCOUNT_AUXLOGIN;
                if (!isset($in["login_mode"])){
                    $in["login_mode"] = MOBILE_LOGIN;
                }
                break;
        }
        $in["pid"] = 100;
        return $in;
    }

    public function getSiteConfigurations($config_item){
        $wrenchboard = new  \App\Models\BackendModel();
        return  $wrenchboard->cfgReadChar($config_item);
    }

    private function gooleOAuthCodeExchange($in, &$local_out) {
        /*
        POST /token HTTP/1.1
        Host: oauth2.googleapis.com
        Content-Type: application/x-www-form-urlencoded

        code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7&
        client_id=your_client_id&
        client_secret=your_client_secret&
        redirect_uri=https%3A//oauth2.example.com/code&
        grant_type=authorization_code
        */

        $data = [
            "code" => $in["code"],
            "client_id" => $this->getSiteConfigurations("google.google_client_id"),
            "client_secret" => $this->getSiteConfigurations("google.google_client_secret"),
            "redirect_uri" => $in["redirect_uri"],
            "grant_type" => "authorization_code"
        ];
        $ch = curl_init();

        curl_setopt($ch, CURLOPT_URL,"https://oauth2.googleapis.com/token");
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
        curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/x-www-form-urlencoded'));
        // Receive server response ...
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

        $server_output = curl_exec($ch);

        curl_close($ch);

        $local_out = json_decode($server_output,true);

        if (!is_array($local_out) || !array_key_exists("message",$local_out)) {
             $local_out["message"] = "Received from Google token API: ".$server_output;
        }
    }

    private function gooleOAuthGetUser($access_token, &$local_out) {

        $urlInfp = "https://www.googleapis.com/oauth2/v1/userinfo?alt=json&access_token=" . $access_token;

        $ch = curl_init();

        curl_setopt($ch, CURLOPT_URL,$urlInfp);
        //curl_setopt($ch, CURLOPT_POST, 1);
        //curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
        curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/x-www-form-urlencoded'));
        // Receive server response ...
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

        $server_output = curl_exec($ch);

        curl_close($ch);

        $local_out = json_decode($server_output,true);

        if (!is_array($local_out) || !array_key_exists("message",$local_out)) {
            $local_out["message"] = "Received from Google token API: ".$server_output;
        }
        return $local_out;
    }

    private function facebookOAuthCodeExchange($in, &$local_out) {
        /*
      https://developers.facebook.com/docs/facebook-login/guides/advanced/manual-flow/#exchangecode
      Step 1. Get access token by code

      GET https://graph.facebook.com/v17.0/oauth/access_token?
        client_id={app-id}
        &redirect_uri={redirect-uri}
        &client_secret={app-secret}
        &code={code-parameter}

      https://developers.facebook.com/docs/facebook-login/guides/access-tokens/get-long-lived
      Step 2. Get long-lived token by access token
      
      curl -i -X GET "https://graph.facebook.com/{graph-api-version}/oauth/access_token?  
      grant_type=fb_exchange_token&          
      client_id={app-id}&
      client_secret={app-secret}&
      fb_exchange_token={your-access-token}" 
        */

        // Step 1. Get access token
        $data = [
            "client_id" => $this->getSiteConfigurations("facebook.facebook_client_id"),
            "client_secret" => $this->getSiteConfigurations("facebook.facebook_client_secret"),
            "redirect_uri" => $in["redirect_uri"],
            "code" => $in["code"]
        ];
        $ch = curl_init();

        $url = "https://graph.facebook.com/v17.0/oauth/access_token?" . http_build_query($data);
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_POST, 0);
        curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/x-www-form-urlencoded'));
        // Receive server response ...
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

        $server_output = curl_exec($ch);

        curl_close($ch);

        /*
        {
        "access_token": "EAAJogfssZCgYBOz16ZBqoASjMwZAGNfcISyfjSmPdQDJON3NLxnlSYmludsX1S6Hp9ZC7ZAeUIZBHLnC7HGIh3KRoxksrqdLO5lp1aNhXvB4ecUlRzUe1OOhaf0CAyuYkE4iJfDJr3Q05gjChWjVYr3gj0502kSCvZAxnwsbsyRtlFcXTzzXeJKqrnwAxZB9EzVkXcimas2ZBRdQ4mcutSZBLNYZCdvCcnIL61ypZCwlASvIfRlaenaZAgp4LnCf06w4ZD",
        "token_type": "bearer",
        "expires_in": 5181637
        }
        */

        $local_out = json_decode($server_output,true);

        if (!is_array($local_out) || !array_key_exists("message",$local_out)) {
             $local_out["message"] = "Received from Facebook token API: ".$server_output;
        }        

        ///////////////////////////////////////////////////////////////////////////////////////
        // IT LOOKS LIKE THE STEP 2 IS NOT NEEDED - BOTH TOKENS HAVE THE SAME EXPIRATION LENGTH
        ///////////////////////////////////////////////////////////////////////////////////////

        /*
        // Step 2. Get long-lived token
        $data = [
            "grant_type" => "fb_exchange_token",
            "client_id" => $this->getSiteConfigurations("facebook.facebook_client_id"),
            "client_secret" => $this->getSiteConfigurations("facebook.facebook_client_secret"),
            "fb_exchange_token" => $local_out["access_token"]
        ];
        $ch = curl_init();
        $url = "https://graph.facebook.com/v17.0/oauth/access_token" . http_build_query($data);
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_POST, 0);
        curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/x-www-form-urlencoded'));
        // Receive server response ...
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

        $server_output = curl_exec($ch);

        curl_close($ch);

        $local_out = json_decode($server_output,true); 
        //*/       
    }

    private function facebookOAuthGetUser($access_token, &$local_out) {
        // https://developers.facebook.com/docs/graph-api/reference/user/
        $urlInfp = "https://graph.facebook.com/me?fields=id,email,name,first_name,last_name&access_token=" . $access_token;

        $ch = curl_init();

        curl_setopt($ch, CURLOPT_URL,$urlInfp);
        //curl_setopt($ch, CURLOPT_POST, 1);
        //curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
        curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/x-www-form-urlencoded'));
        // Receive server response ...
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

        $server_output = curl_exec($ch);

        curl_close($ch);

        $local_out = json_decode($server_output,true);

        if (!is_array($local_out) || !array_key_exists("message",$local_out)) {
            $local_out["message"] = "Received from Google token API: ".$server_output;
        }
        return $local_out;
    }

    private function appleOAuthCodeExchange($in, &$local_out) {
        /*
      https://developer.apple.com/documentation/sign_in_with_apple/generate_and_validate_tokens

      POST https://appleid.apple.com/auth/token

      Content-Type: application/x-www-form-urlencoded
      client_id
      client_secret
      code
      grant_type = authorization_code | refresh_token
      refresh_token - when using refresh
      redirect_uri - no required?

      https://developer.apple.com/documentation/sign_in_with_apple/tokenresponse
      access_token
      expires_in
      id_token
      refresh_token
      token_type = bearer


      curl -v POST "https://appleid.apple.com/auth/token" \
        -H 'content-type: application/x-www-form-urlencoded' \
        -d 'client_id=CLIENT_ID' \
        -d 'client_secret=CLIENT_SECRET' \
        -d 'code=CODE' \
        -d 'grant_type=authorization_code' \
        -d 'redirect_uri=REDIRECT_URI'
        */

        // Step 1. Get access token
        $data = [
            "client_id" => $this->getSiteConfigurations("apple.apple_client_id"),
            "client_secret" => $this->getSiteConfigurations("apple.apple_client_secret"),
            /* "redirect_uri" => $in["redirect_uri"], */
            "code" => $in["code"],
            "grant_type" => "authorization_code"
        ];
        $ch = curl_init();

        curl_setopt($ch, CURLOPT_URL,"https://appleid.apple.com/auth/token");
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
        curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/x-www-form-urlencoded'));
        // Receive server response ...
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

        $server_output = curl_exec($ch);

        curl_close($ch);

        $local_out = json_decode($server_output,true);

        if (!is_array($local_out) || !array_key_exists("message",$local_out)) {
            $local_out["message"] = "Received from Apple token API: ".$server_output;
        }      
    }

    private function appleOAuthGetUser($access_token, &$local_out) {
        // Empty stub

        return $local_out;
    }

    /*
    *essage";s:326:"Received from Google token API: {
    "id": "112113008943138678578",
    "email": "jubaworker@gmail.com",
    "verified_email": true,
    "name": "Juba Juba",
    "given_name": "Juba",
    "family_name": "Juba",
    "picture": "https://lh3.googleusercontent.com/a/AAcHTtcVmXN4sjpZiUCZI5X6AwJWUhi46g4VRJqtIqW2G2cb=s96-c",
    "locale": "en"
    }
    */
    private function provisionGoogleAccount($user, &$out) {
        log_message('critical', "YYYYYYYYYYYYYYYYYYY prepareOauthEndPointData -> " );
        $name = (string) $user["name"];
        if (trim($name) == "") {
            $name = strtok($user["email"], "@");
        }

        $data['google_id'] = $user["id"];
        $data['action'] = WRENCHBOARD_GOOGLE_LOGIN;
        $data['firstname'] = $user["given_name"];
        $data['lastname'] = $user["family_name"];
        $data['email'] = $user["email"];
        $data['login_channel'] = LOGIN_GOOGLE;
        $data['sessionid'] = rand(10000, 99999) . "A" . rand(10000, 99999);

        // $this->load->model('backend_model');
        $out = array();

        $wrenchboard = new  \App\Models\BackendModel();
        $ret = $wrenchboard->wrenchboard_api($data, $out);
        $out['internal_return'] = $ret;
        if ($ret == PHP_LOGIN_OK) {


        } else {
            // Cannot proceed - backend error?
            // $msg = (is_array($out) && array_key_exists('status',$out) && $out['status']!='')
            //    ? $out ['status'] : json_encode($out);
            // $this->session->set_flashdata('login_message','Cannot proceed - error: '.$msg);
            // redirect('login');
        }

    }

    /*
    {
    "id": "10154230206933215",
    "email": "acidumirae@gmail.com",
    "name": "Anatolii Okhotnikov",
    "first_name": "Anatolii",
    "last_name": "Okhotnikov"
    }
    */
    private function provisionFacebookAccount($user, &$out) {
        log_message('critical', "YYYYYYYYYYYYYYYYYYY prepareOauthEndPointData -> " );
        $name = (string) $user["name"];
        if (trim($name) == "") {
            $name = strtok($user["email"], "@");
        }

        $data['fb_id'] = $user["id"];
        $data['action'] = WRENCHBOARD_FACEBOOK_LOGIN;
        $data['firstname'] = $user["first_name"];
        $data['lastname'] = $user["last_name"];
        $data['email'] = $user["email"];
        $data['login_channel'] = LOGIN_FACEBOOK;
        $data['sessionid'] = rand(10000, 99999) . "A" . rand(10000, 99999);

        // $this->load->model('backend_model');
        $out = array();

        $wrenchboard = new  \App\Models\BackendModel();
        $ret = $wrenchboard->wrenchboard_api($data, $out);
        $out['internal_return'] = $ret;
        if ($ret == PHP_LOGIN_OK) {


        } else {
            // Cannot proceed - backend error?
            // $msg = (is_array($out) && array_key_exists('status',$out) && $out['status']!='')
            //    ? $out ['status'] : json_encode($out);
            // $this->session->set_flashdata('login_message','Cannot proceed - error: '.$msg);
            // redirect('login');
        }

    }

    /*
      /*
      {
        "identityToken":"eyJraWQiOiJZdXlYb1kiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJodHRwczovL2FwcGxlaWQuYXBwbGUuY29tIiwiYXVkIjoiY29tLndyZW5jaGJvYXJkLnVzZXJzIiwiZXhwIjoxNjk0MzkzMzE3LCJpYXQiOjE2OTQzMDY5MTcsInN1YiI6IjAwMTgxMC4yMGU3NTAyOGQ0OWM0MmQ4YjQzMGI0MmQxZDc0ODdmMy4xMTU3Iiwibm9uY2UiOiIxLnB1ZmJwZGFhMzYiLCJjX2hhc2giOiJQRE1PNXNGa2pjOEtPclNNZDRjUGZnIiwiZW1haWwiOiJhY2lkdW1pcmFlQGdtYWlsLmNvbSIsImVtYWlsX3ZlcmlmaWVkIjoidHJ1ZSIsImF1dGhfdGltZSI6MTY5NDMwNjkxNywibm9uY2Vfc3VwcG9ydGVkIjp0cnVlLCJyZWFsX3VzZXJfc3RhdHVzIjoyfQ.fEnzaVgB2JaOZbQm2fkpC_J8if5tIIfAphQptZ9Bxp2wrjnDsGvN1b0gvB3KBswv7d6n4A1U46GpaGpShJDhN-e2lKw_lzgFJlRi9-1B-Fudp_gzK61r6W8JzzbPiD0GZgfp_ITPDdxdC7hzixVx4TW8djrV4TIXYjus0b5XnzqRVz2t3ed4Et55s_SZ53SVhM9qnDruVB-KgeGrvDVUks71iM1etuP2vO3xsSFoiKfMEcankX3JUJaCNRSdvVVeUBqH9TfhvmHrCopjnlJ8N2B8o8RDhbnt99OAJtE_dw_Qt5YAAg2ITYQVLBb2dniJ5FBsOBBwbiA0-W1hPJ3RpQ","authorizationCode":"ce0061e5858a34e468a373c3ea7344cdb.0.rryrq.rK6JjdqlVVi6S9coEcTgVQ",
        "email":null,
        "givenName":null,
        "familyName":null,
        "user":"001810.20e75028d49c42d8b430b42d1d7487f3.1157",
        "sub": "001810.20e75028d49c42d8b430b42d1d7487f3.1157",
        "jwt_email": "acidumirae@gmail.com",
        "email_verified": "true",
        "real_user_status": 2
      }
    */
    // real_user_status => The possible values are: 0 (or Unsupported), 1 (or Unknown), 2 (or LikelyReal).
    private function provisionAppleAccount($user, &$out) {
        log_message('critical', "YYYYYYYYYYYYYYYYYYY provisionAppleAccount -> " );
        $email = "";
        if ($user["email"] != null && $user["email"] != "null" && $user["email"] != "") {
            $email = $user["email"];
        } else if ($user["jwt_email"] != null && $user["jwt_email"] != "null" && $user["jwt_email"] != "") {
            $email = $user["jwt_email"];
        }
        $givenName = "";
        if ($user["givenName"] != null && $user["givenName"] != "null" && $user["givenName"] != "") {
            $givenName = $user["givenName"];
        }
        $familyName = "";
        if ($user["familyName"] != null && $user["familyName"] != "null" && $user["familyName"] != "") {
            $familyName = $user["familyName"];
        }
        $name = trim($givenName." ".$familyName);
        if (trim($name) == "") {
            $name = strtok($email, "@");
            if ($givenName == "") {
                $givenName = $name;
            }            
        }
        $apple_id = "";
        if ($user["sub"] != null && $user["sub"] != "null" && $user["sub"] != "") {
            $apple_id = $user["sub"];
        } else if ($user["user"] != null && $user["user"] != "null" && $user["user"] != "") {
            $apple_id = $user["user"];
        }

        $data['apple_id'] = $apple_id;
        $data['action'] = WRENCHBOARD_APPLE_LOGIN; // WRENCHBOARD_FACEBOOK_LOGIN
        $data['firstname'] = $givenName;
        $data['lastname'] = $familyName;
        $data['email'] = $email;
        $data['login_channel'] = LOGIN_APPLE; // LOGIN_FACEBOOK;
        $data['sessionid'] = rand(10000, 99999) . "A" . rand(10000, 99999);

        // $this->load->model('backend_model');
        $out = array();

        $wrenchboard = new  \App\Models\BackendModel();
        $ret = $wrenchboard->wrenchboard_api($data, $out);
        $out['internal_return'] = $ret;
        if ($ret == PHP_LOGIN_OK) {


        } else {
            // Cannot proceed - backend error?
            // $msg = (is_array($out) && array_key_exists('status',$out) && $out['status']!='')
            //    ? $out ['status'] : json_encode($out);
            // $this->session->set_flashdata('login_message','Cannot proceed - error: '.$msg);
            // redirect('login');
        }

    }
}