<?php

declare(strict_types=1);

namespace app\models;

/**
 * Ребро
 */
abstract class Edge extends Document
{
    /**
     * Свойства
     */
    public function attributes(): array
    {
        return array_merge(
            parent::attributes(),
            [
                '_from',
                '_to',
                'type'
            ]
        );
    }

    /**
     * Метки свойств
     */
    public function attributeLabels(): array
    {
        return array_merge(
            parent::attributeLabels(),
            [
                'date' => 'От кого',
                'date' => 'К кому',
                'type' => 'Тип'
            ]
        );
    }

    /**
     * Правила
     */
    public function rules(): array
    {
        return array_merge(
            parent::rules(),
            [
                [
                    ['_from', '_to'],
                    'required',
                    'message' => 'Заполните поле: {attribute}'
                ],
                [
                    'type',
                    'string'
                ]
            ]
        );
    }

    /**
     * Перед сохранением
     *
     * @todo Подождать обновление от ебаного Yii2 и добавить
     * проверку типов передаваемых параметров
     */
    public function beforeSave($data): bool
    {
        if (parent::beforeSave($data)) {
            if ($this->isNewRecord) {
            }

            $this->type = $this->type ?? '';

            return true;
        }

        return false;
    }

    /**
     * Записать (с проверкой на существование)
     *
     * Создаст ребро только в том случае, если его аналога не существует
     */
    public static function writeSafe(string $_from, string $_to, string $type = '', array $data = []): ?static
    {
        if ($edge = self::searchByVertex($_from, $_to, 1)) {
            // Найдено в базе данных

            return $edge;
        }

        return self::write($_from, $_to, $type, $data);
    }

    /**
     * Записать
     */
    public static function write(string $_from, string $_to, string $type = '', array $data = []): ?static
    {
        // Инициализация
        $edge = new static;

        // Настройка
        $edge->_from = $_from;
        $edge->_to = $_to;
        $edge->type = $type;

        foreach ($data as $key => $value) {
            if (is_int($key)) {
                // Обычная запись

                $edge->{$value} = true;
            } else {
                // Ассоциативная запись

                $edge->{$key} = $value;
            }
        }

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

    /**
     * Поиск ребра по его вершинам
     */
    public static function searchByVertex(string $_from, string $_to, int $limit = 1): static|array|null
    {
        $query = self::find()->where(['_from' => $_from, '_to' => $_to]);

        if ($limit <= 1) {
            return $query->one();
        } else {
            return $query->limit($limit)->all();
        }
    }
}
