<?php

declare(strict_types=1);

namespace apexl\Io\collections;

use apexl\Io\dto\LoaderSort;
use apexl\Vault\enums\SortDirection;
use Arrayy\Collection\AbstractCollection;

/**
 * @extends AbstractCollection<array-key, LoaderSort>
 */
final class LoaderSortCollection extends AbstractCollection
{

    /**
     * @param (array|string|LoaderSort)[] $sorts
     */
    private static function resolveSorts(array $sorts): array
    {
        $output = [];
        foreach ($sorts as $sort) {
            if ($sort instanceof LoaderSort) {
                $output[] = $sort;
            } elseif (is_string($sort)) {
                $output[] = LoaderSort::createFromString($sort);
            } elseif (is_array($sort)) {
                if (($sort[1] ?? null) instanceof SortDirection) {
                    $output[] = LoaderSort::createFromArray($sort);
                } else {
                    $output = [
                        ...$output,
                        ...self::resolveSorts($sort)
                    ];
                }
            }
        }

        return $output;
    }

    public static function createFromArray(array $array): LoaderSortCollection
    {
        $array = self::resolveSorts($array);

        return parent::createFromArray($array);
    }

    public function getType(): string
    {
        return LoaderSort::class;
    }

    public function toSql(): string
    {
        $string = $this->map(fn(LoaderSort $sort): string => $sort->toSql())->implode(', ');

        return $string ? sprintf('ORDER BY %s', $string) : '';
    }

    public function unique(): LoaderSortCollection
    {
        if ($this->count() < 2) {
            return $this;
        }

        $array = $this->toArray();
        $cols = array_map(fn(LoaderSort $sort): string => $sort->field, $array);
        $keys = array_keys(array_unique($cols));
        $output = array_values(array_filter($array, fn(int $key): bool => in_array($key, $keys), ARRAY_FILTER_USE_KEY));

        return LoaderSortCollection::createFromArray($output);
    }
}
