<?php

declare(strict_types=1);

namespace app\controllers;

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

use app\models\Account;
use app\models\Supply;
use app\models\SupplyGroup;
use app\models\Search;
use app\models\Notification;
use app\models\Settings;
use app\models\Dellin;
use app\models\SettingsEdgeSettings;
use app\models\Terminal;
use app\models\Import;
use app\models\ImportEdgeSupply;
use app\models\Warehouse;
use app\models\WarehouseEdgeImport;
use Dadata\DadataClient as Dadata;

use Throwable;

class ProfileController extends Controller
{
    public function behaviors()
    {
        return [
            'access' => [
                'class' => AccessControl::class,
                'rules' => [
                    [
                        'allow' => true,
                        'actions' => [
                            'geolocation-init'
                        ]
                    ],
                    [
                        'allow' => true,
                        'roles' => ['@'],
                        'actions' => [
                            'index',
                            'supplies',
                            'import',
                            'monitoring',
                            'geolocation-write',
                            'panel-suppliers-requests-search',
                            'imports-delete',
                            'warehouses-write',
                            'warehouses-rename',
                            'warehouses-delete',
                            'warehouses-close',
                            'warehouses-open'
                        ]
                    ],
                    [
                        'allow' => true,
                        'actions' => ['panel', 'panel-notification-write'],
                        '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' => '/profile',
                '_csrf' => Yii::$app->request->getCsrfToken()
            ]);
        } else if (Yii::$app->request->isGet) {
            // GET-запрос

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

    /**
     * Страница с настройками аккаунта
     */
    public function actionIndex(): string|array
    {
        // Инициализация
        $model = yii::$app->user->identity;
        $panel = yii::$app->request->post('panel') ?? yii::$app->request->get('panel');
        $redirect = yii::$app->request->post('redirect') ?? yii::$app->request->get('redirect');
        $sidebar = $this->renderPartial('sidebar');

        // Обработка настроек аккаунта
        if ($vars = yii::$app->request->post('Account') ?? yii::$app->request->get('Account')) {
            // Обнаружены входные параметры

            if (isset($vars['opts'])) {
                // Переданы параметры

                // Инициализация
                is_array($model->opts) || $model->opts = [];

                // Запись в буфер
                $model->opts = array_merge($model->opts, $vars['opts']);

                // Запись в базу данных
                $model->update();
            } else {
                /**
                 * @todo Написать обработчик ошибок
                 */
            }
        }

        // Инициализация
        $delivery_to_terminal_list = $model->genListTerminalsTo();
        $import_oem_list = $model->genListOem(Supply::searchByAccount(select: 'supply.onec["ЗначенияСвойств"]'));
        $array_unshift_in_start = function (array &$array, string|int $key, mixed $value) {
            $array = array_reverse($array, true);
            $array[$key] = $value;
            return $array = array_reverse($array, true);
        };
        $array_write_default_value = function (array &$array, string $key = 'Выберите', string $value = 'Выберите') use ($array_unshift_in_start) {
            if (isset($array[$key])) {
                // Смещение или ассоциация найдена

                // Деинициализация
                unset($array[$key]);

                // Инициализация
                $array_unshift_in_start($array, $key, $value);
            }
        };

        // Сортировка по алфавиту
        asort($delivery_to_terminal_list);
        asort($import_oem_list);

        // Перемещение в начало массива значения "Выберите"
        $array_write_default_value($delivery_to_terminal_list);
        $array_write_default_value($import_oem_list);

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

            yii::$app->response->format = Response::FORMAT_JSON;

            // Инициализация буфера вывода
            $return = ['_csrf' => yii::$app->request->getCsrfToken()];

            if (!empty($redirect)) {
                // Передан маршрут перенаправления

                // Запись маршрута перенаправления
                $return['redirect'] = $redirect;

                if ($redirect === '/profile') {
                    // Перенаправление на страницу профиля

                    $return['main'] = $this->renderPartial('index', compact(
                        'model',
                        'sidebar',
                        'delivery_to_terminal_list',
                        'import_oem_list',
                        'panel'
                    ));
                }
            }

            return $return;
        }

        return $this->render('index', compact(
            'model',
            'sidebar',
            'delivery_to_terminal_list',
            'import_oem_list',
            'panel'
        ));
    }

    /**
     * Страница панели управления для доверенных пользователей
     */
    public function actionPanel(): string|array
    {
        // Инициализация
        $model_notifications = null;
        $panel = yii::$app->request->post('panel') ?? yii::$app->request->get('panel');
        $sidebar = $this->renderPartial('sidebar');

        if (!$model_settings = Settings::readLast()) {
            $model_settings = new Settings();

            if (!$model_settings->save()) {
                $this->redirect('/');
            }
        }

        if ($vars = yii::$app->request->post('Notification') ?? yii::$app->request->get('Notification')) {
            // Обнаружены входные параметры из раздела "Уведомления"

            // Реинициализация с новыми параметрами
            $model_notifications = new Notification($vars);

            // Запись уведомления и отправка (запись ребра до аккаунта)
            $model_notifications->write();
        } else if ($vars = yii::$app->request->post('Settings') ?? yii::$app->request->get('Settings')) {
            // Обнаружены входные параметры из раздела "Настройки"

            if ($to = new Settings($vars)) {
                // Настройки инициализированы

                // Отправка
                if ($to->save()) {
                    // Сохранено в базе данных

                    // Буфер
                    $from = $model_settings;

                    // Реинициализация (для представления)
                    $model_settings = $to;

                    if ($from) {
                        // Найдена старая версия настроек

                        // Запись ребра: НАСТРОЙКИ (старые) -> НАСТРОЙКИ (новые)
                        SettingsEdgeSettings::write($from->readId(), $to->readId(), 'update');
                    }
                } else {
                    // Не сохранено в базе данных

                    // Запись ошибок
                    $model_settings->addErrors($to->getErrors());
                }
            }
        }

        // Деинициализация
        unset($vars);

        // Раздел "Поставщики"

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

            yii::$app->response->format = Response::FORMAT_JSON;

            return [
                'main' => $this->renderPartial('panel', compact(
                    'model_notifications',
                    'model_settings',
                    'sidebar',
                    'panel'
                )),
                'redirect' => '/profile/panel',
                '_csrf' => yii::$app->request->getCsrfToken()
            ];
        }

        return $this->render('panel', compact(
            'model_notifications',
            'model_settings',
            'sidebar',
            'panel'
        ));
    }

    /**
     * Страница мониторинга
     */
    public function actionMonitoring(Account|int|null $account = null): string|array
    {
        // Инициализация
        $panel = yii::$app->request->post('panel') ?? yii::$app->request->get('panel');
        $sidebar = $this->renderPartial('sidebar');

        if (is_null($account)) {
            // Данные аккаунта не переданы

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

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

                // Инициализация
                $account = yii::$app->user->identity;
            }
        } else {
            if (is_int($account)) {
                // Передан идентификатор (_key) аккаунта (подразумевается)

                // Инициализация (поиск в базе данных)
                if (!$account = Account::searchById(Account::collectionName() . "/$account")) {
                    // Не удалось инициализировать аккаунт

                    return [];
                }
            }
        }

        // Инициализация номера страницы
        $page_search_history = (yii::$app->request->post('search') ?? yii::$app->request->get('search')) - 1;

        if ($page_search_history <= 0) {
            // Вышли за границу поиска перед первой страницей

            // Инициализация
            $page_search_history = 0;
        }

        // Инициализация количества строк на одной странице
        $rows_amount = 10;

        $search_history = Search::SearchByEdge(
            from: 'account',
            to: 'search',
            subquery_where: [
                [
                    'account._id' => yii::$app->user->id
                ]
            ],
            foreach: ['edge' => 'account_edge_search'],
            where: 'edge._to == search._id',
            limit: $rows_amount,
            offset: $offset = ((int) $page_search_history ?? 0) * $rows_amount
        );

        // Проверка результатов
        monitoring_result_check:

        if (count($search_history) === 0 && $offset !== 0) {
            // Вышли за границу поиска после последней страницы

            // Реинициализация (вычитание для идентичного конечного результата)
            --$page_search_history;

            $search_history = Search::SearchByEdge(
                from: 'account',
                to: 'search',
                subquery_where: [
                    [
                        'account._id' => yii::$app->user->id
                    ]
                ],
                foreach: ['edge' => 'account_edge_search'],
                where: 'edge._to == search._id',
                limit: $rows_amount,
                offset: $offset = ((int) $page_search_history ?? 0) * $rows_amount
            );

            // Повторная проверка
            goto monitoring_result_check;
        }

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

            yii::$app->response->format = Response::FORMAT_JSON;

            return [
                'main' => $this->renderPartial('monitoring', compact(
                    'sidebar',
                    'search_history',
                    'page_search_history',
                    'panel'
                )),
                'search' => $page_search_history + 1,
                'redirect' => '/profile/monitoring',
                '_csrf' => yii::$app->request->getCsrfToken()
            ];
        }

        return $this->render('monitoring', compact(
            'sidebar',
            'search_history',
            'page_search_history',
            'panel',
            'account'
        ));
    }

    /**
     * Страница поставок
     */
    public function actionSupplies(): string|array
    {
        // Инициализация
        $supply = new Supply(yii::$app->request->post('Supply') ?? yii::$app->request->get('Supply'));
        $panel = yii::$app->request->post('panel') ?? yii::$app->request->get('panel');
        $sidebar = $this->renderPartial('sidebar');

        // Обработка настроек аккаунта
        if ($vars = yii::$app->request->post('Warehouse') ?? yii::$app->request->get('Warehouse') and $warehouse = yii::$app->request->post('_key') ?? yii::$app->request->get('_key')) {
            // Обнаружены входные параметры

            if (isset($vars['trmn'])) {
                // Передан параметр

                if ($warehouse = Warehouse::searchById(Warehouse::collectionName() . "/$warehouse")) {
                    // Найден склад

                    // Запись в буфер
                    $warehouse->trmn = $vars['trmn'];

                    // Запись в базу данных
                    $warehouse->update();
                }
            } else {
                /**
                 * @todo Написать обработчик ошибок
                 */
            }
        }

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

            yii::$app->response->format = Response::FORMAT_JSON;

            return [
                'main' => $this->renderPartial('supplies', compact(
                    'supply',
                    'sidebar',
                    'panel'
                )),
                'redirect' => '/profile/supplies',
                '_csrf' => yii::$app->request->getCsrfToken()
            ];
        }

        return $this->render('supplies', compact(
            'supply',
            'sidebar',
            'panel'
        ));
    }

    /**
     * Импорт поставок
     *
     * На данный момент только из Excel-таблицы
     */
    public function actionImport()
    {
        // Инициализация
        $supply = new Supply(yii::$app->request->post('Supply') ?? yii::$app->request->get('Supply'));
        $supply->scenario = $supply::SCENARIO_IMPORT_EXCEL;
        $panel = yii::$app->request->post('panel') ?? yii::$app->request->get('panel');
        $help = (bool) (yii::$app->request->post('help') ?? yii::$app->request->get('help'));
        $target = yii::$app->request->post('account') ?? yii::$app->request->get('account');
        $number = yii::$app->request->post('number') ?? yii::$app->request->get('number');
        $warehouse = yii::$app->request->post('warehouse') ?? yii::$app->request->get('warehouse');
        $sidebar = $this->renderPartial('sidebar');

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

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

            if ($help) {
                // Запрошена отправка прайса модератору

                // Отправка письма модераторам
                $mail = Supply::sendMailForImport('ЗАГРУЗИТЬ ФАЙЛ НА СЕРВЕР НАДО');

                return [
                    '_csrf' => yii::$app->request->getCsrfToken(),
                    'alert' => $mail ? 'Письмо с запросом отправлено' : 'Не удалось отправить письмо, свяжитесь с модерацией напрямую через контактные данные в нижней части сайта'
                ];
            }

            // Инициализация файла
            $supply->file_excel = UploadedFile::getInstance($supply, 'file_excel');

            if (!empty($target)) {
                // Получен аккаунт для которого необходимо загрузить каталог

                if (empty($number)) {
                    // Не получен номер раздела в который надо загружать каталог

                    return [
                        '_csrf' => yii::$app->request->getCsrfToken(),
                        'alert' => 'Не получен номер раздела в который надо загружать каталог'
                    ];
                }

                if (Account::isMinimalAuthorized()) {
                    // Авторизован доступ к выполнению этого действия

                    if ($supply->importExcel((int) $warehouse, $target)) {
                        // Импорт успешно завершён

                        return [
                            'main' => $this->renderPartial('supplies', compact(
                                'supply',
                                'sidebar',
                                'panel'
                            )),
                            '_csrf' => yii::$app->request->getCsrfToken()
                        ];
                    }

                    yii::$app->response->statusCode = 409;
                } else {
                    // Не авторизован доступ к выполнению этого действия

                    return [
                        '_csrf' => yii::$app->request->getCsrfToken(),
                        'alert' => 'Вы не имеете разрешения на выполнение этого действия'
                    ];
                }
            } else {
                // Не получен аккаунт для которого необходимо загрузить каталог

                if ($supply->importExcel((int) $warehouse)) {

                    return [
                        'main' => $this->renderPartial('supplies', compact(
                            'supply',
                            'sidebar',
                            'panel'
                        )),
                        '_csrf' => yii::$app->request->getCsrfToken()
                    ];
                }

                yii::$app->response->statusCode = 409;
            }
        }

        return [
            'main' => $this->renderPartial('supplies', compact(
                'supply',
                'sidebar',
                'panel'
            )),
            '_csrf' => yii::$app->request->getCsrfToken()
        ];
    }

    /**
     * Инициализация данных о геолокации
     *
     * @param string|null $account
     *
     * @return array|bool JSON, в случае успеха
     */
    public function actionGeolocationInit(): array|bool
    {
        if (Yii::$app->request->isPost) {
            // POST-запрос

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

            // Инициализация аккаунта
            if (yii::$app->user->isGuest) {
                // Аккаунт не аутентифицирован

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

                // Инициализация
                $account = yii::$app->user->identity;
            }

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

            if (false !== $return = self::geolocationCheck($account)) {
                // Удалось сгенерировать данные для возврата

                return $return;
            }

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

        return false;
    }

    /**
     * Проверка наличия записи о геолокации
     *
     * @param Account|string|null $account
     *
     * @return array|bool JSON, в случае успеха
     *
     * @todo
     * 1. 👁_👁
     */
    public static function geolocationCheck(Account|int|null $account = null): array|bool
    {
        if (is_null($account)) {
            // Данные аккаунта не переданы

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

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

                // Инициализация
                $account = yii::$app->user->identity;
            }
        } else {
            if (is_int($account)) {
                // Передан идентификатор (_key) аккаунта (подразумевается)

                // Инициализация (поиск в базе данных)
                if (!$account = Account::searchById(Account::collectionName() . "/$account")) {
                    // Не удалось инициализировать аккаунт

                    return false;
                }
            }
        }

        if (isset($account->geol)) {
            // Данные о геолокации найдены

            // Генерация ответа
            return [
                'geolocation' => true,
                '_csrf' => yii::$app->request->getCsrfToken()
            ];
        }

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

    /**
     * Запись данных о геолокации по ширине и долготе
     *
     * @param string|null $account Аккаунт
     *
     * @return array|bool JSON, в случае успеха
     *
     * @todo
     * 1. Избавиться от второго запроса к DaData ($dadata->clean("address", $account->city);)
     */
    public function actionGeolocationWrite(): array|bool
    {
        if (Yii::$app->request->isPost) {
            // POST-запрос

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

            // Инициализация аккаунта
            if (yii::$app->user->isGuest) {
                // Аккаунт не аутентифицирован

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

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

                // Инициализация
                $account = yii::$app->user->identity;
            }

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

            // Инициализация данных яндекса
            $yandex = yii::$app->request->post('yandex') ?? yii::$app->request->get('yandex');

            // Инициализация широты (среднее значение из общего периметра)
            $latitude = ($yandex['coordinates'][0][0] + $yandex['coordinates'][1][0]) / 2;

            // Инициализация долготы (среднее значение из общего периметра)
            $longitude = ($yandex['coordinates'][0][1] + $yandex['coordinates'][1][1]) / 2;

            if (empty($latitude) || empty($longitude)) {
                // Широта или долгота не передана

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

                return false;
            }

            try {
                // Инициализация данных геолокации
                $dadata = new Dadata(yii::$app->params['dadata']['key'], yii::$app->params['dadata']['secret']);

                // Запись в буфер данных о геолокации
                $account->geol = $dadata->geolocate("address", $latitude, $longitude)[0];

                // Запись в буфер полученного города
                $account->city = $account->geol['data']['city'];

                // Запись в буфер новых данных (непонятно почему, но только вторым запросом можно получать часовую зону)
                $account->geol = [
                    'data' => [
                        'timezone' => $dadata->clean("address", $account->city)['data']['timezone']
                    ]
                ] + $account->geol;

                // Запись в буфер часовой зоны
                $account->zone = $account->geol['data']['timezone'];

                if ($account->update() < 1) {
                    // Не удалось записать данные

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

                    return false;
                };
            } catch (Throwable $t) {
                // Запись кода ответа
                yii::$app->response->statusCode = 500;

                return false;
            }

            return self::syncGeolocationWithDellin($account);
        }

        return false;
    }

    /**
     * Синхронизация данных о геолокации с данными терминалов ДеловыеЛинии
     *
     * Присваивает терминал Скиллпартс относительно города пользователя
     *
     * @param string|null $account Аккаунт
     *
     * @return bool Статус выполнения
     *
     * @todo Переделать запись страны как "Россия" в определение по геолокации через DaData
     */
    public static function syncGeolocationWithDellin(Account|int|null $account = null): bool
    {
        // Инициализщация аккаунта
        $account = Account::initAccount($account);

        // Синхронизация с базой данных (таблица с ДеловыеЛинии)
        if (isset($account->geol['data']) && $dellin = Dellin::searchByCityKladr(str_pad($account->geol['data']['city_kladr_id'], 25, '0000000000000000000000'))) {
            // Удалось найти город с терминалами ДеловыеЛинии

            foreach ($dellin['data']['terminals']['terminal'] as $dellin) {
                // Перебор терминалов ДеловыеЛинии

                try {
                    // Поиск терминала SkillParts
                    if ($skillparts_buffer = Terminal::searchByDellinTerminalId($dellin['id'], 1)) {
                        // Удалось найти терминал SkillParts

                        // Запись данных терминала SkillParts
                        $skillparts = $skillparts_buffer[0]->dell;
                    } else {
                        // Не удалось найти терминал SkillParts

                        if ($dellin['default'] && !$dellin['isOffice'] && $dellin['receiveCargo'] && $dellin['giveoutCargo']) {
                            // Терминал ДеловыеЛинии помечен как основной, не является офисом, принимает и отправляет посылки

                            // Инициализация данных геолокации
                            $dadata = new Dadata(yii::$app->params['dadata']['key'], yii::$app->params['dadata']['secret']);

                            // Запись в буфер данных о геолокации
                            $geolocation = $dadata->geolocate("address", $dellin['latitude'], $dellin['longitude'])[0];

                            // Инициализация терминала SkillParts
                            $terminal = new Terminal;

                            // Настройка
                            $terminal->cntr = $geolocation['data']['country'];
                            $terminal->city = $geolocation['data']['city'];
                            $terminal->comm = 'Недоступен';
                            $terminal->dell = $dellin['id'];

                            // Запись в базу данных
                            if ($terminal->save()) {
                                // Удалось записать терминал в базу данных

                                // Запись данных терминала SkillParts
                                $skillparts = $terminal->dell;
                            }
                        }
                    }
                } catch (Throwable $t) {
                    continue;
                }
            }

            if (empty($skillparts)) {
                // Не удалось инициализировать терминал SkillParts

                return false;
            } else {
                // Удалось инициализировать терминал SkillParts

                // Запись связанного с городом терминала в настройки пользователя
                // !!! Берётся первый попавшийся терминал
                $account->opts = [
                    'delivery_to_terminal' => $skillparts
                ] + ($account->opts ?? []);

                // Отправка данных из буфера в базу данных
                return $account->update() >= 1;
            }
        }

        return false;
    }

    /**
     * Поиск заявок на регистрацию
     */
    public function actionPanelSuppliersRequestsSearch(int $page = 1)
    {
        if (Yii::$app->request->isPost) {
            // POST-запрос

            if (Account::isAdmin() || Account::isModer()) {
                // Доступ разрешен

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

                // Инициализация буфера ответа
                $response = [];

                // Поиск заявок на регистрацию
                $suppliers =  Account::searchSuppliersRequests($amount, $page, $order);

                foreach ($suppliers as $account) {
                    // Перебор заявок

                    // Поиск данных о заявке
                    foreach ($account->jrnl as $jrnl) {
                        // Перебор журнала

                        if ($jrnl['action'] === 'create') {
                            // Запись о создании найдена

                            // Запись даты регистрации
                            $registration_date = $jrnl['date'];
                        }

                        if ($jrnl['action'] === 'request to become a supplier') {
                            // Запись о подаче заявку на становление поставщиком найдена

                            // Запись даты отправки заявки
                            $supplier_date = $jrnl['date'];

                            // Запись данных о заявке
                            $supplier_data = $jrnl['data'][0];
                        }
                    }

                    if (empty($supplier_data) || empty($supplier_date) || empty($registration_date)) {
                        // Данные из журнала не найдены

                        // Пропуск
                        continue;
                    }

                    // if (!isset($account->indx) || empty($account->indx)) {
                    if (empty($account->indx)) {
                        // Индекс не инициализирован

                        // Инициализация индекса
                        Account::generateIndexes([$account]);
                    }

                    // if (!isset($account->pswd) || empty($account->pswd)) {
                    if (empty($account->pswd)) {
                        // Пароль не инициализирован

                        // Инициализация пароля
                        $account->passwordInit();
                    }

                    // Запись в буфер ответа
                    $response[] = [
                        '_key' => $account->_key,
                        'name' => $account->name,
                        'mail' => $account->mail,
                        'boss' => $account->boss,
                        'desc' => $account->desc,
                        'simc' => $account->simc,
                        'simc' => $account->simc,
                        'comp' => $account->comp,
                        'cntc' => $account->cntc,
                        'taxn' => $account->taxn,
                        'cntg' => $account->cntg,
                        'fadd' => $account->fadd,
                        'ladd' => $account->ladd,
                        'chck' => $account->chck,
                        'indx' => $account->indx,
                        'vrfy' => Account::validateVrfy($account->vrfy),
                        'data' => $supplier_data,
                        'date' => [
                            'regs' => $registration_date,
                            'supl' => $supplier_date
                        ]
                    ];
                }

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

                return [
                    'suppliers' => $response,
                    '_csrf' => yii::$app->request->getCsrfToken()
                ];
            } else {
                // Запись кода ответа
                yii::$app->response->statusCode = 401;

                return;
            }
        }

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

        return;
    }

    public function actionCount(): array|string|null
    {
        if (yii::$app->request->isPost) {
            // POST-запрос

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

            return [
                'button' => $this->renderPartial('/cart/button', ['cart_amount' => Order::count(supplies: true)]),
                '_csrf' => yii::$app->request->getCsrfToken()
            ];
        }
    }

    /**
     * Удалить инстанцию поставки
     *
     * @return array|string|null
     */
    public function actionImportsDelete(): array|string|null
    {
        // Инициализация аккаунта
        $account = Account::initAccount();

        // Инициализация остальных входных параметров
        $supply = new Supply(yii::$app->request->post('Supply') ?? yii::$app->request->get('Supply'));
        $panel = yii::$app->request->post('panel') ?? yii::$app->request->get('panel');
        $sidebar = $this->renderPartial('sidebar');

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

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

            // Инициализация буфера вывода
            $return = [
                '_csrf' => yii::$app->request->getCsrfToken()
            ];

            // Инициализация идентификатора
            $_key = yii::$app->request->post('_key');

            if (empty($_key)) {
                // Не передан идентификатор

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

                return $return;
            }

            if ($import = Import::searchById(Import::collectionName() . "/$_key")) {
                // Найдена инстанция поставки

                if ($edge = WarehouseEdgeImport::searchByImport($import)[0]) {
                    // Найдено ребро: СКЛАД -> ИНСТАНЦИЯ ПОСТАВКИ

                    // Инициализация счётчика удалённых поставок
                    $deleted = 0;

                    foreach (Supply::searchByImport($import->readId(), limit: 9999) as $supply) {
                        // Перебор найденных поставок

                        if (empty($supply)) continue;

                        if (ImportEdgeSupply::searchBySupply($supply)?->delete()) {
                            // Удалено ребро: ИНСТАНЦИЯ ПОСТАВКИ -> ПОСТАВКА

                            // Удаление поставки
                            if ($supply->delete()) ++$deleted;
                        }
                    }

                    // Отправка уведомления
                    Notification::_write("Удалено $deleted поставок из инстанции поставки $_key", account: $account->readId());

                    if ($edge->delete()) {
                        // Удалено ребро: СКЛАД -> ИНСТАНЦИЯ ПОСТАВКИ

                        if ($import->delete()) {
                            // Удалена инстанция поставки

                            // Отправка уведомления
                            Notification::_write("Инстанция поставки $_key была удалена", account: $account->readId());
                        }
                    }
                }
            } else {
                // Не найдена инстанция поставки

                // Отправка уведомления
                Notification::_write("Не найдена инстанция поставки $_key", account: $account->readId());
            }

            // Запись в буфер вывода реинициализированного элемента
            $return['main'] = $this->renderPartial('supplies', compact(
                'supply',
                'sidebar',
                'panel'
            ));

            return $return;
        }
    }

    /**
     * Записать (создать) склад
     *
     * @return array|string|null
     */
    public function actionWarehousesWrite(): array|string|null
    {
        // Инициализация аккаунта
        $account = Account::initAccount();

        // Инициализация остальных входных параметров
        $supply = new Supply(yii::$app->request->post('Supply') ?? yii::$app->request->get('Supply'));
        $panel = yii::$app->request->post('panel') ?? yii::$app->request->get('panel');
        $sidebar = $this->renderPartial('sidebar');

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

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

            // Инициализация буфера вывода
            $return = [
                '_csrf' => yii::$app->request->getCsrfToken()
            ];

            // Запись склада
            if (Warehouse::writeByAccount($account)) Notification::_write("Создан новый склад", account: $account->_key);
            else Notification::_write("Не удалось создать новый склад", account: $account->_key);

            // Запись в буфер вывода реинициализированного элемента
            $return['main'] = $this->renderPartial('supplies', compact(
                'supply',
                'sidebar',
                'panel'
            ));

            return $return;
        }
    }


    /**
     * Переименовать склад
     *
     * @return array|string|null
     */
    public function actionWarehousesRename(): array|string|null
    {
        // Инициализация аккаунта
        $account = Account::initAccount();

        // Инициализация остальных входных параметров
        $supply = new Supply(yii::$app->request->post('Supply') ?? yii::$app->request->get('Supply'));
        $panel = yii::$app->request->post('panel') ?? yii::$app->request->get('panel');
        $sidebar = $this->renderPartial('sidebar');

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

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

            // Инициализация буфера вывода
            $return = [
                '_csrf' => yii::$app->request->getCsrfToken()
            ];

            // Инициализация идентификатора
            $_key = yii::$app->request->post('_key');

            // Инициализация названия\
            $name = yii::$app->request->post('name');

            if (empty($_key) || empty($name)) {
                // Не передан идентификатор или название

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

                return $return;
            }

            if ($warehouse = Warehouse::searchById(Warehouse::collectionName() . "/$_key")) {
                // Найден склад

                // Запись старого названия
                $old = $warehouse->name;

                // Запись параметров
                $warehouse->name = $name;

                if ($warehouse->update() >= 1) {
                    // Обновлён склад

                    // Отправка уведомления
                    Notification::_write("Склад $_key переименован: \"$old\" > \"$name\"", account: $account->_key);
                } else {
                    // Не обновлён склад

                    // Отправка уведомления
                    Notification::_write("Не удалось переименовать склад $_key", account: $account->_key);
                }
            } else {
                // Не найден склад

                // Отправка уведомления
                Notification::_write("Не найден склад $_key", account: $account->_key);
            }

            // Запись в буфер вывода реинициализированного элемента
            $return['main'] = $this->renderPartial('supplies', compact(
                'supply',
                'sidebar',
                'panel'
            ));

            return $return;
        }
    }

    /**
     * Удалить склад
     *
     * @return array|string|null
     *
     * @todo
     * 1. Удаление всех ImportEdgeSupply с устаревшими версиями
     */
    public function actionWarehousesDelete(): array|string|null
    {
        // Инициализация аккаунта
        $account = Account::initAccount();

        // Инициализация остальных входных параметров
        $supply = new Supply(yii::$app->request->post('Supply') ?? yii::$app->request->get('Supply'));
        $panel = yii::$app->request->post('panel') ?? yii::$app->request->get('panel');
        $sidebar = $this->renderPartial('sidebar');

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

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

            // Инициализация буфера вывода
            $return = [
                '_csrf' => yii::$app->request->getCsrfToken()
            ];

            // Инициализация идентификатора
            $_key = yii::$app->request->post('_key');

            if (empty($_key)) {
                // Не передан идентификатор

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

                return $return;
            }

            if ($warehouse = Warehouse::searchById(Warehouse::collectionName() . "/$_key")) {
                // Найден склад

                foreach (Import::searchByWarehouse($warehouse, limit: 100) as $import) {
                    // Найдены инстанции поставки

                    if ($edge = WarehouseEdgeImport::searchByImport($import)[0]) {
                        // Найдено ребро: СКЛАД -> ИНСТАНЦИЯ ПОСТАВКИ

                        // Инициализация счётчика удалённых поставок
                        $deleted = 0;

                        foreach (Supply::searchByImport($import->readId(), limit: 9999) as $supply) {
                            // Перебор найденных поставок

                            if ($edge = ImportEdgeSupply::searchBySupply($supply)) {
                                // Найдено ребро: ИНСТАНЦИЯ ПОСТАВКИ -> ПОСТАВКА

                                // Инициализация версии
                                $version = $edge->vrsn;

                                if ($edge->delete() === 1) {
                                    // Удалено ребро: ИНСТАНЦИЯ ПОСТАВКИ -> ПОСТАВКА

                                    if (ImportEdgeSupply::searchMaxVersion($supply) <= $version) {
                                        // Не найдена более новая версия поставки (обрабатываемая считается актуальной)

                                        // Удаление поставки
                                        if ($supply->delete() === 1) ++$deleted;
                                    }
                                }
                            }
                        }

                        // Отправка уведомления
                        Notification::_write("Удалено $deleted поставок из инстанции поставки $_key", account: $account->_key);

                        if ($edge->delete()) {
                            // Удалено ребро: СКЛАД -> ИНСТАНЦИЯ ПОСТАВКИ

                            if ($import->delete()) {
                                // Удалена инстанция поставки

                                // Отправка уведомления
                                Notification::_write("Инстанция поставки $_key была удалена", account: $account->_key);
                            }
                        }
                    }
                }


                if ($warehouse->delete()) {
                    // Удалён склад

                    // Отправка уведомления
                    Notification::_write("Склад $_key был удалён", account: $account->_key);
                }
            } else {
                // Не найден склад

                // Отправка уведомления
                Notification::_write("Не найден склад $_key", account: $account->_key);
            }

            // Запись в буфер вывода реинициализированного элемента
            $return['main'] = $this->renderPartial('supplies', compact(
                'supply',
                'sidebar',
                'panel'
            ));

            return $return;
        }
    }

    /**
     * Открыть склад
     *
     * @return array|string|null
     */
    public function actionWarehousesOpen(): array|string|null
    {
        // Инициализация аккаунта
        $account = Account::initAccount();

        // Инициализация остальных входных параметров
        $supply = new Supply(yii::$app->request->post('Supply') ?? yii::$app->request->get('Supply'));
        $panel = yii::$app->request->post('panel') ?? yii::$app->request->get('panel');
        $sidebar = $this->renderPartial('sidebar');

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

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

            // Инициализация буфера вывода
            $return = [
                '_csrf' => yii::$app->request->getCsrfToken()
            ];

            // Инициализация идентификатора
            $_key = yii::$app->request->post('_key');

            if (empty($_key)) {
                // Не передан идентификатор

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

                return $return;
            }

            if ($warehouse = Warehouse::searchById(Warehouse::collectionName() . "/$_key")) {
                // Найден склад

                // Запись статуса
                $warehouse->open = true;

                if ($warehouse->update() > 0) {
                    // Открыт склад

                    // Отправка уведомления
                    Notification::_write("Склад $_key был открыт", account: $account->_key);


                    // Запись в буфер вывода реинициализированного элемента
                    $return['opened'] = true;
                }
            } else {
                // Не найден склад

                // Отправка уведомления
                Notification::_write("Не найден склад $_key", account: $account->_key);
            }

            // Запись в буфер вывода реинициализированного элемента
            $return['main'] = $this->renderPartial('supplies', compact(
                'supply',
                'sidebar',
                'panel'
            ));

            return $return;
        }
    }

    /**
     * Закрыть склад
     *
     * @return array|string|null
     */
    public function actionWarehousesClose(): array|string|null
    {
        // Инициализация аккаунта
        $account = Account::initAccount();

        // Инициализация остальных входных параметров
        $supply = new Supply(yii::$app->request->post('Supply') ?? yii::$app->request->get('Supply'));
        $panel = yii::$app->request->post('panel') ?? yii::$app->request->get('panel');
        $sidebar = $this->renderPartial('sidebar');

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

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

            // Инициализация буфера вывода
            $return = [
                '_csrf' => yii::$app->request->getCsrfToken()
            ];

            // Инициализация идентификатора
            $_key = yii::$app->request->post('_key');

            if (empty($_key)) {
                // Не передан идентификатор

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

                return $return;
            }

            if ($warehouse = Warehouse::searchById(Warehouse::collectionName() . "/$_key")) {
                // Найден склад

                // Запись статуса
                $warehouse->open = false;

                if ($warehouse->update() > 0) {
                    // Закрыт склад

                    // Отправка уведомления
                    Notification::_write("Склад $_key был закрыт", account: $account->_key);


                    // Запись в буфер вывода реинициализированного элемента
                    $return['closed'] = true;
                }
            } else {
                // Не найден склад

                // Отправка уведомления
                Notification::_write("Не найден склад $_key", account: $account->_key);
            }

            // Запись в буфер вывода реинициализированного элемента
            $return['main'] = $this->renderPartial('supplies', compact(
                'supply',
                'sidebar',
                'panel'
            ));

            return $return;
        }
    }
}
