<?php

namespace App\Livewire\Products;

use Daylight\Core\Models\Attribute;
use Daylight\Core\Models\Category;
use Daylight\Core\Models\Product;
use Daylight\Core\Modules\Search\Entities\SearchResult;
use Daylight\Core\Modules\Search\SearchQueryBuilder;
use Illuminate\Support\Collection;
use Illuminate\View\View;
use Livewire\Attributes\Url;
use Livewire\Component;

class Browser extends Component
{
    public ?Category $category = null;

    #[Url]
    public array $filters = [];

    #[Url(as: 'q')]
    public ?string $searchQuery = null;

    #[Url(as: 'sort')]
    public string $sortBy = 'relevance';

    public array|Collection $dataLayerProducts = [];

    public array $filterTranslations = [];

    public function mount(): void
    {
        $this->filterTranslations = Attribute::query()
            ->whereFilterable(true)
            ->with([
                'translations' => fn ($q) => $q->where('locale', app()->getLocale()),
            ])
            ->get()
            ->mapWithKeys(function ($attribute) {
                return [
                    $attribute->key => $attribute->translations->first()?->name ?? __('N/A'),
                ];
            })
            ->toArray();

        if (count($this->filters) === 0) {
            $this->filters = $this->getFacets()
                ->mapWithKeys(fn ($facet, $key) => [$key => []])
                ->toArray();
        }
    }

    private function getActiveFilters(): array
    {
        return [
            ...($this->category ? ['categories' => [$this->category->id]] : []),
            ...$this->filters,
        ];
    }

    private function getFacets(): Collection
    {
        return collect([
            'brand' => __('Brand'),
            'price' => __('Price'),
            ...$this->filterTranslations,
        ]);
    }

    public function getSearchQuery(): SearchResult
    {
        $query = SearchQueryBuilder::create()
            ->setBaseQuery(
                Product::query()
                    ->with([
                        'translations' => fn ($q) => $q->where('locale', app()->getLocale()),
                        'variants.media',
                        'variants.prices',
                        'labels.translations' => fn ($q) => $q->where('locale', app()->getLocale()),
                    ])
            )
            ->setAvailableFacets(
                $this->getFacets()
            )
            ->setSearchQuery($this->searchQuery)
            ->setAvailableSortingOptions(collect([
                'relevance' => __('Relevance'),
                'created_at:desc' => __('Latest articles'),
                'price:asc' => __('Price (low to high)'),
                'price:desc' => __('Price (high to low)'),
            ]))
            ->setSortBy($this->sortBy)
            ->setActiveFilters($this->getActiveFilters())
            ->get();

        $this->dataLayerProducts = collect($query->getResults()?->items() ?? [])->map(function (Product $product) {
            return $product->getDataLayerInformation();
        });

        return $query;
    }

    public function updatedFilters(): void
    {
        $this->dispatch('products-refreshed');
    }

    public function updatedSearchQuery(): void
    {
        $this->dispatch('products-refreshed');
    }

    public function updatedSortBy(): void
    {
        $this->dispatch('products-refreshed');
    }

    public function dataLayerProducts(): Collection
    {
        return collect($this->getSearchQuery()->getResults()?->items())?->map(function (Product $product) {
            return [
                'id' => $product->id,
            ];
        });
    }

    public function getCategories(): Collection
    {
        if ($this->category) {
            $children = $this->category->children()->with(['translations' => fn ($q) => $q->where('locale', app()->getLocale())])->get();

            if ($children->isNotEmpty()) {
                return $children;
            }

            return $this->category->siblingsAndSelf()->with(['translations' => fn ($q) => $q->where('locale', app()->getLocale())])->get();
        }

        return Category::query()
            ->with(['translations' => fn ($q) => $q->where('locale', app()->getLocale())])
            ->whereNull('parent_id')->get();
    }

    public function render(): View
    {
        return view('livewire.products.browser', [
            'categories' => $this->getCategories(),
            'searchResult' => $this->getSearchQuery(),
        ]);
    }
}
