<?php

declare(strict_types=1);

namespace mirzaev\deeproots\models;

// Files of the project
use mirzaev\deeproots\models\core,
    mirzaev\deeproots\models\connection,
    mirzaev\deeproots\models\telegram,
    mirzaev\deeproots\models\enumerations\language,
    mirzaev\deeproots\models\account\localization;

// Svoboda time
use svoboda\time\statement as svoboda;

// Baza database
use mirzaev\baza\database,
    mirzaev\baza\column,
    mirzaev\baza\record,
    mirzaev\baza\enumerations\encoding,
    mirzaev\baza\enumerations\type;

// Built-in libraries
use Exception as exception,
    RuntimeException as exception_runtime;

/**
 * Account
 *
 * @package mirzaev\deeproots\models
 *
 * @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
 * @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
 */
final class account extends core
{
    /**
     * File
     *
     * @var string $database Path to the database file
     */
    protected string $file = DATABASES . DIRECTORY_SEPARATOR . 'accounts.baza';

    /**
     * Database
     *
     * @var database $database The database
     */
    public protected(set) database $database;

    /**
     * Constructor
     *
     * @return void
     */
    public function __construct()
    {
        // Initializing the database
        $this->database = new database()
            ->encoding(encoding::utf8)
            ->columns(
                new column('identifier', type::long_long_unsigned),
                new column('name', type::string, ['length' => 64]),
                new column('language', type::string, ['length' => 2]),
                new column('authorized_system', type::char),
                new column('authorized_game_play', type::char),
                new column('authorized_rating_display', type::char),
                new column('authorized_balance_deposit', type::char),
                new column('authorized_balance_withdraw', type::char),
                new column('authorized_settings', type::char),
                new column('authorized_system_accounts', type::char),
                new column('authorized_system_questions', type::char),
                new column('authorized_system_settings', type::char),
                new column('updated', type::integer_unsigned),
                new column('created', type::integer_unsigned)
            )
            ->connect($this->file);
    }

    /**
     * Initialize
     *
     * Searches for the account record by the telegram account in the database,
     * and if it does not find it, then create the account record and the connection record
     *
     * @param record $telegram The telegram account
     *
     * @throws exception_runtime if failed to deactivate the connection between missing account and the telegram account
     * @throws exception_runtime if failed to connect the account with the telegram account
     * @throws exception_runtime if failed to find the created account
     * @throws exception_runtime if failed to create the account
     *
     * @return record The account record from the database
     */
    public function initialize(record $telegram): record
    {
        // Initializing the connection model
        $connection = new connection;

        // Searching for the connection record between theaccount and the telegram account in the database
        $connected = $connection->database->read(filter: fn(record $record) => $record->telegram === $telegram->identifier, amount: 1)[0] ?? null;

        if ($connected instanceof record) {
            // Found the connection record between the account and the telegram account

            // Searching for the account in the database
            $account = $this->database->read(filter: fn(record $record) => $record->identifier === $connected->account, amount: 1)[0] ?? null;

            if ($account instanceof record) {
                // Found the account

                // Exit (success)
                return $account;
            } else {
                // Not found the account

                // Deactivating the connection between missing account and the telegram account
                $deactivated = $connected->read(
                    filter: fn(record $record) => $record->identifier === $connected->identifier,
                    update: function (record &$record) {
                        $record->active = 0;
                        $record->updated = svoboda::timestamp();
                    },
                    amount: 1)[0] ?? null;

                if ($deactivated instanceof record && $deactivated->active === 0) {
                    // Deactivated the connection between missing account and the telegram account

                    // Creating the account
                    goto create;
                } else {
                    // Failed to deactivate the connection between missing account and the telegram account

                    // Exit (fail)
                    throw new exception_runtime('Failed to deactivate the connection between missing account and the telegram account');
                }
            }
        } else {
            // Not found the connection record between the account and the telegram account

            // Creating the account process start
            create:

            // Creating the account
            $identifier = $this->create("$telegram->name_first $telegram->name_second", language::{$telegram->language ?? language::en->name} ?? language::en);

            if ($identifier) {
                // Created the account

                // Searching for the created account in the database
                $account = $this->database->read(filter: fn(record $record) => $record->identifier === $identifier, amount: 1)[0] ?? null;

                if ($account instanceof record) {
                    // Found the created account

                    // Connecting the created account with the telegram account
                    $connected = $connection->create(account: $account->identifier, telegram: $telegram->identifier);

                    if ($connected) {
                        // Connected the created account with the telegram account

                        // Exit (success)
                        return $account;
                    }   else {
                        // Not connected the created account with the telegram account

                        // Exit (fail)
                        throw new exception_runtime('Failed to connect the account with the telegram account');
                    }
                } else {
                    // Not found the created account

                    // Exit (fail)
                    throw new exception_runtime('Failed to find the created account');
                }
            } else {
                // Not created the account

                // Exit (fail)
                throw new exception_runtime('Failed to create the account');
            }
        }
    }

    /**
     * Create
     *
     * Creates the account record in the database
     *
     * @param telegram $telegram The telegram account
     *
     * @return int|false The record identifier, if created
     */
    public function create(string $name, language $language): int|false
    {
        // Initializing the identifier
        $identifier = $this->database->count() + 1;

        // Initializing the record
        $record = $this->database->record(
            $identifier,
            $name,
            $language->name,
            ACCOUNT_ACCESS_SYSTEM,
            ACCOUNT_ACCESS_GAME_PLAY,
            ACCOUNT_ACCESS_RATING_DISPLAY,
            ACCOUNT_ACCESS_BALANCE_DEPOSIT,
            ACCOUNT_ACCESS_BALANCE_WITHDRAW,
            ACCOUNT_ACCESS_SETTINGS,
            ACCOUNT_ACCESS_SYSTEM_ACCOUNTS,
            ACCOUNT_ACCESS_SYSTEM_QUESTIONS,
            ACCOUNT_ACCESS_SYSTEM_SETTINGS,
            svoboda::timestamp(),
            svoboda::timestamp()
        );

        // Creating the record in the database
        $created = $this->database->write($record);

        // Exit (success)
        return $created ? $identifier : false;
    }
}
