<?php

namespace App\Models\Reservation;

use App\Models\Agency\Agency;
use App\Models\Customer\Customer;
use App\Models\Product\Product;
use App\Models\Product\ProductType;
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;

class Reservation extends Model
{
     use HasFactory, SoftDeletes;

     protected $table = 'reservations';

     protected $fillable = [
          'agency_id',
          'customer_id',
          'product_type_id',
          'product_id',
          'reservable_type',
          'reservable_id',
          'created_by',
          'updated_by',
          'assigned_to',
          'confirmed_by',
          'cancelled_by',
          'reservation_code',
          'title',
          'start_date',
          'end_date',
          'pickup_time',
          'status',
          'payment_status',
          'adult_count',
          'child_count',
          'infant_count',
          'unit_price',
          'child_price',
          'infant_price',
          'subtotal',
          'discount_amount',
          'discount_rate',
          'discount_reason',
          'tax_amount',
          'total_amount',
          'paid_amount',
          'remaining_amount',
          'currency',
          'pickup_location',
          'dropoff_location',
          'flight_number',
          'flight_info',
          'extra_data',
          'participants',
          'customer_note',
          'internal_note',
          'cancellation_reason',
          'cancelled_at',
          'confirmed_at',
          'source',
          'reference_number',
          'rating',
     ];

     protected $casts = [
          'start_date' => 'date',
          'end_date' => 'date',
          'pickup_time' => 'datetime',
          'cancelled_at' => 'datetime',
          'confirmed_at' => 'datetime',
          'extra_data' => 'array',
          'participants' => 'array',
          'unit_price' => 'decimal:2',
          'child_price' => 'decimal:2',
          'infant_price' => 'decimal:2',
          'subtotal' => 'decimal:2',
          'discount_amount' => 'decimal:2',
          'discount_rate' => 'decimal:2',
          'tax_amount' => 'decimal:2',
          'total_amount' => 'decimal:2',
          'paid_amount' => 'decimal:2',
          'remaining_amount' => 'decimal:2',
     ];

     // ─── İLİŞKİLER ────────────────────────────────────────────────────────────

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

     public function customer()
     {
          return $this->belongsTo(Customer::class);
     }

     public function productType()
     {
          return $this->belongsTo(ProductType::class);
     }

     public function product()
     {
          return $this->belongsTo(Product::class);
     }

     /** Polymorphic: hangi ürün (Tour, DayTour, vb.) */
     public function reservable()
     {
          return $this->morphTo();
     }

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

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

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

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

     /** Bu rezervasyona katılan kayıtlı yolcular */
     public function passengers()
     {
          return $this->belongsToMany(\App\Models\CustomerPassenger::class, 'reservation_passengers', 'reservation_id', 'passenger_id')
               ->withPivot(['room_number', 'seat_number', 'special_request'])
               ->withTimestamps();
     }

     public function items()
     {
          return $this->hasMany(ReservationItem::class);
     }

     public function activities()
     {
          return $this->hasMany(ReservationActivity::class);
     }

     public function customFields()
     {
          return $this->hasMany(ReservationFieldValue::class);
     }

     // ─── SCOPE'LAR ────────────────────────────────────────────────────────────

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

     public function scopeByCustomer($query, int $customerId)
     {
          return $query->where('customer_id', $customerId);
     }

     public function scopeByStatus($query, string $status)
     {
          return $query->where('status', $status);
     }

     public function scopeByPaymentStatus($query, string $status)
     {
          return $query->where('payment_status', $status);
     }

     public function scopeByProductType($query, int $productTypeId)
     {
          return $query->where('product_type_id', $productTypeId);
     }

     public function scopeUpcoming($query)
     {
          return $query->where('start_date', '>=', today())
               ->whereNotIn('status', ['cancelled', 'refunded']);
     }

     public function scopePast($query)
     {
          return $query->where('start_date', '<', today());
     }

     public function scopeActive($query)
     {
          return $query->whereNotIn('status', ['cancelled', 'refunded']);
     }

     public function scopeByStage($query, string $stage)
     {
          return match($stage) {
               'potential' => $query->whereIn('status', ['potential', 'offer_sent', 'revised']),
               'won' => $query->whereIn('status', ['confirmed', 'in_progress', 'completed']),
               'lost' => $query->whereIn('status', ['cancelled', 'refunded']),
               default => $query->where('status', $stage)
          };
     }

     // ─── DURUM YARDIMCILARI ───────────────────────────────────────────────────

     public function isPotential(): bool
     {
          return in_array($this->status, ['potential', 'offer_sent', 'revised']);
     }

     /** Legacy helper for blade views */
     public function isPending(): bool
     {
          return $this->isPotential();
     }
     public function isWon(): bool
     {
          return in_array($this->status, ['confirmed', 'in_progress', 'completed']);
     }
     public function isConfirmed(): bool
     {
          return $this->status === 'confirmed';
     }
     public function isCompleted(): bool
     {
          return $this->status === 'completed';
     }
     public function isCancelled(): bool
     {
          return $this->status === 'cancelled';
     }
     public function isPaid(): bool
     {
          return $this->payment_status === 'paid';
     }

     public function confirm(): void
     {
          $this->update([
               'status' => 'confirmed',
               'confirmed_at' => now(),
               'confirmed_by' => auth()->id(),
          ]);
     }

     public function cancel(string $reason = ''): void
     {
          $this->update([
               'status' => 'cancelled',
               'cancellation_reason' => $reason,
               'cancelled_at' => now(),
               'cancelled_by' => auth()->id(),
          ]);
     }

     // ─── FİYAT HESAPLAMA ──────────────────────────────────────────────────────

     public function calculateTotals(): void
     {
          $unitPrice = (float) ($this->unit_price ?? 0);
          $childPrice = (float) ($this->child_price ?? $unitPrice * 0.5);
          $infantPr = (float) ($this->infant_price ?? 0);

          $subtotal = ($unitPrice * $this->adult_count)
               + ($childPrice * $this->child_count)
               + ($infantPr * $this->infant_count);

          $discountAmount = $this->discount_rate > 0
               ? $subtotal * ($this->discount_rate / 100)
               : (float) ($this->discount_amount ?? 0);

          $total = $subtotal - $discountAmount + (float) ($this->tax_amount ?? 0);

          $this->update([
               'subtotal' => number_format($subtotal, 2, '.', ''),
               'discount_amount' => number_format($discountAmount, 2, '.', ''),
               'total_amount' => number_format(max(0.0, $total), 2, '.', ''),
               'remaining_amount' => number_format(max(0.0, $total - (float) ($this->paid_amount ?? 0)), 2, '.', ''),
          ]);
     }

     // ─── DISPLAY ATTRİBUTE'LAR ────────────────────────────────────────────────

    public function getStatusLabelAttribute(): string
    {
        return self::getStatusLabel($this->status);
    }

    public static function getStatusLabel(string $status): string
    {
        return [
            'potential' => 'Potansiyel',
            'offer_sent' => 'Teklif Verildi',
            'revised' => 'Revize Edildi',
            'confirmed' => 'Satış Tamamlandı',
            'in_progress' => 'Devam Ediyor',
            'completed' => 'Kapanan',
            'cancelled' => 'İptal Edildi',
            'refunded' => 'İade Edildi',
        ][$status] ?? ucfirst($status);
    }

     public function getStatusColorAttribute(): string
     {
          return [
               'potential' => '#64748b',
               'offer_sent' => '#3b82f6',
               'revised' => '#8b5cf6',
               'confirmed' => '#10b981',
               'in_progress' => '#0ea5e9',
               'completed' => '#22c55e',
               'cancelled' => '#ef4444',
               'refunded' => '#f97316',
          ][$this->status] ?? '#94a3b8';
     }

     public function getPaymentStatusLabelAttribute(): string
     {
          return [
               'unpaid' => 'Ödenmedi',
               'partial' => 'Kısmi Ödendi',
               'paid' => 'Ödendi',
               'refunded' => 'İade Edildi',
          ][$this->payment_status] ?? ucfirst($this->payment_status);
     }

     public function getTotalParticipantsAttribute(): int
     {
          return $this->adult_count + $this->child_count + $this->infant_count;
     }

     /**
      * Ürün tipine göre formd alanlarını döndür (dinamik form sistemi için)
      * Buraya yeni ürün tipi eklendikçe genişletilebilir.
      */
     public static function extraFieldsFor(string $productTypeCode): array
     {
          return match ($productTypeCode) {
               'kultur-turu' => [
                    ['key' => 'room_type', 'label' => 'Oda Tipi', 'type' => 'select', 'options' => ['single' => 'Tek Kişilik', 'double' => 'Çift Kişilik', 'triple' => '3 Kişilik']],
                    ['key' => 'board_type', 'label' => 'Pansiyon', 'type' => 'select', 'options' => ['bb' => 'Oda & Kahvaltı', 'hb' => 'Yarım Pansiyon', 'fb' => 'Tam Pansiyon', 'ai' => 'Her Şey Dahil']],
                    ['key' => 'departure_point', 'label' => 'Kalkış Noktası', 'type' => 'text'],
               ],
               'gunubirlik-tur' => [
                    ['key' => 'departure_point', 'label' => 'Kalkış Noktası', 'type' => 'text'],
                    ['key' => 'return_point', 'label' => 'Dönüş Noktası', 'type' => 'text'],
                    ['key' => 'meal_included', 'label' => 'Yemek Dahil', 'type' => 'boolean'],
               ],
               'transfer' => [
                    ['key' => 'service_type', 'label' => 'Hizmet Tipi', 'type' => 'select', 'options' => ['airport' => 'Havalimanı', 'hotel' => 'Otel', 'port' => 'Liman', 'private' => 'Özel']],
                    ['key' => 'vehicle_type', 'label' => 'Araç Tipi', 'type' => 'select', 'options' => ['sedan' => 'Sedan', 'van' => 'Van', 'minibus' => 'Minibüs', 'bus' => 'Otobüs']],
                    ['key' => 'flight_number', 'label' => 'Uçuş No', 'type' => 'text'],
               ],
               'arac-kiralama', 'rent-a-car' => [
                    ['key' => 'car_class', 'label' => 'Araç Sınıfı', 'type' => 'select', 'options' => ['economy' => 'Ekonomi', 'compact' => 'Compact', 'suv' => 'SUV', 'premium' => 'Premium']],
                    ['key' => 'driver_age', 'label' => 'Sürücü Yaşı', 'type' => 'number'],
                    ['key' => 'extra_driver', 'label' => 'Ek Sürücü', 'type' => 'boolean'],
                    ['key' => 'gps', 'label' => 'GPS', 'type' => 'boolean'],
                    ['key' => 'child_seat', 'label' => 'Çocuk Koltuğu', 'type' => 'boolean'],
                    ['key' => 'full_insurance', 'label' => 'Tam Kasko', 'type' => 'boolean'],
               ],
               'tekne-turu' => [
                    ['key' => 'boat_type', 'label' => 'Tekne Tipi', 'type' => 'select', 'options' => ['yacht' => 'Yat', 'catamaran' => 'Katamaran', 'speedboat' => 'Hız Teknesi', 'gulet' => 'Gulet']],
                    ['key' => 'cabin_count', 'label' => 'Kabin Sayısı', 'type' => 'number'],
                    ['key' => 'meal_plan', 'label' => 'Yemek Planı', 'type' => 'text'],
               ],
               default => [],
          };
     }

     // ─── BOOT ──────────────────────────────────────────────────────────────────

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

          static::creating(function (Reservation $r) {
               if (empty($r->reservation_code)) {
                    $r->reservation_code = 'RES-' . strtoupper(substr(uniqid(), -6)) . '-' . date('ymd');
               }
               if (auth()->check()) {
                    $r->created_by = auth()->id();
                    $r->agency_id = $r->agency_id ?? auth()->user()->agency_id;
               }
          });

          static::updated(function (Reservation $r) {
               if (auth()->check()) {
                    $r->updated_by = auth()->id();
               }
               // Kalan tutarı otomatik güncelle
               $r->remaining_amount = (string) (max(0, (float) $r->total_amount - (float) $r->paid_amount));
          });

          static::created(function (Reservation $r) {
               $r->updateCustomerStats();
          });

          static::updated(function (Reservation $r) {
               // Durum veya tutar değiştiyse istatistikleri güncelle
               if ($r->isDirty(['status', 'total_amount', 'customer_id'])) {
                    $r->updateCustomerStats();

                    // Eğer müşteri değiştiyse eski müşteriyi de güncelle
                    if ($r->isDirty('customer_id')) {
                         $oldCustomerId = $r->getOriginal('customer_id');
                         if ($oldCustomerId) {
                              $oldCustomer = Customer::find($oldCustomerId);
                              if ($oldCustomer) {
                                   $r->recalculateCustomerStats($oldCustomer);
                              }
                         }
                    }
               }
          });

          static::deleted(function (Reservation $r) {
               $r->updateCustomerStats();
          });
     }

     /**
      * Müşteri istatistiklerini (harcama, rezervasyon sayısı) günceller.
      */
     public function updateCustomerStats(): void
     {
          $customer = $this->customer;
          if (!$customer)
               return;

          // Bu müşterinin tüm aktif (iptal edilmemiş) rezervasyonlarını al
          $stats = Reservation::where('customer_id', $customer->id)
               ->whereNotIn('status', ['cancelled', 'refunded'])
               ->selectRaw('COUNT(*) as total_count, SUM(total_amount) as total_spent, MIN(start_date) as first_date, MAX(start_date) as last_date')
               ->first();

          $totalBookings = (int) ($stats->total_count ?? 0);
          $totalSpent = (float) ($stats->total_spent ?? 0);
          $avgValue = $totalBookings > 0 ? $totalSpent / $totalBookings : 0;

          // Harcamalara göre sadakat puanı hesapla (her 100 birim harcama = 10 puan)
          $loyaltyPoints = (int) floor($totalSpent / 100) * 10;

          $customer->update([
               'total_bookings' => $totalBookings,
               'total_spent' => $totalSpent,
               'average_booking_value' => $avgValue,
               'lifetime_value' => $totalSpent,
               'first_booking_date' => $stats->first_date,
               'last_booking_date' => $stats->last_date,
               'loyalty_points' => $loyaltyPoints,
          ]);
     }

     /**
      * Belirli bir müşteri için tüm istatistikleri sıfırdan hesaplar.
      */
     protected function recalculateCustomerStats(Customer $customer): void
     {
          $stats = Reservation::where('customer_id', $customer->id)
               ->whereNotIn('status', ['cancelled', 'refunded'])
               ->selectRaw('COUNT(*) as total_count, SUM(total_amount) as total_spent, MIN(start_date) as first_date, MAX(start_date) as last_date')
               ->first();

          $totalBookings = (int) ($stats->total_count ?? 0);
          $totalSpent = (float) ($stats->total_spent ?? 0);

          $customer->update([
               'total_bookings' => $totalBookings,
               'total_spent' => $totalSpent,
               'average_booking_value' => $totalBookings > 0 ? $totalSpent / $totalBookings : 0,
               'lifetime_value' => $totalSpent,
               'first_booking_date' => $stats->first_date,
               'last_booking_date' => $stats->last_date,
          ]);
     }
}
