<?php

namespace App\Libraries\Adapter\Auth;

use App\Entities\UserEntity;
use App\Entities\UserSNSEntity;

class GoogleAuth extends Auth
{
	private $_client = null;
	public function __construct(string $site,  $debug = false)
	{
		parent::__construct($site, $debug);
	}
	private function getClient(): \Google_Client
	{
		if (is_null($this->_client)) {
			$this->_client = new \Google_Client();
			$this->_client->setClientId(AUTH_ADAPTERS[$this->getSiteName()]['CLIENT_ID']);
			$this->_client->setClientSecret(AUTH_ADAPTERS[$this->getSiteName()]['CLIENT_KEY']);
			$this->_client->setRedirectUri(base_url() . AUTH_ADAPTERS[$this->getSiteName()]['CALLBACK_URL']);
			$this->_client->addScope('email');
			$this->_client->addScope('profile');
		}
		return $this->_client;
	}

	private function setAccessToken()
	{
		$formDatas = $this->getFormDatas();
		//1. Google 로그인후 인증코드 확인
		if (!isset($formDatas['code']) || !$formDatas['code']) {
			throw new \Exception($this->getSiteName() . " 인증 CallBack Code가 필요합니다.");
		}
		//2.토큰정보 가져오기
		$tokenInfo = $this->getClient()->fetchAccessTokenWithAuthCode($formDatas['code']);
		if (isset($tokenInfo['error'])) {
			throw new \Exception($tokenInfo['error']);
		}
		$token = $tokenInfo[AUTH_ADAPTERS[$this->getSiteName()]['TOKEN_NAME']];
		//3. Google Service에 접근하기위해 Access Token을 설정
		$this->getClient()->setAccessToken($token);

		//4. Google에 로그인이 했으므로 세션에 Token값 설정
		$this->_session->set(AUTH_ADAPTERS[$this->getSiteName()]['TOKEN_NAME'], $token);
	}
	private function getAccessToken(): ?string
	{
		return $this->_session->get(AUTH_ADAPTERS[$this->getSiteName()]['TOKEN_NAME']);
	}

	public function getAuthButton()
	{
		$button = "";
		if (!$this->getAccessToken()) {
			$button = anchor($this->getClient()->createAuthUrl(), AUTH_ADAPTERS[$this->getSiteName()]['ICON'], ["target" => "_self"]);
		}
		return $button;
	}

	protected function execute_process(): UserEntity
	{
		try {
			//Google 접근 권한 설정.
			$this->setAccessToken();
			//Google 서비스 설정
			$service = new \Google\Service\Oauth2($this->getClient());
			$result = $service->userinfo->get();
			if ($this->_debug) {
				log_message("debug", var_export($result, true));
			}
			// throw new \Exception(__METHOD__ . "에서 데이터 처리 필요");
			// DEBUG - 2023-07-13 12:54:51 --> \Google\Service\Oauth2\Userinfo::__set_state(array(
			// 	'internal_gapi_mappings' =>
			//    array (
			// 	 'familyName' => 'family_name',
			// 	 'givenName' => 'given_name',
			// 	 'verifiedEmail' => 'verified_email',
			//    ),
			// 	'modelData' =>
			//    array (
			// 	 'verified_email' => true,
			// 	 'given_name' => '이름',
			// 	 'family_name' => '성',
			//    ),
			// 	'processed' =>
			//    array (
			//    ),
			// 	'email' => 'twsdfsew342s@gmail.com',
			// 	'familyName' => '성',
			// 	'gender' => NULL,
			// 	'givenName' => '이름',
			// 	'hd' => NULL,
			// 	'id' => '103667492432234234236838324',
			// 	'link' => NULL,
			// 	'locale' => 'ko',
			// 	'name' => '성이름',
			// 	'picture' => 'https://lh3.googleusercontent.com/a/AAcHTteFSgefsdfsdRJBkJA2tBEmg4PQrvI1Ta_5IXu5=s96-c',
			// 	'verifiedEmail' => true,
			//  ))
			//조건에 해당하는 이미 등록된 사용자가 있는지 검사
			$snsEntity = $this->getUserSNSModel()->asObject(UserSNSEntity::class)->where(
				array("site" => $this->getSiteName(), "id" => $result['id'])
			)->first();
			//snsEntity 없으면 신규등록
			if (is_null($snsEntity)) {
				$snsEntity = $this->getUserSNSModel()->create([
					'site' => $this->getSiteName(),
					'id' => $result['id'],
					'name' => $result['name'],
					'email' => $result['email'],
					'detail' => json_encode($result),
					'status' => 'standby'
				]);
			}
			//상태가 use(승인완료)가 아니라면
			if ($snsEntity->status !== DEFAULTS['STATUS']) {
				throw new \Exception($this->getSiteName() . "의{$result['email']}:{$result['name']}님은 " . lang("Admin/UserSNS.label." . $snsEntity->status) . "입니다");
			}
			//user_id가 연결되어있지 않았다면
			if (!$snsEntity->user_id) {
				throw new \Exception($this->getSiteName() . "의{$result['email']}:{$result['name']}님은 아직 사용자 지정이 되지 않았습니다. ");
			}
			//인증된 사용자 정보를 가져온후 로그인처리
			$entity = $this->getUserModel()->getEntity($snsEntity->user_id);
			return $this->setSession_process($entity);;
		} catch (\Exception $e) {
			throw new \Exception("관리자에게 문의하시기 바랍니다.<BR>{$e->getMessage()}");
		}
	}
}
