<?php

/*
 * This file is part of Monsieur Biz' Search plugin for Sylius.
 *
 * (c) Monsieur Biz <sylius@monsieurbiz.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

declare(strict_types=1);

namespace MonsieurBiz\SyliusSearchPlugin\Helper;

class FilterHelper implements FilterHelperInterface
{
    public const MAIN_TAXON_FILTER = 'main_taxon';

    public const TAXON_FILTER = 'taxon';

    public const PRICE_FILTER = 'price';

    private SlugHelperInterface $slugHelper;

    public function __construct(SlugHelperInterface $slugHelper)
    {
        $this->slugHelper = $slugHelper;
    }

    public function buildFilters(array $appliedFilters): array
    {
        if (count($appliedFilters) === 0) {
            return [];
        }

        $filters = [];
        foreach ($appliedFilters as $field => $values) {
            if (self::TAXON_FILTER === $field) {
                $filters[] = $this->buildTaxonFilter($values);
            } elseif (self::MAIN_TAXON_FILTER === $field) {
                $filters[] = $this->buildMainTaxonFilter($values);
            } elseif (self::PRICE_FILTER === $field) {
                if (isset($values['min'], $values['max'])) {
                    $min = $values['min'] !== '' ? (int) $values['min'] : null;
                    $max = $values['max'] !== '' ? (int) $values['max'] : null;
                    $priceFilter = $this->buildPriceFilter($min, $max);
                    if (count($priceFilter) > 0) {
                        $filters[] = $priceFilter;
                    }
                }
            } else {
                $filters[] = $this->buildFilter($field, $values);
            }
        }

        return [
            'bool' => [
                'filter' => $filters,
            ],
        ];
    }

    public function buildFilter(string $field, array $values): array
    {
        $filterValues = [];
        foreach ($values as $value) {
            $filterValues[] = $this->buildFilterValue($value);
        }

        return [
            'nested' => [
                'path' => 'attributes',
                'query' => [
                    'bool' => [
                        'must' => [
                            'match' => [
                                'attributes.code' => $field,
                            ],
                        ],
                        'should' => $filterValues,
                        'minimum_should_match' => 1,
                    ],
                ],
            ],
        ];
    }

    public function buildTaxonFilter(array $values): array
    {
        $filterValues = [];
        foreach ($values as $value) {
            $filterValues[] = $this->buildTaxonFilterValue($value);
        }

        return [
            'nested' => [
                'path' => 'taxon',
                'query' => [
                    'bool' => [
                        'should' => $filterValues,
                        'minimum_should_match' => 1,
                    ],
                ],
            ],
        ];
    }

    public function buildMainTaxonFilter(array $values): array
    {
        $filterValues = [];
        foreach ($values as $value) {
            $filterValues[] = $this->buildMainTaxonFilterValue($value);
        }

        return [
            'nested' => [
                'path' => 'mainTaxon',
                'query' => [
                    'bool' => [
                        'should' => $filterValues,
                        'minimum_should_match' => 1,
                    ],
                ],
            ],
        ];
    }

    public function buildPriceFilter(?int $min, ?int $max): array
    {
        $filters = [];
        if (null !== $min) {
            $filters['gte'] = $min * 100;
        }
        if (null !== $max) {
            $filters['lte'] = $max * 100;
        }

        if (count($filters) === 0) {
            return [];
        }

        return [
            'nested' => [
                'path' => 'price',
                'query' => [
                    'range' => [
                        'price.value' => [$filters],
                    ],
                ],
            ],
        ];
    }

    public function buildFilterValue(string $value): array
    {
        return [
            'term' => [
                'attributes.value.keyword' => $this->slugHelper->toLabel($value),
            ],
        ];
    }

    public function buildTaxonFilterValue(string $value): array
    {
        return [
            'term' => [
                'taxon.name' => $this->slugHelper->toLabel($value),
            ],
        ];
    }

    public function buildMainTaxonFilterValue(string $value): array
    {
        return [
            'term' => [
                'mainTaxon.name' => $this->slugHelper->toLabel($value),
            ],
        ];
    }
}
