<?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 app\models\Order;
use app\models\Account;
use app\models\Product;
use app\models\OrderEdgeSupply;
use app\models\AccountEdgeOrder;
use app\models\connection\Dellin;
use app\models\Invoice;
use app\models\Notification;
use app\models\Search;
use app\models\Settings;
use app\models\Supply;
use app\models\SupplyEdgeProduct;

use Codeception\PHPUnit\ResultPrinter\HTML;

use DateTime;
use Exception;
use Throwable;

class OrderController extends Controller
{
    public function behaviors()
    {
        return [
            'access' => [
                'class' => AccessControl::class,
                'rules' => [
                    [
                        'allow' => true,
                        'roles' => ['@'],
                        'actions' => [
                            'index',
                            'accept',
                            'write',
                            'delete',
                            'amount-update',
                            'amount-update',
                            'request',
                            'edit-stts',
                            'supply-read',
                            'supply-edit-stts',
                            'supply-edit-time',
                            'supply-edit-cost',
                            'supply-edit-comm'
                        ]
                    ],
                    [
                        'allow' => true,
                        'actions' => [
                            'list'
                        ],
                        '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()
    {
        // Инициализация cookie
        $cookies = yii::$app->response->cookies;

        if (isset(yii::$app->request->referrer)) {
            // Найден HTTP-заголовок REFERRER

            // Инициализация адреса переадресации из HTTP-заголовка referrer
            $redirect = $referrer = trim(parse_url(yii::$app->request->referrer, PHP_URL_PATH) . '?' . parse_url(yii::$app->request->referrer, PHP_URL_QUERY), '/');
        } else {
            // Не найден HTTP-заголовок REFERRER

            // Инициализация адреса переадресации из текущего URI
            $redirect = yii::$app->request->pathInfo;
        }

        // Реинициализация с фильтрацией
        $redirect = match (yii::$app->request->pathInfo) {
            'order/write' => $redirect,
            'order/delete', 'order/amount-update', 'order/request' => 'cart',
            'order/accept', 'order/supply-read', 'order/supply-write-stts', 'order/supply-edit-time', 'order/supply-edit-cost', 'order/supply-edit-comm' => 'orders',
            default => yii::$app->request->pathInfo
        };

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

        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' => '/orders',
                '_csrf' => yii::$app->request->getCsrfToken()
            ]);
        } else if (yii::$app->request->isGet) {
            // GET-запрос

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

    public function actionIndex(string $stts = '@all')
    {
        // Инициализация cookie
        $cookies = yii::$app->response->cookies;

        // Инициализация открытой панели ("Модерация", "Мои заказы")
        $window = yii::$app->request->post('window') ?? yii::$app->request->get('window') ?? 'orders_panel_orders';

        // Инициализация аккаунта
        $account = Account::initAccount();

        // Инициализация данных поиска
        try {
            if ($search = yii::$app->request->post('search') ?? yii::$app->request->get('search') === '@last') {
                // Запрошено использование прошлых данных

                // Чтение сохраненных данных в cookie
                $search = $cookies->get('search');

                if (empty($search)) {
                    // Переданы неверные данные

                    throw new Exception("Переданы неверные данные \$search: $search", 500);
                }
            } else {
                // Запрошен поиск

                if (empty($search)) {
                    // Переданы неверные данные

                    throw new Exception("Переданы неверные данные \$search: $search", 500);
                }

                // Запись данных в cookie
                $cookies->add(new Cookie([
                    'name' => 'search',
                    'value' => $search
                ]));
            }
        } catch (Exception $e) {
            // Деинициализация (не удалять, отправляется в представление через compact)
            $search = null;
        } finally {
            if (isset($search)) {
                // Запись в историю
                Search::write($search, 'order');
            }
        }

        // Инициализация открытого окна
        try {
            if ($stts === '@last') {
                // Запрошено использование прошлых данных

                // Чтение сохраненных данных в cookie
                $stts = $cookies->get('stts');

                if (empty($stts)) {
                    // Переданы неверные данные

                    throw new Exception("Переданы неверные данные \$stts: $stts", 500);
                }
            } else {
                // Запрошено использование новых данных

                if (empty($stts)) {
                    // Переданы неверные данные

                    throw new Exception("Переданы неверные данные \$stts: $stts", 500);
                }

                // Запись данных в cookie
                $cookies->add(new Cookie([
                    'name' => 'stts',
                    'value' => $stts
                ]));
            }
        } catch (Exception $e) {
            // Реинициализация
            $stts = '@all';
        }

        // Инициализация данных периода (от)
        try {
            if ('@last' === $from = yii::$app->request->post('from') ?? yii::$app->request->get('from')) {
                // Запрошено использование прошлых данных

                // Чтение сохраненных данных в cookie
                $from = $cookies->get('from');

                if (empty($from) || !filter_var($from, FILTER_VALIDATE_INT)) {
                    // Переданы неверные данные (необходим unixtime)

                    throw new Exception("Переданы неверные данные \$from: $from", 500);
                }
            } else {
                // Запрошен поиск

                if (empty($from) || !filter_var($from, FILTER_VALIDATE_INT)) {
                    // Переданы неверные данные (необходим unixtime)

                    throw new Exception("Переданы неверные данные \$from: $from", 500);
                }

                // Запись данных в cookie
                $cookies->add(new Cookie([
                    'name' => 'from',
                    'value' => $from
                ]));
            }
        } catch (Exception $e) {
            // Реинициализация
            $from = time() - 604800;
        } finally {
            // Конвертация типа
            $from = (int) $from;
        }

        // Инициализация данных периода (до)
        try {
            if ('@last' === $to = yii::$app->request->post('to') ?? yii::$app->request->get('to')) {
                // Запрошено использование прошлых данных

                // Чтение данных в cookie
                $to = $cookies->get('to');

                if (empty($to) || !filter_var($to, FILTER_VALIDATE_INT)) {
                    // Переданы неверные данные (необходим unixtime)

                    throw new Exception("Переданы неверные данные \$to: $to", 500);
                }
            } else {
                // Запрошен поиск

                if (empty($to) || !filter_var($to, FILTER_VALIDATE_INT)) {
                    // Переданы неверные данные (необходим unixtime)

                    throw new Exception("Переданы неверные данные \$to: $to", 500);
                }

                // Запись данных в cookie
                $cookies->add(new Cookie([
                    'name' => 'to',
                    'value' => $to
                ]));
            }
        } catch (Exception $e) {
            // Реинициализация
            $to = time();
        } finally {
            // Конвертация типа
            $to = (int) $to;
        }

        if ($window === 'orders_panel_orders') {
            // Обработка панели заказов пользователя

            // Инициализация заказов
            $data = Order::searchSmart(
                stts: $stts,
                limit: 10,
                page: 1,
                supplies: true,
                from: $from,
                to: $to,
                search: $search
            );
        } else if ($window === 'orders_panel_moderation') {
            // Обработка панели модерации заказов

            // Инициализация заказов
            $data = Order::searchSmart(
                stts: $stts,
                limit: 10,
                page: 1,
                supplies: true,
                from: $from,
                to: $to,
                search: $search
            );

        } else {
            // Запрошено неизвестное окно
        }

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

            // Конвертация из UNIXTIME в формат поддерживаемый календарём по спецификации HTML
            $from = DateTime::createFromFormat('U', (string) $from)->format('Y-m-d');
            $to = DateTime::createFromFormat('U', (string) $to)->format('Y-m-d');

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

            return [
                'main' => $this->renderPartial('/orders/index', compact('data', 'account', 'search', 'from', 'to', 'window')
                    + ['panel' => $this->renderPartial('/orders/search/panel', compact('account') + ['data' => $data] ?? null)]),
                'title' => 'Заказы',
                'redirect' => '/orders',
                '_csrf' => yii::$app->request->getCsrfToken()
            ];
        }

        return $this->render('/orders/index', compact('data', 'account'));
    }

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

            // Инициализация входных данных
            $account = yii::$app->user->identity;
            $supply_id = yii::$app->request->post('supply_id');
            $amount = yii::$app->request->post('amount') ?? 1;
            $delivery = yii::$app->request->post('delivery');

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

            if (empty($supply_id) || empty($delivery)) {
                // Не выполнены условия для выполнения

                // 501 Not Implemented
                yii::$app->response->statusCode = 501;
            }

            // Инициализация возврата по умолчанию
            $return = [
                '_csrf' => yii::$app->request->getCsrfToken()
            ];

            // Инициализация корзины
            if (!$data = Order::searchSmart($account)[0] ?? null) {
                // Корзина не найдена (текущий заказ)

                // Инициализация
                $data['order'] = new Order();
                $data['order']->save() or throw new Exception('Не удалось инициализировать заказ');

                // Запись ребра: АККАУНТ -> ЗАКАЗ
                AccountEdgeOrder::write($account->readId(), $data['order']->readId(), data: ['stts' => 'current']) or $data['order']->addError('errors', 'Не удалось инициализировать ребро: АККАУНТ -> ЗАКАЗ');
            }

            // Если запись не удалась, то вернуть код: 500 Internal Server Error
            $data['order']->writeSupply($supply_id, $delivery, (int) $amount) or yii::$app->response->statusCode = 500;

            return $return;
        }

        yii::$app->response->statusCode = 500;

        return null;
    }

    /**
     * Удаление
     *
     * @todo Разделить логику (для удобства чтения)
     */
    public function actionDelete(): string|array|null
    {
        // Инициализация входных параметров (необязательных)
        $targets = yii::$app->request->post('targets') ?? yii::$app->request->get('targets');
        $page = yii::$app->request->get('page') ?? yii::$app->request->post('page') ?? 1;

        // Инициализация аккаунта
        $account = Account::initAccount();

        // Инициализация заказа
        $order = Order::searchSmart($account)[0]['order'] ?? null;

        if (isset($order)) {
            // Получены необходимые параметры

            if ($targets) {
                // Удаление выбранных целей (удаление из заказа)

                foreach (isset($targets[0]) && is_array($targets[0]) ? $targets : [$targets] as $target) {
                    // Унификация входных параметров

                    foreach ($target as $catn => $amount) {
                        // Перебор целей

                        // Удаление
                        $order->deleteSupply([$catn => (int) $amount]);
                    }
                }
            } else {
                // Целью подразумевается сам заказ (удаление заказа)

                // Инициализация
                $order->stts = 'reserved';

                if ($order->update() > 0) {
                    // Сохранены изменения

                    // Запись в журнал
                    $order->journal('reserved');

                    // Поиск
                    $edge = AccountEdgeOrder::searchByVertex($account->readId(), $order->readId(), filter: ['stts' => 'current']);

                    if (count($edge) > 1) {
                        // Найден более чем 1 заказ

                        return null;
                    }

                    // Инициализация
                    $edge = $edge[0];
                    $edge->stts = 'reserved';

                    // Запись
                    $edge->update();

                    // Реинициализация
                    $order = Order::searchSmart($account);

                    if (empty($order)) {
                        // Корзина не инициализирована

                        // Инициализация
                        $order = new Order();
                        $order->save() or throw new Exception('Не удалось инициализировать заказ');

                        // Подключение
                        $order->connect($account);
                    }
                }
            }
        }

        // Инициализация содержимого корзины
        $connections = $order->supplies(10, $page);

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

            // Инициализация формата ответа
            yii::$app->response->format = Response::FORMAT_JSON;

            return [
                'main' => $this->renderPartial('/cart/index', compact('order', 'connections', 'account')),
                'title' => 'Корзина',
                'redirect' => '/cart',
                '_csrf' => yii::$app->request->getCsrfToken()
            ];
        }

        return $this->render('/cart/index', compact('order', 'connections', 'account'));
    }

    /**
     * Обновление количества товара
     */
    public function actionAmountUpdate(): string|array|null
    {
        // Инициализация
        $targets = yii::$app->request->post('targets') ?? yii::$app->request->get('targets');
        $page = yii::$app->request->get('page') ?? yii::$app->request->post('page') ?? 1;
        $account = yii::$app->user->identity;
        $order = Order::searchSmart();
        $connections = $order->content(10, $page);

        foreach (isset($targets[0]) && is_array($targets[0]) ? $targets : [$targets] as $target) {
            // Унификация входных параметров

            foreach ($target as $catn => $data) {
                // Перебор целей (переданных объектов в корзине)

                foreach ($data as $type => $amount) {
                    // Перебор данных цели

                    foreach ($connections as $connection) {
                        // Перебор объектов в корзине

                        if ($connection['supply']['catn'] === $catn) {
                            // Цель найдена (продукт)

                            foreach ($connection['order_edge_supply'] as $order_edge_supply) {
                                // Перебор связанных поставок

                                if ($order_edge_supply["dlvr"]["type"] === $type) {
                                    // Цель найдена (поставка)

                                    if ($connection['amount'][$type] > $amount) {
                                        // Запрошено уменьшение количества

                                        // Удаление
                                        $order->deleteSupply([
                                            $catn => [
                                                $type => $connection['amount'][$type] - $amount
                                            ]
                                        ]);
                                    } else if ($connection['amount'][$type] < $amount) {
                                        // Запрошено увеличение количества

                                        // Запись
                                        $order->writeSupply('supply/' . $connection['supply']['_key'], $type, $amount - $connection['amount'][$type]);
                                    }

                                    break;
                                }
                            }
                        }
                    }
                }
            }
        }

        // Ренициализация
        $connections = $order->content(10, $page);

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

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

            return [
                'main' => $this->renderPartial('/cart/index', compact('order', 'connections', 'account')),
                'title' => 'Корзина',
                'redirect' => '/cart',
                '_csrf' => yii::$app->request->getCsrfToken()
            ];
        }

        return $this->render('/cart/index', compact('order', 'connections', 'account'));
    }

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

        if (isset($account)) {
            // Найден аккаунт

            if ($account->filled() === true) {
                // Заполнены все необходимые поля для оформления заказа (подразумевается прохождение второго этапа регистрации)

                // Инициализация данных о заказе и поставках
                $data = Order::searchSmart(supplies: true)[0];

                if (($account_edge_order = AccountEdgeOrder::searchByVertex(yii::$app->user->id, $data['order']->readId(), filter: ['stts' => 'current'])[0]) ?? false) {
                    // Найдено ребро: АККАУНТ -> ЗАКАЗ

                    // Инициализация статуса необходимости реинициализации
                    $reinitialization = false;

                    if ($order_edge_supply = OrderEdgeSupply::searchByDirection($account_edge_order->_to, type: 'write', limit: 500)) {
                        // Найдены рёбра: ЗАКАЗ -> ПОСТАВКА

                        foreach ($order_edge_supply as $edge) {
                            // Перебор рёбер: ЗАКАЗ -> ПОСТАВКА

                            if ($product = (Product::searchByCatnAndProd(($product = Product::searchBySupplyId($edge->_to))['catn'], $product['prod']))) {
                                // Найден товар

                                if ($sender = Account::searchById($account_edge_order->_from)) {
                                    // Найден отправитель
                                    try {
                                        // Инициализация данных геолокации

                                        // Инициализация буфера
                                        $buffer = [];

                                        try {
                                            $from = (int) $sender->opts['delivery_from_terminal'] ?? empty(Settings::searchActive()->delivery_from_default) ? 36 : (int) Settings::searchActive()->delivery_from_default;
                                        } catch (Exception $e) {
                                            $from = empty(Settings::searchActive()->delivery_from_default) ? 36 : (int) Settings::searchActive()->delivery_from_default;
                                        }

                                        try {
                                            $to = (int) $account->opts['delivery_to_terminal'] ?? 36;
                                        } catch (Exception $e) {
                                            $to = 36;
                                        }

                                        if (($buffer_connection = $buffer['product']['bffr']["$from-$to-" . $edge['dlvr']['type']] ?? false) && time() < $buffer_connection['expires']) {
                                            // Найдены данные доставки в буфере и их срок хранения не превышен, информация актуальна

                                            // Запись в буфер вывода
                                            $buffer['delivery'] = $buffer_connection['data'];
                                        } else {
                                            // Инициализация доставки Dellin (автоматическая)
                                            $product->bffr = ($product->bffr ?? []) + [
                                                "$from-$to-" . $edge['dlvr']['type'] => [
                                                    'data' => $buffer['delivery'] = Dellin::calcDeliveryAdvanced(
                                                        $from,
                                                        $to,
                                                        (int) ($buffer['product']['wght'] ?? 0),
                                                        (int) ($buffer['product']['dmns']['x'] ?? 0),
                                                        (int) ($buffer['product']['dmns']['y'] ?? 0),
                                                        (int) ($buffer['product']['dmns']['z'] ?? 0),
                                                        avia: $edge['dlvr']['type'] === 'avia'
                                                    ),
                                                    'expires' => time() + 86400
                                                ]
                                            ];

                                            // Отправка в базу данных
                                            $product->update();
                                        }

                                        // Запись даты доставки
                                        $edge->dlvr = $edge->dlvr + ['data' => $buffer['delivery']];

                                        // Запись в базу данных
                                        $edge->update();
                                    } catch (Exception $e) {
                                        // Удаление из заказа
                                        $edge->delete();

                                        // Продолжение цикла
                                        continue;
                                    }
                                }

                                if ($product['stts'] !== 'active') {
                                    // Не активен товар

                                    // Удаление из заказа
                                    $edge->delete();

                                    // Статус необходимости реинициализации
                                    $reinitialization = true;
                                }

                                // Удаление ребра: ПОСТАВКА -> ТОВАР (уменьшение количества товаров доступных для покупки)
                                SupplyEdgeProduct::searchByVertex($edge->_to, $product->readId(), 'connect')[0]->delete();
                            }
                        }
                    }

                    // Реинициализация
                    if ($reinitialization) $data = Order::searchSmart(supplies: true);

                    // Запись
                    $account_edge_order->stts = 'requested';

                    if ($account_edge_order->update() > 0) {
                        // Удалось сохранить изменения

                        // Запись в журнал
                        $data['order']->journal('requested');

                        Invoice::generate($data['order']->_key, $this->renderPartial('/invoice/order/pattern', [
                            'buyer' => [
                                'id' => yii::$app->user->identity->_key,
                                'info' => 'Неизвестно'
                            ],
                            'data' => $data,
                            'date' => $account_edge_order->date ?? time()
                        ]));

                        // Отправка уведомлений модераторам
                        Notification::_write($this->renderPartial('/notification/system/orders/new', ['id' => $account_edge_order->_key]), true, '@auth', Notification::TYPE_MODERATOR_ORDER_NEW);

                        // Отправка уведомления покупателю
                        Notification::_write($this->renderPartial('/notification/system/orders/new', ['id' => $account_edge_order->_key]), true, $account->_key, Notification::TYPE_NOTICE);
                    }
                }

                return $this->actionIndex();
            } else {
                // Не заполнены все необходимые поля для оформления заказа (подразумевается прохождение второго этапа регистрации)

                // var_dump($account->getErrors());

                foreach ($account->getErrors() as $parameter => $errors) {
                    // Перебор параметров с ошибками

                    foreach ($errors as $error) {
                        // Перебор ошибок

                        // Инициализация ярлыка
                        $label = $account->getAttributeLabel($parameter) ?? $parameter;

                        // Отправка уведомления покупателю
                        Notification::_write($error . " ($label)", account: $account->_key, type: Notification::TYPE_ERROR);
                    }
                }

                return null;
            }
        }
    }

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

        if (isset($account)) {
            // Найден аккаунт

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

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

            if (empty($order)) {
                // Не получен обязательные параметры

                yii::$app->response->statusCode = 500;

                goto end;
            }

            if ($account_edge_order = AccountEdgeOrder::searchByOrder(Order::collectionName() . '/' . $order)[0]) {
                // Удалось найти ребро до заказа

                // Запись в буфер изначальных данных
                $old = $account_edge_order->stts;

                // Запись в буфер записи в базу данных
                $account_edge_order->stts = $stts;

                // Отправка в базу данных
                if ($account_edge_order->update() > 0) {
                    // Удалось сохранить изменения

                    // Инициализация аккаунта покупателя
                    $buyer = Account::searchById($account_edge_order->_from);

                    // Отправка уведомления
                    Notification::_write($this->renderPartial('/notification/system/orders/edit', ['order' => $order, 'from' => Order::statusToRussian($old), 'to' =>  Order::statusToRussian($stts), 'target' => 'Статус']), true, $buyer->_key, Notification::TYPE_NOTICE);

                    // Запись в буфер вывода
                    $buffer['stts'] = $account_edge_order->stts;
                } else {
                    // Не удалось сохранить изменения

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

            end:

            // Запись обязательных параметров
            $buffer['_csrf'] = yii::$app->request->getCsrfToken();

            // Инициализация данных заказов
            $data = Order::searchSmart(stts: '@last', limit: 10, page: 1, supplies: true);

            // Инициализация панели модератора заказов
            if (!yii::$app->user->isGuest && Account::isMinimalAuthorized($account)) $moderator_data = Order::searchSmart(account: '@all', stts: '@last', limit: 10, page: 1, supplies: true);
            else $moderator_data = null;

            // Запись в буфер вывода
            $buffer['main'] = $this->renderPartial('/orders/index', compact('data', 'moderator_data'));

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

            return $buffer;
        }
    }

    /**
     * Список заказов для модерации
     *
     * @param string $catn Артикул
     */
    public function actionList(int $page): array|string|null
    {
        if (!yii::$app->user->isGuest && Account::isMinimalAuthorized()) {
            // Авторизован пользователь

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

            // Инициализация количества
            $amount = yii::$app->request->post('amount') ?? yii::$app->request->get('amount') ?? 8;

            if ($moderator_data = Order::searchSmart(
                account: '@all',
                stts: '@all',
                limit: (int) $amount,
                page: $page,
                supplies: true
            )) {
                // Найдены заказы

                // Генерация списка
                $list = trim($this->renderPartial('/orders/moderation', compact('moderator_data')));

                if (!empty($list)) $return['list'] = $list;
            } else {
                // Не найдены заказы

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

                // Запись в буфер возврата
                // $return['alert'] = "Не удалось найти заказы для генерации списка";
            }

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

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

                return $return;
            }
        }

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

    /**
     * Чтение инстанции поставки в заказе (order_edge_supply)
     *
     * @param string $catn Артикул поставки
     *
     * @return string|array|null
     */
    public function actionSupplyRead(string $order, string $prod, string $catn, string $delivery): string|array|null
    {
        // Инициализация буфера вывода
        $buffer = [];

        if (empty($order) || empty($prod) || empty($catn) || empty($delivery)) {
            // Не получены обязательные параметры

            yii::$app->response->statusCode = 500;

            goto end;
        }

        if ($order_edge_supply = OrderEdgeSupply::searchBySupplyData($catn, $prod, $delivery, Order::searchById(Order::collectionName() . "/$order"))) {
            // Удалось найти рёбра: ЗАКАЗ -> ПОСТАВКА

            // Инициализация ребра: ПОСТАВКА -> ТОВАР
            $supply_edge_product = SupplyEdgeProduct::searchBySupplyId($order_edge_supply[0]->_to)[0] ?? null;

            // Поиск ребра до аккаунта
            $account = Account::searchBySupplyId($order_edge_supply[0]->_to);

            // Поиск привязанного товара
            $product = Product::searchBySupplyId($order_edge_supply[0]->_to);

            // Поиск привязанного товара
            $supply = Supply::searchById($order_edge_supply[0]->_to);

            // Инициализация доставки
            if (empty($time = $order_edge_supply[0]->time)) {
                // Не найден срок доставки (в днях)

                if (empty($order_edge_supply[0]->dlvr['data'])) {
                    // Не удалось рассчитать доставку

                    // Инициализация времени
                    $time = 0;
                } else {
                    // Удалось рассчитать доставку

                    // Инициализация даты отправки
                    try {
                        // Взять данные из "arrivalToOspSender" (Дата прибытия на терминал-отправитель)

                        $delivery_send_date = DateTime::createFromFormat('Y-m-d', $order_edge_supply[0]->dlvr['data']['orderDates']['arrivalToOspSender'])->getTimestamp();
                    } catch (Throwable $e) {
                        // Взять данные из "pickup" (Дата передачи груза на адресе отправителя)

                        $delivery_send_date = DateTime::createFromFormat('Y-m-d', $order_edge_supply[0]->dlvr['data']['orderDates']['pickup'])->getTimestamp();
                    }

                    // Инициализация времени доставки
                    try {
                        // Доставка по воздуху (подразумевается), данные из "giveoutFromOspReceiver" (Дата и время, с которого груз готов к выдаче на терминале)

                        // Оставлено на всякий случай для дальнейших разбирательств

                        $delivery_converted = DateTime::createFromFormat('Y-m-d H:i:s', $order_edge_supply[0]->dlvr['data']['orderDates']['giveoutFromOspReceiver'])->getTimestamp();
                    } catch (Throwable $e) {
                        // Инициализация даты отправки

                        // Автоматическая доставка (подразумевается), данные из "arrivalToOspReceiver" (Дата прибытия натерминал-получатель)
                        $delivery_converted = DateTime::createFromFormat('Y-m-d', $order_edge_supply[0]->dlvr['data']['orderDates']['arrivalToOspReceiver'])->getTimestamp();
                    }
                    $time = ceil(($delivery_converted - ($delivery_send_date ?? 0)) / 60 / 60 / 24);
                }
            }

            // Запись параметров
            $buffer['cost'] = $order_edge_supply[0]->cost ?? $supply->cost ?? 0;
            $buffer['time'] = $time ?? 0;
            $buffer['amnt'] = count($order_edge_supply) ?? 0;
            $buffer['comm'] = $order_edge_supply[0]->comm ?? '';
            $buffer['stts'] = $order_edge_supply[0]->stts ?? 'processing';
            $buffer['id'] = $order_edge_supply[0]->_key ?? 'Неизвестно';
        }

        end:

        // Запись обязательных параметров
        $buffer['_csrf'] = yii::$app->request->getCsrfToken();

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

        return $buffer;
    }

    /**
     * Редактирование цены поставки в заказе (order_edge_supply)
     *
     * @param string $order Заказ в котором находится поставка
     * @param string $prod Производитель
     * @param string $catn Артикул
     * @param string $delivery Тип доставки
     *
     * @return string|array|null
     */
    public function actionSupplyEditCost(string $order, string $prod, string $catn, string $delivery): string|array|null
    {
        // Инициализация входных параметров
        $cost = yii::$app->request->post('cost') ?? yii::$app->request->get('cost');

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

        // Инициализация аккаунта
        $account = Account::initAccount();

        // Инициализация заказа
        $order = Order::searchById(Order::collectionName() . "/$order");

        if (empty($order) || empty($prod) || empty($catn) || empty($delivery) || empty($cost)) {
            // Не получены обязательные параметры

            yii::$app->response->statusCode = 500;

            goto end;
        }

        if ($order_edge_supply = OrderEdgeSupply::searchBySupplyData($catn, $prod, $delivery, $order)[0]) {
            // Удалось найти инстанцию поставки

            // Запись в буфер изначальных данных
            $old = $order_edge_supply->cost;

            // Запись в буфер записи в базу данных
            $order_edge_supply->cost = $cost;

            // Отправка в базу данных
            if ($order_edge_supply->update() > 0) {
                // Удалось сохранить изменения

                // Инициализация аккаунта покупателя
                $buyer = Account::searchById(AccountEdgeOrder::searchByOrder($order->readId())[0]->_from);

                // Отправка уведомления
                Notification::_write($this->renderPartial('/notification/system/orders/edit', ['order' => $order->_key, 'from' => $old, 'to' => $cost, 'target' => 'Цена поставки']), true, $buyer->_key, Notification::TYPE_NOTICE);

                // Запись в буфер вывода
                $buffer['cost'] = $order_edge_supply->cost;
            } else {
                // Не удалось сохранить изменения

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

        end:

        // Запись обязательных параметров
        $buffer['_csrf'] = yii::$app->request->getCsrfToken();

        // Инициализация данных заказов
        $data = Order::searchSmart(stts: '@last', limit: 10, page: 1, supplies: true);

        // Инициализация панели модератора заказов
        if (!yii::$app->user->isGuest && Account::isMinimalAuthorized($account)) $moderator_data = Order::searchSmart(account: '@all', stts: '@last', limit: 10, page: 1, supplies: true);
        else $moderator_data = null;

        // Запись в буфер вывода
        $buffer['main'] = $this->renderPartial('/orders/index', compact('data', 'moderator_data'));

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

        return $buffer;
    }

    /**
     * Редактирование времени доставки поставки в заказе (order_edge_supply)
     *
     * @param string $order Заказ в котором находится поставка
     * @param string $prod Производитель
     * @param string $catn Артикул
     * @param string $delivery Тип доставки
     *
     * @return string|array|null
     */
    public function actionSupplyEditTime(string $order, string $prod, string $catn, string $delivery): string|array|null
    {
        // Инициализация входных параметров
        $time = yii::$app->request->post('time') ?? yii::$app->request->get('time');

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

        // Инициализация аккаунта
        $account = Account::initAccount();

        // Инициализация заказа
        $order = Order::searchById(Order::collectionName() . "/$order");

        if (empty($order) || empty($prod) || empty($catn) || empty($delivery) || empty($time)) {
            // Не получены обязательные параметры

            yii::$app->response->statusCode = 500;

            goto end;
        }

        if ($order_edge_supply = OrderEdgeSupply::searchBySupplyData($catn, $prod, $delivery, $order)[0]) {
            // Удалось найти инстанцию поставки

            // Запись в буфер изначальных данных
            $old = $order_edge_supply->time;

            // Запись в буфер записи в базу данных
            $order_edge_supply->time = $time;

            // Отправка в базу данных
            if ($order_edge_supply->update() > 0) {
                // Удалось сохранить изменения

                // Инициализация аккаунта покупателя
                $buyer = Account::searchById(AccountEdgeOrder::searchByOrder($order->readId())[0]->_from);

                // Отправка уведомления
                Notification::_write($this->renderPartial('/notification/system/orders/edit', ['order' => $order->_key, 'from' => $old, 'to' => $time + 1, 'target' => 'Дата получения поставки']), true, $buyer->_key, Notification::TYPE_NOTICE);

                // Запись в буфер вывода
                $buffer['time'] = $order_edge_supply->time;
            } else {
                // Не удалось сохранить изменения

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

        end:

        // Запись обязательных параметров
        $buffer['_csrf'] = yii::$app->request->getCsrfToken();

        // Инициализация данных заказов
        $data = Order::searchSmart(stts: '@last', limit: 10, page: 1, supplies: true);

        // Инициализация панели модератора заказов
        if (!yii::$app->user->isGuest && Account::isMinimalAuthorized($account)) $moderator_data = Order::searchSmart(account: '@all', stts: '@last', limit: 10, page: 1, supplies: true);
        else $moderator_data = null;

        // Запись в буфер вывода
        $buffer['main'] = $this->renderPartial('/orders/index', compact('data', 'moderator_data'));

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

        return $buffer;
    }

    /**
     * Редактирование статуса поставки в заказе (order_edge_supply)
     *
     * @param string $order Заказ в котором находится поставка
     * @param string $prod Производитель
     * @param string $catn Артикул
     * @param string $delivery Тип доставки
     *
     * @return string|array|null
     */
    public function actionSupplyEditStts(string $order, string $prod, string $catn, string $delivery): string|array|null
    {
        // Инициализация входных параметров
        $stts = yii::$app->request->post('stts') ?? yii::$app->request->get('stts') ?? '';

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

        // Инициализация аккаунта
        $account = Account::initAccount();

        // Инициализация заказа
        $order = Order::searchById(Order::collectionName() . "/$order");

        if (empty($order) || empty($prod) || empty($catn) || empty($delivery) || empty($stts)) {
            // Не получены обязательные параметры

            yii::$app->response->statusCode = 500;

            goto end;
        }

        if ($order_edge_supply = OrderEdgeSupply::searchBySupplyData($catn, $prod, $delivery, $order)[0]) {
            // Удалось найти инстанцию поставки

            // Запись в буфер изначальных данных
            $old = $order_edge_supply->stts;

            // Запись в буфер записи в базу данных
            $order_edge_supply->stts = $stts;

            // Отправка в базу данных
            if ($order_edge_supply->update() > 0) {
                // Удалось сохранить изменения

                // Инициализация аккаунта покупателя
                $buyer = Account::searchById(AccountEdgeOrder::searchByOrder($order->readId())[0]->_from);

                // Отправка уведомления
                Notification::_write($this->renderPartial('/notification/system/orders/edit', ['order' => $order->_key, 'from' => Order::statusToRussian($old), 'to' => Order::statusToRussian($stts), 'target' => 'Статус поставки']), true, $buyer->_key, Notification::TYPE_NOTICE);

                // Запись в буфер вывода
                $buffer['stts'] = $order_edge_supply->stts;
            } else {
                // Не удалось сохранить изменения

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

        end:

        // Запись обязательных параметров
        $buffer['_csrf'] = yii::$app->request->getCsrfToken();

        // Инициализация данных заказов
        $data = Order::searchSmart(stts: '@last', limit: 10, page: 1, supplies: true);

        // Инициализация панели модератора заказов
        if (!yii::$app->user->isGuest && Account::isMinimalAuthorized($account)) $moderator_data = Order::searchSmart(account: '@all', stts: '@last', limit: 10, page: 1, supplies: true);
        else $moderator_data = null;

        // Запись в буфер вывода
        $buffer['main'] = $this->renderPartial('/orders/index', compact('data', 'moderator_data'));

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

        return $buffer;
    }

    /**
     * Запись комментария поставки в заказе (order_edge_supply)
     *
     * @param string $order Заказ в котором находится поставка
     * @param string $prod Производитель
     * @param string $catn Артикул
     * @param string $delivery Тип доставки
     *
     * @return string|array|null
     */
    public function actionSupplyEditComm(string $order, string $prod, string $catn, string $delivery): string|array|null
    {
        // Инициализация входных параметров
        $comm = yii::$app->request->post('comm') ?? yii::$app->request->get('comm');

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

        // Инициализация аккаунта
        $account = Account::initAccount();

        // Инициализация заказа
        $order = Order::searchById(Order::collectionName() . "/$order");

        if (empty($order) || empty($prod) || empty($catn) || empty($delivery) || empty($comm)) {
            // Не получены обязательные параметры

            yii::$app->response->statusCode = 500;

            goto end;
        }

        if ($order_edge_supply = OrderEdgeSupply::searchBySupplyData($catn, $prod, $delivery, $order)[0]) {
            // Удалось найти инстанцию поставки

            // Запись в буфер изначальных данных
            $old = $order_edge_supply->comm;

            // Запись в буфер записи в базу данных
            $order_edge_supply->comm = $comm;

            // Отправка в базу данных
            if ($order_edge_supply->update() > 0) {
                // Удалось сохранить изменения

                // Инициализация аккаунта покупателя
                $buyer = Account::searchById(AccountEdgeOrder::searchByOrder($order->readId())[0]->_from);

                // Отправка уведомления
                Notification::_write($this->renderPartial('/notification/system/orders/edit', ['order' => $order->_key, 'from' => $old, 'to' => $comm, 'target' => 'Комментарий поставки']), true, $buyer->_key, Notification::TYPE_NOTICE);

                // Запись в буфер вывода
                $buffer['comm'] = $order_edge_supply->comm;
            } else {
                // Не удалось сохранить изменения

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

        end:

        // Запись обязательных параметров
        $buffer['_csrf'] = yii::$app->request->getCsrfToken();

        // Инициализация данных заказов
        $data = Order::searchSmart(stts: '@last', limit: 10, page: 1, supplies: true);

        // Инициализация панели модератора заказов
        if (!yii::$app->user->isGuest && Account::isMinimalAuthorized($account)) $moderator_data = Order::searchSmart(account: '@all', stts: '@last', limit: 10, page: 1, supplies: true);
        else $moderator_data = null;

        // Запись в буфер вывода
        $buffer['main'] = $this->renderPartial('/orders/index', compact('data', 'moderator_data'));

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

        return $buffer;
    }
}
