<?php

declare(strict_types=1);

namespace KupShop\CatalogElasticBundle\Filters;

use KupShop\CatalogBundle\ProductList\DynamicFilterAttributes;
use KupShop\CatalogElasticBundle\DataContext\ElasticFilterSpecContext;
use KupShop\CatalogElasticBundle\DataContext\ElasticFilterValuesContext;
use KupShop\CatalogElasticBundle\Elastica\QueryBuilder;
use KupShop\CatalogElasticBundle\Enum\FilterValuesOrder;

class Producers extends ElasticFilter
{
    use QueryBuilder;

    public const ELASTIC_FIELD_NAME = 'filter_producer';

    public function getAggregations(DynamicFilterAttributes $attributes): iterable
    {
        if (!$attributes->producers) {
            return [];
        }

        $detail = $this->agg()->top_hits('detail')
            ->setSize(1)
            ->setSource([
                'includes' => [
                    'filter_producer.id',
                    'filter_producer.name',
                    'filter_producer.photo',
                    'filter_producer.filter_url',
                ],
            ]);

        yield $this->agg()
            ->terms(self::filterIdentifier())
            ->setField(self::ELASTIC_FIELD_NAME.'.id')
            ->addAggregation($detail);
    }

    public function applyFilters(ElasticFilterSpecContext $ctx): void
    {
        if (!is_array($ctx->value)) {
            return;
        }

        $filter = $this->query()->terms(self::ELASTIC_FIELD_NAME.'.id', $ctx->value);

        $ctx->set(self::filterIdentifier(), $filter);
    }

    public function collectValues(ElasticFilterValuesContext $ctx): void
    {
        $aggregations = $ctx->getTargetAggregations();

        if (empty($aggregations)) {
            $ctx->set('producers', [
                'values' => [],
            ]);

            return;
        }

        assert(count($aggregations) === 1, 'Tady by jich víc být nemělo.');
        $aggregation = reset($aggregations);

        $values = [];
        foreach ($aggregation->getBuckets() as $producerBucket) {
            $detail = $producerBucket['detail']['hits']['hits'][0]['_source']['filter_producer'] ?? null;
            if (!$detail) {
                continue;
            }

            $values[$detail['id']] = array_merge($detail, [
                'count' => $producerBucket['doc_count'],
            ]);
        }

        if ($ctx->getOrderBy() === FilterValuesOrder::Admin) {
            usort($values, static fn ($a, $b) => strcasecmp($a['name'], $b['name']));
        }

        $ctx->set('producers', [
            'values' => $values,
            'values_count' => $aggregation->getTotalBucketCount(),
        ]);
    }

    public function supportsOrderBy(): bool
    {
        return true;
    }
}
