<?php

namespace Shm\ShmBlueprints\Auth;

use Shm\Shm;
use Shm\ShmAuth\Auth;
use Shm\ShmDB\mDB;
use Shm\ShmUtils\I18n;
use Shm\ShmUtils\Response;

class ShmCallSet extends ShmAuthBase
{
    private string $callSetAuthCollection = '_call_set_auth';

    private array $testPhones = [
        79201111111,
        79202222222,
    ];

    private mixed $getCodeFunctionHandler = null;

    private int $timeLiveCallSetCode = 60 * 5;

    public function setGetCodeFunctionHandler($handler): static
    {
        $this->getCodeFunctionHandler = $handler;
        return $this;
    }

    private function getCode($phone)
    {
        if ($this->getCodeFunctionHandler) {
            return call_user_func($this->getCodeFunctionHandler, $phone);
        }

        return false;
    }

    public function make(): array
    {
        if (count($this->_authStructures) === 0) {
            throw new \Exception("No auth structures defined for Call Set");
        }

        return [
            'type' => Shm::boolean(),
            'description' => 'Установка телефона через входящий звонок с подтверждением',
            'args' => Shm::structure([
                'phone' => Shm::nonNull(Shm::string()),
                'code' => Shm::int(),
            ]),
            'resolve' => function ($root, $args) {
                $phone = (int) preg_replace("/[^,.0-9]/", '', $args['phone']);

                if (isset($args['code'])) {
                    return $this->confirmPhone($phone, (int) $args['code']);
                }

                return $this->sendConfirmationCode($phone);
            },
        ];
    }

    private function sendConfirmationCode(int $phone)
    {
        $this->validatePhoneSetRequest($phone);

        if (in_array($phone, $this->testPhones)) {
            $code = 9876;
        } else {
            $code = $this->getCode($phone);
        }

        mDB::collection($this->callSetAuthCollection)->insertOne([
            'user_id' => mDB::id(Auth::getAuthID()),
            'auth_collection' => Auth::getAuthCollection(),
            'phone' => $phone,
            'code' => (int) $code,
            'created_at' => time(),
            'ip' => $_SERVER['REMOTE_ADDR'] ?? null,
        ]);

        return null;
    }

    private function confirmPhone(int $phone, int $code): bool
    {
        [$phoneField, $currentAuthStructure] = $this->validatePhoneSetRequest($phone);

        $findCallSet = mDB::collection($this->callSetAuthCollection)->findOne(
            [
                'user_id' => mDB::id(Auth::getAuthID()),
                'phone' => $phone,
                'code' => $code,
                'created_at' => ['$gt' => time() - $this->timeLiveCallSetCode],
            ],
            [
                'sort' => ['_id' => -1],
            ]
        );

        if (!$findCallSet) {
            Response::validation(I18n::get('wrong_call_code'));
        }

        return $this->setPhoneForCurrentUser($phone, $phoneField, $currentAuthStructure);
    }
}
