<?php

declare(strict_types=1);

namespace app\models\traits;

use yii;

use exception;

trait SearchByEdge
{
    /**
     * Поиск через связи рёбрами с аккаунтом
     *
     * @param string $id Идентификатор пользователя
     * @param int $limit Количество
     * @param int $offset Сдвиг
     * @param string $sort Сортировка
     */
    public static function searchByEdge(
        string $from,
        string $to,
        string $edge = null,
        int $limit = 10,
        int $offset = 0,
        array $sort = ['ASC'],
        string|array $subquery_where = [],
        array $foreach = [],
        string|array $where = [],
        string $direction = 'ANY',
        array $let = [],
        string|array $select = null,
        callable $handle = null,
        array &$params = []
    ): ?array {
        $subquery = static::find()
            ->for([$from, $edge ?? $from . '_edge_' . $to])
            ->traversal($to, $direction)
            ->in($edge ?? $from . '_edge_' . $to)
            ->where($subquery_where);

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

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

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

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

        // Запрос
        $request = $query
            ->foreach($foreach)
            ->where($where)
            ->select($select ?? $to);

        if (isset($handle)) {
            // Передана функция для постобработки

            return $handle($request);
        } else if (isset($select)) {
            $response = $request->createCommand()->execute()->getAll();

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

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

            return $response;
        } else {
            return $request->all();
        }
    }
}
