<?php

if (!defined('BASEPATH')) {
    exit('No direct script access allowed');
}

class auth_google_model extends CI_Model
{

    protected $google_client = null;

    public function __construct()
    {
        parent::__construct();
        $this->load->model('ciext/core_model');
        $this->load->library('ciext/configurator');
    }

    public function get_auth_link()
    {
        // add scope
        $this->get_google_client()->addScope('https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/plus.login');

        return $this->get_google_client()->createAuthUrl();
    }

    public function auth($code)
    {
        $result = false;

        // get token
        $token = $this->get_google_client()->fetchAccessTokenWithAuthCode($code);
        $this->get_google_client()->setAccessToken($token);

        // get google userinfo data
        $oauth2 = new \Google_Service_Oauth2($this->get_google_client());
        $user_info = $oauth2->userinfo->get();

        if (isset($user_info->id)) {
            // register customer
            if (!$this->is_google_user_exist($user_info->id, $user_info->email)) {
                $this->register_google_user($user_info);
            }

            // auth customer
            $user = $this->get_user_by_google_id($user_info->id);
            if (isset($user['id_acl_user'])) {
                $this->session->set_userdata('id_user', $user['id_acl_user']);
                $result = true;
            }
        }

        return $result;
    }

    /**
     * @param string $google_user_id
     * @return bool
     */
    protected function is_google_user_exist($google_user_id)
    {
        return (!empty($this->get_user_by_google_id($google_user_id))) ? true : false;
    }

    /**
     * @param string $google_user_id
     * @return array
     */
    protected function get_user_by_google_id($google_user_id)
    {
        // prepare data
        $google_user_id = $this->db->escape_str($google_user_id);

        $id_lan = $this->core_model->get_lang_id();

        $user = $this->db->
                select('u.id_acl_user, u.login, u.photo, u.email, ut.name, ut.surname')->
                join('acl_user_translate ut', 'ut.id_acl_user=u.id_acl_user AND ut.id_lan=' . $id_lan, 'left')->
                join('acl_user_google ug', 'ug.id_acl_user=u.id_acl_user', 'left')->
                where('ug.google_user_id', $google_user_id)->
                get('acl_user u')->
                row_array();

        return $user;
    }

    /**
     * @param object $user_info
     */
    protected function register_google_user($user_info)
    {
        $user = $this->get_user_by_login($user_info->email);
        $id_lan = $this->core_model->get_lang_id();

        // load picture
        if (!empty($user_info->picture)) {
            $file_typeArr = explode('.', $user_info->picture);
            $picture_name = 'google_' . $user_info->id . '.' . end($file_typeArr);
            file_put_contents($this->get_app_path() . '/assets/uploads/userinfo/' . $picture_name, file_get_contents($user_info->picture));
        }

        // create new user
        if (empty($user)) {
            $this->db->insert('acl_user', array(
                'login'       => $user_info->email,
                'password'    => $this->rt_user->password_hash($this->get_user_pass()),
                'photo'       => (!empty($picture_name)) ? $picture_name : '',
                'email'       => $user_info->email,
                'id_acl_role' => 0,
                'registered'  => date('Y-m-d'),
                'confirmed'   => 1,
                'active'      => 1
            ));
            // get user id
            $user_id = $this->db->insert_id();

            $this->db->insert('acl_user_translate', array(
                'id_acl_user' => $user_id,
                'name'        => $user_info->givenName,
                'surname'     => $user_info->familyName,
                'id_lan'      => $id_lan,
            ));

            $this->db->insert('acl_user_google', array(
                'id_acl_user'    => $user_id,
                'google_user_id' => $user_info->id,
            ));
        } else {
            // update existing user
            $this->db->insert('acl_user_google', array(
                'id_acl_user'    => $user['id_acl_user'],
                'google_user_id' => $user_info->id,
            ));
        }
    }

    /**
     * @return \Google_Client
     */
    protected function get_google_client()
    {
        if (is_null($this->google_client)) {
            // load google api
            require_once $this->get_app_path() . 'vendor/autoload.php';

            $this->google_client = new Google_Client();
            $this->setAuthConfig($this->get_config_data('json_key'));
        }

        return $this->google_client;
    }

    protected function setAuthConfig($json)
    {
        if (!$config = json_decode($json, true)) {
            throw new LogicException('invalid json for auth config');
        }

        $key = isset($config['installed']) ? 'installed' : 'web';
        if (isset($config['type']) && $config['type'] == 'service_account') {
            // application default credentials
            $this->useApplicationDefaultCredentials();

            // set the information from the config
            $this->setClientId($config['client_id']);
            $this->google_client->setConfig('client_email', $config['client_email']);
            $this->google_client->setConfig('signing_key', $config['private_key']);
            $this->google_client->setConfig('signing_algorithm', $config['HS256']);
        } elseif (isset($config[$key])) {
            // old-style
            $this->google_client->setClientId($config[$key]['client_id']);
            $this->google_client->setClientSecret($config[$key]['client_secret']);
            if (isset($config[$key]['redirect_uris'])) {
                $this->google_client->setRedirectUri($config[$key]['redirect_uris'][0]);
            }
        } else {
            // new-style
            $this->google_client->setClientId($config['client_id']);
            $this->google_client->setClientSecret($config['client_secret']);
            if (isset($config['redirect_uris'])) {
                $this->google_client->setRedirectUri($config['redirect_uris'][0]);
            }
        }
    }

    /**
     * @param string $login
     * @return array
     */
    protected function get_user_by_login($login)
    {
        $user = $this->db->
                        select('id_acl_user')->
                        where('login', $login)->
                        get('acl_user')->row_array();

        return $user;
    }

    /**
     * @return string
     */
    protected function get_user_pass()
    {
        return $this->rt_user->password_hash('google user pass ' . time());
    }

    /**
     * @return string
     */
    protected function get_client_credentials_file()
    {
        return $this->get_config_data('json_key');
    }

    /**
     * @return string
     */
    public function get_app_path()
    {
        return dirname(dirname(dirname(dirname(BASEPATH)))) . '/';
    }

    /**
     * @param string $key
     * @return mixed
     */
    public function get_config_data($key)
    {
        $conf = new configurator('auth_google');

        return $conf->item($key);
    }

}
