<?php

declare(strict_types=1);

/*
 * Chill is a software for social workers
 *
 * For the full copyright and license information, please view
 * the LICENSE file that was distributed with this source code.
 */

namespace Chill\MainBundle\Tests\Export;

use Chill\MainBundle\Export\AggregatorInterface;
use Chill\MainBundle\Export\ExportGenerationContext;
use Chill\MainBundle\Export\ExportManager;
use Chill\MainBundle\Export\FilterInterface;
use Chill\MainBundle\Export\SortExportElement;
use Doctrine\ORM\QueryBuilder;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Contracts\Translation\TranslatableInterface;
use Symfony\Contracts\Translation\TranslatorInterface;

/**
 * @internal
 *
 * @coversNothing
 */
class SortExportElementTest extends KernelTestCase
{
    private SortExportElement $sortExportElement;

    public function setUp(): void
    {
        parent::setUpBeforeClass();
        $this->sortExportElement = new SortExportElement($this->makeTranslator());
    }

    public function testSortFilterRealData(): void
    {
        self::bootKernel();

        $sorter = self::getContainer()->get(SortExportElement::class);
        $translator = self::getContainer()->get(TranslatorInterface::class);
        $exportManager = self::getContainer()->get(ExportManager::class);
        $filters = $exportManager->getAllFilters();

        $sorter->sortFilters($filters);

        $previousName = null;
        foreach ($filters as $filter) {
            if ($filter->getTitle() instanceof TranslatableInterface) {
                continue;
            }

            if (null === $previousName) {
                $previousName = $translator->trans($filter->getTitle());
                continue;
            }

            $current = $translator->trans($filter->getTitle());
            if ($current === $previousName) {
                continue;
            }

            self::assertEquals(-1, $previousName <=> $current, sprintf("comparing '%s' and '%s'", $previousName, $current));
            $previousName = $current;
        }
    }

    public function testSortAggregator(): void
    {
        $aggregators = [
            'foo' => $a = $this->makeAggregator('a'),
            'zop' => $q = $this->makeAggregator('q'),
            'bar' => $c = $this->makeAggregator('c'),
            'baz' => $b = $this->makeAggregator('b'),
        ];

        $this->sortExportElement->sortAggregators($aggregators);

        self::assertEquals(['foo', 'baz', 'bar', 'zop'], array_keys($aggregators));
        self::assertSame($a, $aggregators['foo']);
        self::assertSame($b, $aggregators['baz']);
        self::assertSame($c, $aggregators['bar']);
        self::assertSame($q, $aggregators['zop']);
    }

    public function testSortFilter(): void
    {
        $filters = [
            'foo' => $a = $this->makeFilter('a'),
            'zop' => $q = $this->makeFilter('q'),
            'bar' => $c = $this->makeFilter('c'),
            'baz' => $b = $this->makeFilter('b'),
        ];

        $this->sortExportElement->sortFilters($filters);

        self::assertEquals(['foo', 'baz', 'bar', 'zop'], array_keys($filters));
        self::assertSame($a, $filters['foo']);
        self::assertSame($b, $filters['baz']);
        self::assertSame($c, $filters['bar']);
        self::assertSame($q, $filters['zop']);
    }

    private function makeTranslator(): TranslatorInterface
    {
        return new class () implements TranslatorInterface {
            public function trans(string $id, array $parameters = [], ?string $domain = null, ?string $locale = null)
            {
                return $id;
            }

            public function getLocale(): string
            {
                return 'en';
            }
        };
    }

    private function makeAggregator(string $title): AggregatorInterface
    {
        return new class ($title) implements AggregatorInterface {
            public function __construct(private readonly string $title) {}

            public function buildForm(FormBuilderInterface $builder): void {}

            public function getNormalizationVersion(): int
            {
                return 1;
            }

            public function normalizeFormData(array $formData): array
            {
                return [];
            }

            public function denormalizeFormData(array $formData, int $fromVersion): array
            {
                return [];
            }

            public function getFormDefaultData(): array
            {
                return [];
            }

            public function getLabels($key, array $values, mixed $data): callable
            {
                return fn ($v) => $v;
            }

            public function getQueryKeys($data): array
            {
                return [];
            }

            public function getTitle(): string|TranslatableInterface
            {
                return $this->title;
            }

            public function addRole(): ?string
            {
                return null;
            }

            public function alterQuery(QueryBuilder $qb, $data, ExportGenerationContext $exportGenerationContext): void {}

            public function applyOn(): string
            {
                return '';
            }
        };
    }

    private function makeFilter(string $title): FilterInterface
    {
        return new class ($title) implements FilterInterface {
            public function __construct(private readonly string $title) {}

            public function getTitle(): string|TranslatableInterface
            {
                return $this->title;
            }

            public function buildForm(FormBuilderInterface $builder): void {}

            public function getNormalizationVersion(): int
            {
                return 1;
            }

            public function normalizeFormData(array $formData): array
            {
                return [];
            }

            public function denormalizeFormData(array $formData, int $fromVersion): array
            {
                return [];
            }

            public function getFormDefaultData(): array
            {
                return [];
            }

            public function describeAction($data, ExportGenerationContext $context): string|TranslatableInterface|array
            {
                return ['a', []];
            }

            public function addRole(): ?string
            {
                return null;
            }

            public function alterQuery(QueryBuilder $qb, $data, ExportGenerationContext $exportGenerationContext): void {}

            public function applyOn(): string
            {
                return '';
            }
        };
    }
}
