<?php

namespace App\Services\Site;

use App\Models\Agency\Agency;
use App\Models\DayTour\DayTour;
use App\Models\InternationalTour\InternationalTour;
use App\Models\Product\ProductType;
use App\Models\Tour\Tour;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Collection;

/**
 * Public sitenin tur veri katmanı.
 *
 * Zorunlu web filtreleri her sorguda uygulanır:
 * turlar is_active + is_public + !is_draft (+ yayın/pasif tarih pencereleri).
 * Özel kalkışlar (is_private) tarih listelerinde asla dışarı sızmaz.
 */
class SiteTourCatalog
{
    /** ürün tipi kodu => [model, tarih ilişkisi adı] */
    public const TYPE_MODELS = [
        'kultur-turu' => Tour::class,
        'gunubirlik-tur' => DayTour::class,
        'yurtdisi-turu' => InternationalTour::class,
    ];

    /** Acentenin web'de listelenebilir tur tipleri (yetki ∩ desteklenen modeller). */
    public function visibleTourTypes(Agency $agency): Collection
    {
        return ProductType::active()
            ->whereIn('code', array_keys(self::TYPE_MODELS))
            ->whereHas('agencies', fn ($q) => $q->where('agencies.id', $agency->id)
                ->where('agency_product_types.is_active', true))
            ->orderBy('sort_order')
            ->get();
    }

    public function typeFromRouteSlug(Agency $agency, string $routeSlug): ?ProductType
    {
        return $this->visibleTourTypes($agency)
            ->first(fn (ProductType $type) => $type->route_slug === $routeSlug);
    }

    public function baseQuery(Agency $agency, string $typeCode): ?Builder
    {
        $model = self::TYPE_MODELS[$typeCode] ?? null;
        if (! $model) {
            return null;
        }

        return $model::query()
            ->where('agency_id', $agency->id)
            ->where('is_active', true)
            ->where('is_public', true)
            ->where('is_draft', false)
            ->where(fn ($q) => $q->whereNull('published_at')->orWhere('published_at', '<=', now()))
            ->where(fn ($q) => $q->whereNull('expires_at')->orWhere('expires_at', '>', now()))
            ->with(['coverImage.diskItem', 'product']);
    }

    /**
     * Liste sayfası sorgusu. Filtreler: q (ad/açıklama), category_id,
     * min_days / max_days, sort (recommended|price_asc|price_desc|newest).
     */
    public function paginate(Agency $agency, ProductType $type, array $filters = [], int $perPage = 12): ?LengthAwarePaginator
    {
        $query = $this->baseQuery($agency, $type->code);
        if (! $query) {
            return null;
        }

        if (! empty($filters['q'])) {
            $term = '%' . str_replace(['%', '_'], ['\\%', '\\_'], $filters['q']) . '%';
            $query->where(fn ($q) => $q->where('name', 'like', $term)
                ->orWhere('short_description', 'like', $term)
                ->orWhere('description', 'like', $term));
        }

        if (! empty($filters['category_id'])) {
            $categoryId = (int) $filters['category_id'];
            $query->whereHas('product.categories', fn ($q) => $q->where('product_categories.id', $categoryId));
        }

        if ($type->code !== 'gunubirlik-tur') {
            if (! empty($filters['min_days'])) {
                $query->where('days', '>=', (int) $filters['min_days']);
            }
            if (! empty($filters['max_days'])) {
                $query->where('days', '<=', (int) $filters['max_days']);
            }
        }

        match ($filters['sort'] ?? 'recommended') {
            'newest' => $query->orderByDesc('created_at'),
            'name' => $query->orderBy('name'),
            default => $query->orderByDesc('is_featured')->orderByDesc('priority')->orderByDesc('booking_count'),
        };

        return $query->paginate($perPage)->withQueryString();
    }

    /** Vitrin (tour_showcase section) — tüm görünür tiplerden karışık. */
    public function showcase(Agency $agency, string $source = 'featured', int $limit = 6): Collection
    {
        $tours = collect();

        foreach ($this->visibleTourTypes($agency) as $type) {
            $query = $this->baseQuery($agency, $type->code);
            if (! $query) {
                continue;
            }

            // Kaynak seçimi FİLTREdir, sıralama değil: "Öne çıkanlar" seçiliyken
            // yalnızca tur kartında işaretlenmiş turlar vitrine girer. İşaretli
            // tur yoksa bölüm hiç çizilmez (yanlışlıkla rastgele tur gösterilmez).
            match ($source) {
                'new' => $query->where('is_new', true)->orderByDesc('created_at'),
                'bestseller' => $query->where('is_bestseller', true)->orderByDesc('booking_count'),
                default => $query->where('is_featured', true)->orderByDesc('priority'),
            };

            $tours = $tours->concat(
                $query->limit($limit)->get()->each(fn ($tour) => $tour->setAttribute('site_type', $type))
            );
        }

        return $tours
            ->sortByDesc(fn ($t) => [(bool) $t->is_featured, (int) ($t->priority ?? 0)])
            ->take($limit)
            ->values();
    }

    /** Detay: slug ile tur + tüm web verileri eager load. */
    public function findBySlug(Agency $agency, ProductType $type, string $slug)
    {
        $query = $this->baseQuery($agency, $type->code);
        if (! $query) {
            return null;
        }

        $isDayTour = $type->code === 'gunubirlik-tur';

        return $query
            ->where('slug', $slug)
            ->with(array_filter([
                'galleryImages.diskItem',
                'itineraries',
                'transferPoints',
                'departureCity',
                $isDayTour ? null : 'sliderImages.diskItem',
                $isDayTour ? null : 'arrivalCity',
            ]))
            ->first();
    }

    /**
     * Detay/fiyat tablosu için rezervasyona açık tarihler.
     * Özel kalkışlar (is_private) burada filtrelenir.
     */
    public function bookableDates($tour, int $limit = 24): Collection
    {
        if ($tour instanceof DayTour) {
            return $tour->tourDates()
                ->where('is_active', true)
                ->where('is_private', false)
                ->where('tour_date', '>=', now()->toDateString())
                ->whereIn('status', ['available', 'guaranteed'])
                ->with('marketplacePrices')
                ->limit($limit)
                ->get();
        }

        return $tour->tourDates()
            ->where('is_active', true)
            ->where('is_published', true)
            ->where('is_bookable', true)
            ->where('is_private', false)
            ->where('start_date', '>', now())
            ->with('marketplacePrices')
            ->orderBy('start_date')
            ->limit($limit)
            ->get();
    }

    /**
     * Destinasyon mozaiği: varış şehrine göre tur sayıları + kapak görseli.
     * @return Collection<int, object{name: string, count: int, image: ?string, type_slug: string, city_id: int}>
     */
    public function destinations(Agency $agency, int $limit = 6): Collection
    {
        $buckets = [];

        foreach ($this->visibleTourTypes($agency) as $type) {
            $query = $this->baseQuery($agency, $type->code);
            if (! $query) {
                continue;
            }

            $cityRelation = $type->code === 'gunubirlik-tur' ? 'departureCity' : 'arrivalCity';
            $cityKey = $type->code === 'gunubirlik-tur' ? 'departure_city_id' : 'arrival_city_id';

            $query->whereNotNull($cityKey)->with($cityRelation)
                ->get()
                ->groupBy($cityKey)
                ->each(function ($tours, $cityId) use (&$buckets, $cityRelation, $type) {
                    $city = $tours->first()->{$cityRelation};
                    if (! $city) {
                        return;
                    }

                    $key = $city->id;
                    $buckets[$key] ??= (object) [
                        'name' => $city->name,
                        'count' => 0,
                        'image' => null,
                        'type_slug' => $type->route_slug,
                        'city_id' => $city->id,
                    ];
                    $buckets[$key]->count += $tours->count();
                    $buckets[$key]->image ??= $tours->first(fn ($t) => $t->cover_image_url)?->cover_image_url;
                });
        }

        return collect($buckets)->sortByDesc('count')->take($limit)->values();
    }
}
