<?php

namespace App\Models\Tour;

use App\Models\Agency\Agency;
use App\Models\Definition\City;
use App\Models\User;
use App\Traits\SyncsProductState;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Str;

class Tour extends Model
{
    use HasFactory, SoftDeletes, SyncsProductState;

    protected $table = 'cultural_tours';

    protected $fillable = [
        'product_id',
        'agency_id',
        'code',
        'name',
        'slug',
        'description',
        'short_description',
        'places_to_visit',
        'inclusions',
        'exclusions',
        'cancellation_policy',
        'terms_conditions',
        'video_url',
        'documents',
        'tour_type',
        'pricing_type',
        'transportation_type',
        'transportation_method',
        'departure_airports',
        'departure_flight_number',
        'flight_departure_time',
        'arrival_airports',
        'arrival_flight_number',
        'flight_arrival_time',
        'has_transfer_points',
        'transportation_notes',
        'has_guide',
        'languages',
        'duration',
        'days',
        'nights',
        'departure_time',
        'return_time',
        'departure_city_id',
        'arrival_city_id',
        'destinations',
        'distance_km',
        'departure_latitude',
        'departure_longitude',
        'arrival_latitude',
        'arrival_longitude',
        'min_participants',
        'max_participants',
        'use_pricing_classes',
        'pricing_class_group_id',
        'class_capacities',
        'min_age',
        'max_age',
        'child_min_age',
        'child_max_age',
        'infant_min_age',
        'infant_max_age',
        'child_friendly',
        'infant_allowed',
        'difficulty_level',
        'difficulty_description',
        'fitness_level',
        'requirements',
        'instant_booking',
        'booking_deadline_hours',
        'cancellation_deadline_hours',
        'refundable',
        'meta_title',
        'meta_description',
        'meta_keywords',
        'tags',
        'is_featured',
        'is_bestseller',
        'is_new',
        'priority',
        'is_active',
        'is_public',
        'is_bookable',
        'is_draft',
        'published_at',
        'expires_at',
        'view_count',
        'booking_count',
        'wishlist_count',
        'rating_average',
        'rating_count',
        'external_ids',
        'api_data',
        'payment_plan',
        'payment_plan_enabled',
        'online_payment_enabled',
        'online_deposit_percent',
        'auto_guarantee_on_min',
        'created_by',
        'updated_by',
    ];

    protected function casts(): array
    {
        return [
            'documents' => 'array',
            'languages' => 'array',
            'destinations' => 'array',
            'requirements' => 'array',
            'tags' => 'array',
            'external_ids' => 'array',
            'api_data' => 'array',
            'class_capacities' => 'array',
            'use_pricing_classes' => 'boolean',
            'payment_plan' => 'array',
            'payment_plan_enabled' => 'boolean',
            'online_payment_enabled' => 'boolean',
            'online_deposit_percent' => 'decimal:2',
            'auto_guarantee_on_min' => 'boolean',
            'has_guide' => 'boolean',
            'has_transfer_points' => 'boolean',
            'child_friendly' => 'boolean',
            'infant_allowed' => 'boolean',
            'instant_booking' => 'boolean',
            'refundable' => 'boolean',
            'is_featured' => 'boolean',
            'is_bestseller' => 'boolean',
            'is_new' => 'boolean',
            'is_active' => 'boolean',
            'is_public' => 'boolean',
            'is_bookable' => 'boolean',
            'is_draft' => 'boolean',
            'published_at' => 'datetime',
            'expires_at' => 'datetime',
            'departure_time' => 'datetime',
            'return_time' => 'datetime',
            'distance_km' => 'decimal:2',
            'departure_latitude' => 'decimal:8',
            'departure_longitude' => 'decimal:8',
            'arrival_latitude' => 'decimal:8',
            'arrival_longitude' => 'decimal:8',
            'rating_average' => 'decimal:2',
        ];
    }

    // Basic Relationships
    public function agency()
    {
        return $this->belongsTo(Agency::class);
    }

    public function product()
    {
        return $this->belongsTo(\App\Models\Product\Product::class, 'product_id');
    }

    public function departureCity()
    {
        return $this->belongsTo(City::class, 'departure_city_id');
    }

    public function arrivalCity()
    {
        return $this->belongsTo(City::class, 'arrival_city_id');
    }

    public function creator()
    {
        return $this->belongsTo(User::class, 'created_by');
    }

    public function updater()
    {
        return $this->belongsTo(User::class, 'updated_by');
    }

    // Tour Categories relationship (Many-to-Many through product_category via Product)
    // Pivot'un product_id'si products.id'ye FK'lı; bu yüzden parent key tours.id DEĞİL tours.product_id olmalı.
    // (Aksi halde sorgu product_category.product_id = tours.id ile eşleşmeye çalışır ve boş döner.)
    public function categories()
    {
        return $this->belongsToMany(
            \App\Models\Product\ProductCategory::class,
            'product_category',
            'product_id',
            'category_id',
            'product_id', // parentKey
            'id'          // relatedKey
        );
    }

    // Tour Images relationships
    public function tourImages()
    {
        return $this->hasMany(TourImage::class, 'cultural_tour_id')->ordered();
    }

    public function activeTourImages()
    {
        return $this->hasMany(TourImage::class, 'cultural_tour_id')->active()->approved()->ordered();
    }

    public function coverImage()
    {
        return $this->hasOne(TourImage::class, 'cultural_tour_id')->cover()->active();
    }

    public function featuredImages()
    {
        return $this->hasMany(TourImage::class, 'cultural_tour_id')->featured()->active()->ordered();
    }

    public function galleryImages()
    {
        return $this->hasMany(TourImage::class, 'cultural_tour_id')->forGallery()->active()->ordered();
    }

    public function sliderImages()
    {
        return $this->hasMany(TourImage::class, 'cultural_tour_id')->forSlider()->active()->ordered();
    }

    public function thumbnailImages()
    {
        return $this->hasMany(TourImage::class, 'cultural_tour_id')->forThumbnails()->active()->ordered();
    }

    public function itineraryImages()
    {
        return $this->hasMany(TourImage::class, 'cultural_tour_id')->bySection('itinerary')->active()->ordered();
    }

    // Tour Itineraries relationship
    public function itineraries()
    {
        return $this->hasMany(TourItinerary::class, 'cultural_tour_id')->ordered();
    }

    public function activeItineraries()
    {
        return $this->hasMany(TourItinerary::class, 'cultural_tour_id')->active()->ordered();
    }

    // Tour Transfer Points relationship
    public function transferPoints()
    {
        return $this->hasMany(TourTransferPoint::class, 'cultural_tour_id')->orderBy('sort_order');
    }

    public function activeTransferPoints()
    {
        return $this->hasMany(TourTransferPoint::class, 'cultural_tour_id')->active()->orderBy('sort_order');
    }

    public function departurePoints()
    {
        return $this->hasMany(TourTransferPoint::class, 'cultural_tour_id')->departurePoints();
    }

    public function transferStops()
    {
        return $this->hasMany(TourTransferPoint::class, 'cultural_tour_id')->transferPoints();
    }

    public function getItinerariesByDay($dayNumber)
    {
        return $this->itineraries()->byDay($dayNumber)->get();
    }

    public function getItineraryDays()
    {
        return $this->itineraries()->select('day_number')->distinct()->orderBy('day_number')->pluck('day_number');
    }

    // Fiyatlar artık tarihler (tourDates) üzerinde tutulur.
    public function getPricingForDate($date)
    {
        // O tarihte aktif bir TourDate varsa onun fiyatını kullan
        return $this->tourDates()
            ->where('start_date', '<=', $date)
            ->where('end_date', '>=', $date)
            ->where('is_active', true)
            ->first();
    }

    public function tourDates()
    {
        return $this->hasMany(TourDate::class, 'cultural_tour_id')->orderBy('start_date');
    }

    public function upcomingDates()
    {
        return $this->hasMany(TourDate::class, 'cultural_tour_id')->upcoming()->available();
    }

    /**
     * Ana fiyat: en yakın (gelecek, satılabilir) tarihin ANA PAZAR yetişkin fiyatı.
     * Gelecek tarih yoksa bugüne en yakın geçmiş tarihe düşer. Ana pazar fiyat satırı
     * yoksa tarihin temsili adult_price kolonuna düşer.
     *
     * @return array{price: float, currency: string, start_date: ?\Carbon\Carbon}|null
     */
    public function getPrimaryPriceInfo(): ?array
    {
        $date = $this->upcomingDates()->orderBy('start_date')->with('marketplacePrices')->first()
            ?? $this->tourDates()->orderByDesc('start_date')->with('marketplacePrices')->first();
        if (!$date) {
            return null;
        }

        $price = null;
        $cur = null;
        $pmId = $this->product?->primary_marketplace_id;
        if ($pmId) {
            $rows = $date->marketplacePrices->where('marketplace_id', $pmId);
            // Sınıfsız satır öncelikli; sınıflı modda en düşük (taban) satıra düş
            $row = $rows->firstWhere('tour_class_id', null) ?? $rows->sortBy(fn ($r) => (float) $r->adult_price)->first();
            if ($row && $row->adult_price !== null) {
                $price = (float) $row->adult_price;
                $cur = $row->currency;
            }
        }
        if ($price === null && $date->adult_price !== null) {
            $price = (float) $date->adult_price;
            $cur = $date->currency;
        }
        if ($price === null) {
            return null;
        }

        return [
            'price' => $price,
            'currency' => $cur ?: 'TRY',
            'start_date' => $date->start_date ? \Carbon\Carbon::parse($date->start_date) : null,
        ];
    }

    // En düşük / en yüksek yetişkin fiyatı — pazaryeri fiyat matrisinden (ana pazar öncelikli)
    private function marketplacePriceAggregate(string $fn, bool $onlyUpcoming = true)
    {
        $idsQuery = $this->tourDates()->where('is_active', true);
        if ($onlyUpcoming) {
            $idsQuery->where('start_date', '>=', now()->toDateString());
        }
        $ids = $idsQuery->pluck('id');
        if ($ids->isEmpty() && $onlyUpcoming) {
            $ids = $this->tourDates()->pluck('id'); // gelecek tarih yoksa tüm tarihlere düş
        }
        if ($ids->isEmpty()) {
            return 0;
        }

        $q = \App\Models\TourDateMarketplacePrice::where('priceable_type', TourDate::class)
            ->whereIn('priceable_id', $ids)
            ->whereNotNull('adult_price');

        $pmId = $this->product?->primary_marketplace_id;
        $val = $pmId ? (clone $q)->where('marketplace_id', $pmId)->{$fn}('adult_price') : null;

        return (float) ($val ?? $q->{$fn}('adult_price') ?? 0);
    }

    public function getLowestPrice()
    {
        return $this->marketplacePriceAggregate('min');
    }

    public function getHighestPrice()
    {
        return $this->marketplacePriceAggregate('max');
    }

    // "…'dan başlayan fiyat" — liste/kart gösterimleri için
    public function getStartingPriceAttribute()
    {
        return $this->getLowestPrice();
    }

    /**
     * Bir tarih için geçerli kademeli ödeme planını döndürür.
     * Tarih kendi özel planını kullanıyorsa onu, aksi halde tur planını verir.
     * (Şimdilik yalnızca konfigürasyon; tahsilat mantığı ileride bağlanacak.)
     */
    public function getEffectivePaymentPlan($date = null)
    {
        if ($date && $date->use_custom_payment_plan && !empty($date->payment_schedule)) {
            return $date->payment_schedule;
        }

        return $this->payment_plan_enabled ? ($this->payment_plan ?: []) : [];
    }

    /**
     * Benzersiz slug oluşturur. Aynı slug varsa sonuna -2, -3 gibi sayı ekler.
     * Soft-delete edilmiş kayıtlar da unique index'te yer tuttuğu için withTrashed ile aranır.
     */
    public static function generateUniqueSlug(string $name, ?int $excludeId = null): string
    {
        $originalSlug = Str::slug($name) ?: 'tur';
        $slug = $originalSlug;
        $counter = 2;

        while (static::withTrashed()
            ->where('slug', $slug)
            ->when($excludeId, fn ($q) => $q->where('id', '!=', $excludeId))
            ->exists()
        ) {
            $slug = $originalSlug . '-' . $counter++;
        }

        return $slug;
    }

    // Scopes
    public function scopeActive($query)
    {
        return $query->where('is_active', true);
    }

    public function scopePublic($query)
    {
        return $query->where('is_public', true);
    }

    public function scopeBookable($query)
    {
        return $query->where('is_bookable', true);
    }

    public function scopeDraft($query)
    {
        return $query->where('is_draft', true);
    }

    public function scopeNotDraft($query)
    {
        return $query->where('is_draft', false);
    }

    public function scopeFeatured($query)
    {
        return $query->where('is_featured', true);
    }

    public function scopeBestseller($query)
    {
        return $query->where('is_bestseller', true);
    }

    public function scopeNew($query)
    {
        return $query->where('is_new', true);
    }

    public function scopeByAgency($query, $agencyId)
    {
        return $query->where('agency_id', $agencyId);
    }

    public function scopeByTourType($query, $type)
    {
        return $query->where('tour_type', $type);
    }

    public function scopeByDepartureCity($query, $cityId)
    {
        return $query->where('departure_city_id', $cityId);
    }

    public function scopeByDuration($query, $min, $max)
    {
        return $query->whereBetween('duration', [$min, $max]);
    }

    // Helper Methods
    public function isExpired()
    {
        return $this->expires_at && $this->expires_at->isPast();
    }

    public function isPublished()
    {
        return $this->published_at && $this->published_at->isPast();
    }

    public function isAvailable()
    {
        return $this->is_active && $this->is_public && $this->is_bookable && !$this->isExpired();
    }

    public function getFormattedPriceAttribute()
    {
        $lowest = $this->getLowestPrice();
        if ($lowest > 0) {
            return number_format($lowest, 2) . ' ' . $this->currency;
        }
        return 'Fiyat Belirtilmemiş';
    }

    public function getDiscountedPriceAttribute()
    {
        // Bu method daha sonra promosyon sistemi eklendiğinde genişletilebilir
        return $this->getLowestPrice();
    }

    public function getCurrencyAttribute()
    {
        // Para birimi artık tarihlerde tutulur; en yakın aktif tarihten alınır
        return optional(
            $this->tourDates()
                ->where('is_active', true)
                ->whereNotNull('currency')
                ->orderBy('start_date')
                ->first()
        )->currency ?: 'TRY';
    }

    // Tour Image helper methods
    public function getCoverImageUrlAttribute()
    {
        return $this->coverImage?->image_url;
    }

    public function getThumbnailUrlAttribute()
    {
        return $this->coverImage?->thumbnail_url ?: $this->featuredImages->first()?->thumbnail_url;
    }

    public function getGalleryImageUrlsAttribute()
    {
        return $this->galleryImages->pluck('image_url')->toArray();
    }

    public function hasImages()
    {
        return $this->activeTourImages()->count() > 0;
    }

    public function getImageCount()
    {
        return $this->activeTourImages()->count();
    }

    public function addImageFromDisk($diskItemId, array $attributes = [])
    {
        $defaultAttributes = [
            'disk_item_id' => $diskItemId,
            'image_type' => 'gallery',
            'sort_order' => $this->tourImages()->count(),
            'is_active' => true,
            'is_approved' => true,
            'approved_at' => now(),
            'approved_by' => auth()->id(),
        ];

        return $this->tourImages()->create(array_merge($defaultAttributes, $attributes));
    }

    // Backward compatibility alias
    public function addImageFromGallery($diskItemId, array $attributes = [])
    {
        return $this->addImageFromDisk($diskItemId, $attributes);
    }

    public function setCoverImage($diskItemId)
    {
        return $this->addImageFromDisk($diskItemId, [
            'image_type' => 'cover',
            'is_cover' => true,
            'show_in_gallery' => true,
            'show_in_slider' => true,
        ]);
    }

    public function addFeaturedImage($diskItemId)
    {
        return $this->addImageFromDisk($diskItemId, [
            'image_type' => 'featured',
            'is_featured' => true,
            'show_in_gallery' => true,
            'show_in_slider' => true,
        ]);
    }

    // Tour Status Methods
    public function getTourTypeDisplayNameAttribute()
    {
        // Etiketler uygulamanın geri kalanıyla aynı olmalı (form select'leri,
        // filtreler, günübirlik tur): "Yurt İçi" / "Yurt Dışı".
        $types = [
            'domestic' => 'Yurt İçi',
            'international' => 'Yurt Dışı',
        ];

        return $types[$this->tour_type] ?? ucfirst($this->tour_type);
    }

    public function getAccommodationTypeDisplayNameAttribute()
    {
        // Kültür turları her zaman konaklamalıdır
        return 'Konaklamalı';
    }

    public function getDifficultyLevelDisplayNameAttribute()
    {
        $levels = [
            'easy' => 'Kolay',
            'moderate' => 'Orta',
            'challenging' => 'Zor',
            'extreme' => 'Çok Zor',
        ];

        return $levels[$this->difficulty_level] ?? ucfirst($this->difficulty_level);
    }

    protected static function boot()
    {
        parent::boot();

        static::creating(function ($tour) {
            if (empty($tour->slug)) {
                $tour->slug = static::generateUniqueSlug((string) $tour->name);
            }

            if (empty($tour->code)) {
                // Tur no: acente içinde 1'den başlayan düz sıra numarası
                $tour->code = \App\Support\SequentialCode::next(
                    static::withTrashed()->where('agency_id', $tour->agency_id)
                );
            }

            if (auth()->check()) {
                $tour->created_by = auth()->id();
            }
        });

        static::updating(function ($tour) {
            if (auth()->check()) {
                $tour->updated_by = auth()->id();
            }
        });
    }
}
