<?php

declare(strict_types=1);

namespace app\models\traits;

use ArangoDBClient\Document;

trait SearchByEdge
{
    /**
     * Поиск через связи рёбрами с аккаунтом
     *
     * Аргумент $asArray и его реализацию пришлось добавить чтобы не переписывать кучу кода
     */
    public static function searchByEdge(
        string $from,
        string $to,
        string|null $edge = null,
        string $direction = 'ANY',
        int|null $limit = 10,
        int|null $offset = 0,
        array $sort = ['ASC'],
        string|array $subquery_where = [],
        string|array $subquery_select = null,
        array $foreach = [],
        string|array $where = [],
        array|null $let = [],
        string|array $select = null,
        callable|null $handle = null,
        array|null $filterStart = null,
        array $params = [],
        bool $asArray = true,
        bool $debug = false,
        bool $aql = false,
        bool $count = false
    ): mixed {
        $subquery = static::find()
            ->params($params)
            ->for([$from, $edge ?? $from . '_edge_' . $to])
            ->traversal($to, $direction)
            ->in($edge ?? $from . '_edge_' . $to)
            ->where($subquery_where);

        $subquery = $subquery
            ->select($subquery_select ?? $edge ?? $from . '_edge_' . $to)
            ->createCommand();

        $query = static::find()
            ->params($subquery->getBindVars())
            ->let($edge ?? $from . '_edge_' . $to, '(' . (string) $subquery . ')')
            ->limit($limit)
            ->offset($offset)
            ->orderBy($sort);

        if (!empty($let)) {
            // Переданы дополнительные условия фильтрации

            $query->let(...$let);
        }

        if (!empty($filterStart)) {
            // Переданы дополнительные условия фильтрации

            $query->filter($filterStart, 'START_SENSETIVE');
        }

        // Инициализация
        $request = $query
            ->foreach($foreach)
            ->where($where)
            ->limit($limit)
            ->select($select ?? $to);

        // Режим вывода строки запроса
        if ($aql) {
            // Запрошена проверка

            return (string) $request->createCommand();
        }

        // Режим проверки
        if ($debug) {
            // Запрошена проверка

            var_dump((string) $request->createCommand());

            return null;
        }

        // Запрос
        if ($count) {
            // Запрошен подсчет

            return $query->count();
        } else if (isset($handle)) {
            // Передана функция для постобработки

            return $handle($request);
        } else if (isset($select)) {
            // Указан выбор свойств

            $response = $request->createCommand()->execute()->getAll();

            if ($asArray) {
                // Передан параметр указывающий на необходимость возврата как объекта

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

                    if ($attribute instanceof Document) {
                        // Получена инстанция документа ArangoDB

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

            return $response;
        } else {
            // Иначе просто запросить для ActiveQuery

            return $request->all();
        }
    }
}
