<?php

namespace Daylight\Core\Modules\Search\Entities;

use Daylight\Core\Models\Translations\AttributeTranslation;
use Daylight\Core\Modules\Search\SearchQueryBuilder;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Collection;

class SearchResult
{
    protected $results = [];

    public ?Collection $activeFilters;

    protected ?Collection $cachedFacets = null;

    protected ?array $cachedFacetDistributions = null;

    protected ?Collection $cachedTranslations = null;

    public function __construct(
        public SearchQueryBuilder $request,
        public Builder $baseQuery,
        public readonly Collection $originalResults
    ) {
        $this->activeFilters = $this->request->getActiveFilters();
    }

    public function getActiveFilters(bool $formatted = true, bool $ignoreCategory = true): Collection
    {
        $filters = clone $this->request->getActiveFilters();

        if ($ignoreCategory) {
            $filters->forget('categories');
        }

        if ($formatted) {
            return $filters->filter()->mapWithKeys(function ($values, $key) {
                if ($key === 'price') {
                    return collect([
                        $key => collect([
                            new ActivePriceFilter($this, 'price', $values),
                        ]),
                    ]);
                }

                return [
                    $key => collect($values)->map(function ($value) use ($key) {
                        return new ActiveFilter($this, $key, $value);
                    }),
                ];
            })->flatten()->values();
        }

        return $filters;
    }

    public function estimatedTotalHits(): int
    {
        return $this->originalResults->first()['estimatedTotalHits'];
    }

    public function getSortingOptions(): Collection
    {
        return $this->request->getSortingOptions()->map(function ($value, $key) {
            return new SortingOption($this, $key, $value);
        });
    }

    public function getFacets(): Collection
    {
        if ($this->cachedFacets !== null) {
            return $this->cachedFacets;
        }

        $this->cachedFacetDistributions = collect($this->originalResults)
            ->pluck('facetDistribution')
            ->flattenKeepKeys()
            ->toArray();

        $this->cachedTranslations = $this->loadTranslations();

        $this->cachedFacets = $this->request->getAvailableFacets()
            ->map(function ($name, $property) {
                return new Facet($this, $property, $name);
            })
            ->filter(function (Facet $facet) {
                $distributions = $this->cachedFacetDistributions[$facet->property] ?? [];

                return ! empty($distributions);
            })
            ->values();

        return $this->cachedFacets;
    }

    protected function loadTranslations(): Collection
    {
        $locale = app()->getLocale();
        $translations = AttributeTranslation::all();

        return collect([
            'brand' => $translations->get('brand') ?? collect(),
            'attributeValues' => $translations->get('attributeValues') ?? collect(),
        ]);
    }

    public function getCachedFacetDistributions(): array
    {
        if ($this->cachedFacetDistributions === null) {
            $this->cachedFacetDistributions = collect($this->originalResults)
                ->pluck('facetDistribution')
                ->flattenKeepKeys()
                ->toArray();
        }

        return $this->cachedFacetDistributions;
    }

    public function getCachedTranslations(): Collection
    {
        if ($this->cachedTranslations === null) {
            $this->cachedTranslations = $this->loadTranslations();
        }

        return $this->cachedTranslations;
    }

    public function getResults()
    {
        if ($this->results) {
            return $this->results;
        }

        if ($this->estimatedTotalHits() === 0) {
            return collect()->paginateMeilisearchResults($this->estimatedTotalHits(), $this->request->getPerPage());
        }

        $hits = collect($this->originalResults->first()['hits']);

        if ($hits->count() === 0) {
            return collect();
        }

        if (config('database.default') === 'pgsql') {
            $products = $this->baseQuery
                ->whereIn('id', $hits->pluck('id'))
                ->orderByRaw('position(id::text in \'' . $hits->pluck('id')->implode(',') . '\')')
                ->get();
        } else {
            $products = $this->baseQuery
                ->whereIn('id', $hits->pluck('id'))
                ->orderByRaw('FIELD(id, ' . $hits->pluck('id')->implode(',') . ')')
                ->get();
        }

        $this->results = $products->paginateMeilisearchResults($this->estimatedTotalHits(), $this->request->getPerPage());

        return $this->results;
    }
}
