<?php

declare(strict_types=1);

namespace app\controllers;

use yii;
use yii\web\Controller;
use yii\web\Response;
use yii\web\Cookie;
use yii\filters\AccessControl;

use app\models\Account;
use app\models\AccountForm;

class AccountController extends Controller
{
    public function behaviors()
    {
        return [
            'access' => [
                'class' => AccessControl::class,
                'rules' => [
                    [
                        'allow' => true,
                        'actions' => [
                            'file',
                            'data',
                            'restore',
                            'generate-password'
                        ]
                    ],
                    [
                        'allow' => true,
                        'roles' => ['@'],
                        'actions' => [
                            'index',
                            'edit',
                            'regenerate'
                        ]
                    ],
                    [
                        'allow' => true,
                        'actions' => [
                            'read',
                            'accept',
                            'decline'],
                        'matchCallback' => function ($rule, $action): bool {
                            if (
                                !yii::$app->user->isGuest
                                && (yii::$app->user->identity->type === 'administrator'
                                    || yii::$app->user->identity->type === 'moderator')
                            ) {
                                return true;
                            }

                            return false;
                        }
                    ],
                    [
                        'allow' => false,
                        'roles' => ['?'],
                        'denyCallback' => [$this, 'accessDenied']
                    ]
                ]
            ]
        ];
    }

    public function accessDenied()
    {
        // Инициализация
        $cookies = yii::$app->response->cookies;

        // Запись cookie с редиректом, который выполнится после авторизации
        $cookies->add(new Cookie([
            'name' => 'redirect',
            'value' => yii::$app->request->pathInfo
        ]));

        if (Yii::$app->request->isPost) {
            // POST-запрос

            // Настройка
            Yii::$app->response->format = Response::FORMAT_JSON;

            // Генерация ответа
            Yii::$app->response->content = json_encode([
                'main' => $this->renderPartial('/account/index'),
                'redirect' => yii::$app->request->pathInfo,
                '_csrf' => Yii::$app->request->getCsrfToken()
            ]);
        } else if (Yii::$app->request->isGet) {
            // GET-запрос

            $this->redirect('/authentication');
        }
    }

    public function actionIndex()
    {
        return $this->renderPartial('/accounts/index');
    }

    /**
     * Подтверждение
     *
     * @param int $_key Идентификатор аккаунта
     */
    public function actionAccept(string $_key)
    {
        if (yii::$app->user->isGuest) {
            // Аккаунт не аутентифицирован
        } else {
            if (yii::$app->request->isPost) {
                // AJAX-POST-запрос

                if (
                    yii::$app->user->identity->type === 'administrator'
                    || yii::$app->user->identity->type === 'moderator'
                ) {
                    // Запрос произведен уполномоченным

                    if ($account = Account::searchById(Account::collectionName() . '/' . $_key)) {
                        // Аккаунт найден

                        $account->type = 'user';

                        if ($account->update() > 0) {
                            // Удалось перезаписать данные в хранилище

                            // Запись в журнал
                            $account->journal('accepted into suppliers');

                            // Отправка письма с подтверждением аккаунта
                            $account->sendMailVerify();

                            // Настройка формата ответа
                            yii::$app->response->format = Response::FORMAT_JSON;

                            return true;
                        }
                    }
                }
            }
        }

        // Запись кода ответа
        yii::$app->response->statusCode = 500;

        return false;
    }

    /**
     * Отказ
     *
     * @param int $_key Идентификатор аккаунта
     */
    public function actionDecline(string $_key)
    {
        if (yii::$app->user->isGuest) {
            // Аккаунт не аутентифицирован
        } else {
            if (yii::$app->request->isPost) {
                // AJAX-POST-запрос

                if (
                    yii::$app->user->identity->type === 'administrator'
                    || yii::$app->user->identity->type === 'moderator'
                ) {
                    // Запрос произведен уполномоченным

                    if ($account = Account::searchById(Account::collectionName() . '/' . $_key)) {
                        // Аккаунт найден

                        // Отправка письма с отказом и причиной
                        $account->sendMailDecline(yii::$app->request->post('reason') ?? yii::$app->request->get('reason'));

                        // Настройка формата ответа
                        yii::$app->response->format = Response::FORMAT_JSON;

                        // Удаление аккаунта
                        return $account->delete() > 0;
                    }
                }
            }
        }

        // Запись кода ответа
        yii::$app->response->statusCode = 500;

        return false;
    }

    /**
     * Запрос файла
     *
     * @param int $_key Идентификатор аккаунта
     * @param string $file Путь до файла от каталога аккаунта
     */
    public function actionFile(string $_key, string $file)
    {
        // Инициализация файла
        $file = YII_PATH_PUBLIC . "/../assets/accounts/$_key/files/$file";

        if (file_exists($file)) {
            // Удалось найти файл

            return $this->response->sendFile($file);
        } else {
            // Не удалось найти файл

            // Запись кода ответа
            yii::$app->response->statusCode = 500;

            // Перенаправление на страницу аккаунта
            return yii::$app->response->redirect("/$_key");
        }
    }

    /**
     * Редактирование параметра
     *
     * @param int $_key
     * @param string $target
     *
     * @return void
     */
    public function actionEdit(int $_key, string $target)
    {
        if (yii::$app->user->isGuest) {
            // Аккаунт не аутентифицирован
        } else {
            if (yii::$app->request->isPost) {
                // AJAX-POST-запрос

                if (
                    $_key === yii::$app->user->identity->_key ||
                    (yii::$app->user->identity->type === 'administrator'
                        || yii::$app->user->identity->type === 'moderator')
                ) {
                    // Запрос произведен с изменяемого аккаунта, либо уполномоченным

                    if ($account = Account::searchById(Account::collectionName() . '/' . $_key)) {
                        // Аккаунт найден

                        // Запись параметра
                        $account->{$target} = yii::$app->request->post('value') ?? yii::$app->request->get('value') ?? 'Неизвестно';

                        // Настройка формата ответа
                        yii::$app->response->format = Response::FORMAT_JSON;

                        return $account->update() > 0;
                    }
                }
            }
        }

        // Запись кода ответа
        yii::$app->response->statusCode = 500;

        return false;
    }

    /**
     * Регенерация параметра
     *
     * @param int $_key Идентификатор
     * @param string $target
     *
     * @return void
     */
    public function actionRegenerate(int $_key, string $target)
    {
        if (yii::$app->user->isGuest) {
            // Аккаунт не аутентифицирован
        } else {
            if (yii::$app->request->isPost) {
                // AJAX-POST-запрос

                if ($account = Account::searchById(Account::collectionName() . '/' . $_key)) {
                    // Аккаунт найден

                    if (
                        $account->_key === yii::$app->user->identity->_key ||
                        (yii::$app->user->identity->type === 'administrator'
                            || yii::$app->user->identity->type === 'moderator')
                    ) {
                        // Запрос произведен с изменяемого аккаунта, либо уполномоченным

                        if ($target === 'indx') {
                            // Запрошена регенерация индекса

                            // Настройка формата ответа
                            yii::$app->response->format = Response::FORMAT_JSON;

                            // Регенерация индекса
                            return Account::generateIndexes([$account], force: true);
                        }
                    }
                }
            }
        }

        // Запись кода ответа
        yii::$app->response->statusCode = 500;

        return false;
    }

    /**
     * Информация
     *
     * @param int $_key Идентификатор
     */
    public function actionData(int $_key)
    {
        if (yii::$app->request->isPost) {
            // AJAX-POST-запрос

            // Инициализация аккаунта (тот кто выполняет запрос)
            $account = account::initAccount();

            // Поиск данных об аккаунта (запрашиваемом)
            $data = account::initAccount($_key)->getAttributes();

            if ($account->isAdmin() || $account->isModer()) {
                // Авторизован как работник
            } else if ((int) $account->_key === $_key) {
                // Авторизован как владелец аккаунта

                unset(
                    $data['vrfy'],
                    $data['geol'],
                    $data['auth'],
                    $data['jrnl'],
                    $data['acpt'],
                    $data['pswd']
                );
            } else {
                // Не авторизован

                // Очистка от защищенных свойств
                $data = [
                    '_key' => $data['_key'],
                    'indx' => $data['indx'],
                    'agnt' => $data['agnt'],
                    'type' => $data['type']
                ];
            }

            // Настройка формата ответа
            yii::$app->response->format = Response::FORMAT_JSON;

            return [
                'data' => $data,
                '_csrf' => Yii::$app->request->getCsrfToken()
            ];
        }
    }

    /**
     * Восстановление пароля
     *
     * @return string
     */
    public function actionRestore()
    {
        // Инициализация
        $model = new AccountForm(yii::$app->request->post('AccountForm'));
        $type = yii::$app->request->post('type') ?? yii::$app->request->get('type');
        $target = yii::$app->request->post('target') ?? yii::$app->request->get('target');

        // Фильтрация
        $target = match ($target) {
            'panel' => 'panel',
            'main' => 'main',
            default => 'main'
        };

        // Рендер для всплывающей панели
        $panel = $target === 'panel';

        if (yii::$app->request->isPost) {
            // AJAX-POST-запрос

            // Настройка кода ответа
            yii::$app->response->format = Response::FORMAT_JSON;

            if (yii::$app->user->isGuest || $model->validate()) {
                // Аккаунт не аутентифицирован и проверка пройдена

                // Отправка запроса на генерацию пароля и запись ответа
                $return = [
                    'status' => Account::restoreSend($model->mail),
                    '_csrf' => yii::$app->request->getCsrfToken()
                ];

                return $return;
            } else {
                // Аккаунт аутентифицирован

                // Настройка кода ответа
                yii::$app->response->statusCode = 400;

                return [
                    'redirect' => '/',
                    '_csrf' => yii::$app->request->getCsrfToken()
                ];
            }
        }
    }

    /**
     * Генерация нового пароля
     *
     * @return string
     */
    public function actionGeneratePassword(string $id, string $key)
    {
        if ($account = Account::searchById(Account::collectionName() . "/$id")) {
            // Найден аккаунт

            if ($account->chpk === $key) {
                // Ключи  совпадают

                // Инициализация буфера пароля
                $old = $account->pswd;

                // Генерация пароля
                $account->restoreGenerate();

                if ($account->pswd !== $old) {
                    // Успешно сгенерирован новый пароль

                    // Инициализация формы аутентификации
                    $form = new AccountForm;

                    // Запись параметров
                    $form->mail = $account->mail;
                    $form->pswd = $account->pswd;

                    // Аутентификация
                    $form->authentication();
                }
            }
        }

        // Перенаправление на главную страницу
        $this->redirect('/');
    }

    /**
     * Генерация нового пароля
     *
     * @return string
     */
    public function actionRead(int $page = 1): string|array|null
    {
        if (yii::$app->request->isPost) {
            // POST-запрос

            // Инициализация входных параметров
            $amount = yii::$app->request->post('amount') ?? yii::$app->request->get('amount') ?? 20;
            $order = yii::$app->request->post('order') ?? yii::$app->request->get('order') ?? ['DESC'];

            // Инициализация cookie
            $cookies = yii::$app->response->cookies;

            // Чтение аккаунтов
            $accounts = Account::read(limit: $amount, page: $page, order: $order);

            // Запись формата ответа
            yii::$app->response->format = Response::FORMAT_JSON;

            return [
                'accounts' => $this->renderPartial('/account/list', compact('accounts', 'amount', 'page')),
                '_csrf' => yii::$app->request->getCsrfToken()
            ];
        }

        return false;
    }
}
