<?php

declare(strict_types=1);

namespace app\models;

use moonland\phpexcel\Excel;
use app\models\traits\SearchByEdge;

/**
 * Продукт (в ассортименте магазина)
 *
 * Представляет собой лот состоящий из предложений от поставщиков
 *
 * @see Supply Поставки для продуктов
 */
class Product extends Document
{
    use SearchByEdge;

    /**
     * Сценарий импорта из .excel документа
     */
    const SCENARIO_IMPORT = 'import';

    /**
     * Сценарий записи товара
     */
    const SCENARIO_WRITE = 'write';

    /**
     * Файл .excel для импорта товаров
     */
    public Excel|null $file = null;

    /**
     * Группа в которой состоит товар
     */
    public ProductGroup|null $group = null;

    /**
     * Имя коллекции
     */
    public static function collectionName(): string
    {
        return 'product';
    }

    /**
     * Свойства
     */
    public function attributes(): array
    {
        return array_merge(
            parent::attributes(),
            [
                'name',
                'desc',
                'ocid',
                'catn',
                'imgs',
                'time',
                'oemn',
                'cost'
            ]
        );
    }

    /**
     * Метки свойств
     */
    public function attributeLabels(): array
    {
        return array_merge(
            parent::attributeLabels(),
            [
                'name' => 'Название',
                'desc' => 'Описание',
                'ocid' => 'Идентификатор 1C',
                'catn' => 'Каталожный номер',
                'imgs' => 'Изображения',
                'time' => 'Срок доставки',
                'oemn' => 'OEM номера',
                'cost' => 'Стоимость',
                'file' => 'Документ',
                'group' => 'Группа'
            ]
        );
    }

    /**
     * Правила
     */
    public function rules(): array
    {
        return array_merge(
            parent::rules(),
            [
                [
                    [
                        'name',
                        'catn'
                    ],
                    'required',
                    'message' => 'Заполните поля: {attribute}',
                    'on' => self::SCENARIO_WRITE,
                    'except' => self::SCENARIO_IMPORT
                ],
                [
                    'file',
                    'required',
                    'message' => 'Заполните поля: {attribute}',
                    'on' => self::SCENARIO_IMPORT
                ],
                [
                    'catn',
                    'string',
                    'message' => '{attribute} должен быть строкой'
                ],
                [
                    [
                        'oemn',
                        'imgs'
                    ],
                    'arrayValidator',
                    'message' => '{attribute} должен быть массивом.'
                ],
                [
                    'file',
                    'file',
                    'skipOnEmpty' => false,
                    'extensions' => 'xlsx',
                    'checkExtensionByMimeType' => false,
                    'maxFiles' => 5,
                    'maxSize' => 1024 * 1024 * 30,
                    'wrongExtension' => 'Разрешены только документы в формате: ".xlsx"',
                    'message' => 'Проблема при чтении документа',
                    'on' =>  self::SCENARIO_IMPORT
                ]
            ]
        );
    }

    /**
     * Запись
     *
     * @param string $catn Артикул, каталожный номер
     */
    public static function initEmpty(string $catn): self|array
    {
        $oemn = self::convertOemn2Catn($catn);

        if (count($oemn) === 1) {
            // Передан только один артикул

            if ($model = self::searchByCatn($catn)) {
                // Продукт уже существует

                return $model;
            }

            // Запись
            return self::writeEmpty($catn);
        }

        // Инициализация
        $models = [];

        foreach ($oemn as $catn) {
            // Перебор всех найденных артикулов

            if ($model = self::searchByCatn($catn)) {
                // Продукт уже существует

                continue;
            }

            // Запись
            if ($model = self::writeEmpty($catn)) {
                // Записано

                // Запись в массив сохранённых моделей
                $models[] = $model;
            }
        }

        return $models;
    }

    /**
     * Запись
     */
    public static function writeEmpty(string $catn): ?self
    {
        // Инициализация
        $model = new self;

        // Настройки
        $model->catn = $catn;

        // Запись
        return $model->save() ? $model : null;
    }

    /**
     * Поиск OEM номеров
     *
     * @param string $oemn OEM номера
     * @param string $delimiters Разделители
     *
     * @todo НЕ ЗАБЫТЬ СДЕЛАТЬ НАСТРОЙКУ РАЗДЕЛИТЕЛЕЙ
     */
    public static function convertOemn2Catn(string $oemn, string $delimiters = '\s\+\/,'): array
    {
        // Инициализация
        $catn = [];

        // Конвертация
        preg_match_all("/[^$delimiters]+/", $oemn, $catn);

        return $catn[0];
    }

    /**
     * Импорт товаров
     *
     * На данный момент обрабатывает только импорт из
     * файлов с расширением .excel
     */
    public function import(): bool
    {
        // Инициализация массива данных
        $data = [];

        if ($this->validate()) {
            foreach ($this->file as $file) {
                // Перебор файлов

                // Сохранение на диск
                if (!file_exists('../assets/import/excel/')) {
                    mkdir('../assets/import/excel/', 0775, true);
                }
                $file->saveAs($path = '../assets/import/excel/' . $file->baseName . '.' . $file->extension);

                // Проверка файла пройдена

                $data[] = Excel::import($path, [
                    'setFirstRecordAsKeys' => true,
                    'setIndexSheetByName' => true,
                ]);
            }

            foreach ($data[0] as $doc) {
                // Перебор полученных документов

                // Сохранение в базе данных
                $product = new static($doc);

                if ($product->validate()) {
                    // Проверка пройдена

                    // Запись документа
                    $product->save();

                    // Запись группы
                    $group = static::class . 'Group';
                    (new $group())->writeMember($product, $this->group);
                } else {
                    // Проверка не пройдена
                    foreach ($product->errors as $attribute => $error) {
                        $this->addError($attribute, $error);
                    }
                }
            }

            return true;
        }

        return false;
    }

    /**
     * Поиск по каталожному номеру
     *
     * Ищет продукт и возвращает его,
     * либо выполняет поиск через представление
     *
     * @todo Переделать нормально
     */
    public static function searchByCatn(string $catn, int $limit = 1, array $select = []): static|array|null
    {
        if ($limit <= 1) {
            return static::findOne(['catn' => $catn]);
        }

        $query = self::find()
            ->collection('product_search')
            ->search(['catn' => $catn])
            ->limit($limit)
            ->select($select)
            ->createCommand()
            ->execute()
            ->getAll();

        foreach ($query as &$attribute) {
            // Приведение всех свойств в массив и очистка от лишних данных

            $attribute = $attribute->getAll();
        }

        return $query;
    }
}
