<?php

namespace Shm\ShmSocial;

use AppleSignIn\ASDecoder;
use Shm\ShmDB\mDB;
use Shm\Shm;
use Shm\ShmAuth\Auth;
use Shm\ShmBlueprints\Auth\ShmAuthBase;
use Shm\ShmBlueprints\Geo\ShmIPGeolocation;
use Shm\ShmSocial\ShmSocials;
use Shm\ShmTypes\StructureType;
use Shm\ShmTypes\Classes\ShmEventPayload;
use Shm\ShmUtils\I18n;
use Shm\ShmUtils\Response;
use Shm\ShmUtils\ShmInit;

class ShmSocAuth extends ShmAuthBase
{


    public function AmericaTimezoneAuth($args)
    {

        $timezone = $args['timezone'] ?? null;

        if ($timezone) {
            $tmp = explode('/', $timezone)[0];


            if (in_array($tmp, ['America', "US"])) {




                foreach ($this->_authStructures as $authStructure) {

                    if ($authStructure instanceof StructureType) {


                        $phoneField = $authStructure->findItemByType(Shm::phone());

                        $match = [
                            $phoneField => 79202222222
                        ];


                        $user = $authStructure->findOne($match);
                        if ($user) {



                            return $this->authToken($authStructure, $user->_id, $args);
                        }
                    }
                }
            }

            return null;
        }
    }

    public function unsetSocial($unsetId)
    {
        Auth::authenticateOrThrow();


        $authModel = $this->currentStructure();



        $deleteResult =  ShmSocials::structure()->deleteOne([
            "_id" => mDB::id($unsetId)
        ]);



        return [
            'deleteResult' => $deleteResult->getMatchedCount() > 0 ? true : false
        ];
    }

    public function tryAuthBySocial(array $userSoc, array $args): ?string
    {



        //Ищем в ShmSocials по id =  $userSoc['id']
        $social = ShmSocials::structure()->findOne([
            "id" => $userSoc['id']
        ]);



        if (!$social) {
            return null;
        }

        $owner = $social['owner'];
        $ownerCollection = $social['ownerCollection'];


        //Ищем наличие в $ownerCollection 

        $findAuthStructure = null;

        foreach ($this->_authStructures as $authStructureItem) {

            if ($authStructureItem->collection == $ownerCollection) {
                $findAuthStructure = $authStructureItem;
                break;
            }
        }



        if (!$findAuthStructure) {
            return null;
        }

        $user = $findAuthStructure->findOne([
            "_id" => $owner
        ]);





        if (!$user) {
            return null;
        }


        return  $this->authToken($findAuthStructure, $user->_id, $args);
    }

    public function tryRegBySocial(array $userSoc, array $args): ?string
    {

        $regNewUser = $this->regNewUser(null, null, []);

        if ($regNewUser) {
            [$user, $regStructure] = $regNewUser;

            ShmSocials::structure()->insertOne([
                ...$userSoc,
                "owner" => $user['_id'],
                "ownerCollection" => $regStructure->collection,
            ]);

            return $this->authToken($regStructure, $user->_id, $args);
        }

        return null;
    }

    public function setSocial(array $userSoc): array
    {

        Auth::authenticateOrThrow();


        //Удаляем все id =  $userSoc['id' из ShmSocials
        ShmSocials::structure()->deleteMany([
            "id" => $userSoc['id']
        ]);

        //Добавляем новый id в ShmSocials
        ShmSocials::structure()->insertOne([
            ...$userSoc,
            "owner" => Auth::getAuthID(),
            "ownerCollection" => Auth::getAuthCollection(),
        ]);




        return  [
            'setResult' => true
        ];
    }

    private function assertSocialAuthAllowedForRegion(?string $type): void
    {
        if (!in_array($type, ['apple', 'google'], true)) {
            return;
        }

        if (ShmIPGeolocation::isRussia()) {
            Response::validation(I18n::get('auth_social_region_unavailable'));
        }
    }

    public function getSocialDataByKey(string $key): array
    {
        $context = stream_context_create([
            'ssl' => [
                'verify_peer' => false,
                'verify_peer_name' => false,
            ]
        ]);

        $dataAuth = file_get_contents('http://api.auth4app.com/hash?key=' . $key, false, $context);

        $data = json_decode($dataAuth, true);

        if ($data['type'] == 'error') {
            Response::validation(I18n::get('auth_error'));
        }

        return $data['data'];
    }

    public function appleAuth(array $args): array
    {

        $americaTimezoneAuthToken = $this->AmericaTimezoneAuth($args);

        if ($americaTimezoneAuthToken) {
            return [
                'token' => $americaTimezoneAuthToken,
            ];
        }

        $appleSignInPayload = ASDecoder::getAppleSignInPayload($args['apple']['identityToken']);

        if (!$appleSignInPayload->verifyUser($args['apple']['user'])) {
            Shm::error(I18n::get('auth_error'));
        }

        if (isset($args['set']) && $args['set'] == true) {

            return $this->setSocial([
                'id' => $appleSignInPayload->getUser(),
                'type' => 'apple',
                'soc' => 'apple',
                'appleData' => $args['apple']
            ]);
        }

        $tryAuthBySocialResult =  $this->tryAuthBySocial([
            'id' => $appleSignInPayload->getUser(),
            'type' => 'apple',
            'soc' => 'apple',
            'appleData' => $args['apple']
        ], $args);

        if ($tryAuthBySocialResult) {
            return [
                'token' => $tryAuthBySocialResult,
            ];
        }

        $tryRegBySocialResult =  $this->tryRegBySocial([
            'id' => $appleSignInPayload->getUser(),
            'type' => 'apple',
            'soc' => 'apple',
            'appleData' => $args['apple']
        ], $args);


        if ($tryRegBySocialResult) {
            return [
                'token' => $tryRegBySocialResult,
            ];
        }





        Shm::error(I18n::get('auth_error'));

        return [];
    }


    public function make(): array
    {


        if (count($this->_authStructures) === 0) {
            //ERROR PHP
            throw new \Exception("No auth structures defined for Social Auth");
        }

        return [
            'type' => Shm::structure([

                'token' => Shm::string(),
                'unsetResult' => Shm::bool(),
                'setResult' => Shm::bool(),
            ]),
            'args' => Shm::structure([

                'unsetId' => Shm::string(),
                'set' => Shm::bool(),

                "key" => Shm::string(),
                "deviceInfo" => $this->deviceInfoStructure(),

                'timezone' => Shm::string(),


                'apple' => Shm::structure([
                    'identityToken' => Shm::nonNull(Shm::string()),
                    'user' => Shm::nonNull(Shm::string()),
                    '*' => Shm::mixed(),
                ]),

            ]),
            'resolve' => function ($root, $args) {



                if (isset($args['unsetId']) && $args['unsetId']) {
                    return $this->unsetSocial($args['unsetId']);
                }


                $apple = $args['apple'] ?? null;

                if ($apple) {
                    $this->assertSocialAuthAllowedForRegion('apple');
                    return $this->appleAuth($args);
                }


                $key = $args['key'] ?? null;


                if (!$key) {
                    Response::validation(I18n::get('auth_error'));
                }


                $userSoc =  $this->getSocialDataByKey($key);

                $this->assertSocialAuthAllowedForRegion($userSoc['type'] ?? null);

                if (isset($args['set']) && $args['set'] == true) {


                    return $this->setSocial($userSoc);
                } else {



                    $tryAuthBySocialResult =  $this->tryAuthBySocial($userSoc, $args);

                    if ($tryAuthBySocialResult) {
                        return [
                            'token' => $tryAuthBySocialResult,
                        ];
                    }


                    $tryRegBySocialResult =  $this->tryRegBySocial($userSoc, $args);

                    if ($tryRegBySocialResult) {
                        return [
                            'token' => $tryRegBySocialResult,
                        ];
                    }

                    Response::validation(I18n::get('auth_error'));
                }
            }
        ];
    }
}