<?php

namespace Database\Seeders;

use App\Models\Agency\Agency;
use App\Models\Customer\Customer;
use App\Models\DayTour\DayTour;
use App\Models\DayTour\DayTourDate;
use App\Models\InternationalTour\InternationalTour;
use App\Models\InternationalTour\InternationalTourDate;
use App\Models\Product\Product;
use App\Models\Sale\Sale;
use App\Models\Tour\Tour;
use App\Models\Tour\TourDate;
use App\Services\Operation\DepartureInventoryService;
use App\Services\Operation\OperationService;
use Carbon\Carbon;
use Illuminate\Database\Seeder;
use Illuminate\Support\Str;

class SaleSeeder extends Seeder
{
    /** productable_type => [dateClass, foreignKey] */
    private array $typeMap = [
        Tour::class => [TourDate::class, 'cultural_tour_id'],
        InternationalTour::class => [InternationalTourDate::class, 'international_tour_id'],
        DayTour::class => [DayTourDate::class, 'day_tour_id'],
    ];

    public function run(): void
    {
        $agency = Agency::first();
        if (!$agency) {
            return;
        }

        $customers = Customer::where('agency_id', $agency->id)
            ->where('customer_type', 'individual')
            ->get();
        if ($customers->isEmpty()) {
            return;
        }

        $performerId = \App\Models\User::byAgency($agency->id)->first()?->id;

        // ── Önceki (bağsız) satışları ve operasyon kayıtlarını temizle ─────────
        $this->cleanup($agency->id);

        // ── Gerçek kalkışları (tur tarihlerini) topla ──────────────────────────
        $departures = $this->collectDepartures($agency->id);
        if (empty($departures)) {
            $this->command->warn('Rezervasyon bağlanacak tur tarihi bulunamadı. Önce tur seederlarını çalıştırın.');
            return;
        }

        $inventory = app(DepartureInventoryService::class);
        $operations = app(OperationService::class);
        $affected = [];      // key => date model (recount/evaluate için)
        $totalSales = 0;

        foreach ($departures as $dep) {
            // Her kalkışa 1-3 rezervasyon
            $saleCount = rand(1, 3);

            for ($s = 0; $s < $saleCount; $s++) {
                $customer = $customers->random();
                $adults = rand(1, 3);
                $children = rand(0, 2);

                $status = $this->weightedStatus();

                $adultPrice = (float) ($dep['adult_price'] ?: 1000);
                $childPrice = (float) ($dep['child_price'] ?: $adultPrice * 0.7);
                $subtotal = ($adultPrice * $adults) + ($childPrice * $children);
                $taxAmount = round($subtotal * 0.20, 2);
                $total = $subtotal + $taxAmount;
                $paid = $status === 'confirmed' || $status === 'in_progress'
                    ? (rand(0, 1) ? $total : round($total / 2, 2))
                    : 0;

                $sale = Sale::create([
                    'agency_id' => $agency->id,
                    'customer_id' => $customer->id,
                    'product_type_id' => $dep['product']->product_type_id,
                    'product_id' => $dep['product']->id,
                    'reservable_type' => $dep['product']->productable_type,
                    'reservable_id' => $dep['product']->productable_id,
                    'tour_date_type' => $dep['date_class'],
                    'tour_date_id' => $dep['date']->id,
                    'created_by' => $performerId,
                    // sale_code boş bırakılır — model hook'u acente içinde 1'den başlayan sıra no atar
                    'title' => $dep['product']->name . ' — ' . $customer->last_name,
                    'start_date' => $dep['start'],
                    'end_date' => $dep['end'],
                    'status' => $status,
                    'payment_status' => $paid >= $total ? 'paid' : ($paid > 0 ? 'partial' : 'unpaid'),
                    'adult_count' => $adults,
                    'child_count' => $children,
                    'infant_count' => 0,
                    'unit_price' => $adultPrice,
                    'child_price' => $childPrice,
                    'subtotal' => $subtotal,
                    'tax_amount' => $taxAmount,
                    'total_amount' => $total,
                    'paid_amount' => $paid,
                    'remaining_amount' => max(0, $total - $paid),
                    'currency' => $dep['currency'] ?: 'TRY',
                    'source' => collect(['website', 'phone', 'walk_in', 'agency'])->random(),
                    'created_at' => Carbon::now()->subDays(rand(1, 20)),
                ]);

                // Ana hizmet kalemi
                $qty = $adults + $children;
                $sale->items()->create([
                    'product_id' => $dep['product']->id,
                    'product_type_id' => $dep['product']->product_type_id,
                    'name' => $dep['product']->name . ' (Ana Hizmet)',
                    'quantity' => $qty,
                    'unit_price' => $adultPrice,
                    'tax_rate' => 20.0,
                    'tax_amount' => round($qty * $adultPrice * 0.20, 2),
                    'total_price' => round($qty * $adultPrice * 1.20, 2),
                    'currency' => $dep['currency'] ?: 'TRY',
                ]);

                $sale->calculateTotals();

                // Aktivite
                $sale->activities()->create([
                    'agency_id' => $agency->id,
                    'performed_by' => $performerId,
                    'activity_type' => 'status_change',
                    'subject' => 'Rezervasyon Oluşturuldu',
                    'description' => "'{$dep['product']->name}' kalkışına rezervasyon alındı ({$dep['start']->format('d.m.Y')}).",
                    'created_at' => $sale->created_at,
                ]);

                // Yolcuları ilişkilendir
                $this->attachPassengers($sale, $customer, $qty);

                $totalSales++;
            }

            $affected[$dep['date_class'] . ':' . $dep['date']->id] = $dep['date'];
        }

        // ── Envanteri yeniden say + operasyon durumunu değerlendir ────────────
        foreach ($affected as $date) {
            $inventory->recount($date);
            $operations->evaluate($date);
        }

        // ── Vitrin için birkaç durum: manuel kesin kalkış + bir iptal ─────────
        $this->showcaseStates($affected, $operations, $performerId);

        $this->command->info("{$totalSales} rezervasyon " . count($affected) . ' kalkışa bağlandı ve operasyona işlendi.');
    }

    /**
     * Önceki satışları (ve bağlı kalemler/aktiviteler/yolcu bağlarını) ve
     * operasyon kayıtlarını temizler; böylece seeder tekrar çalıştırılınca
     * temiz, kalkışa bağlı veri üretilir.
     */
    private function cleanup(int $agencyId): void
    {
        $sales = Sale::withTrashed()->where('agency_id', $agencyId)->get();
        foreach ($sales as $sale) {
            $sale->items()->delete();
            $sale->activities()->delete();
            $sale->passengers()->detach();
            $sale->forceDelete();
        }

        \App\Models\Operation\TourOperation::where('agency_id', $agencyId)->forceDelete();
    }

    /**
     * Acentenin ürünlerine ait yaklaşan, satışa açık tarihleri normalize eder.
     */
    private function collectDepartures(int $agencyId): array
    {
        $products = Product::where('agency_id', $agencyId)->get();
        $departures = [];

        foreach ($products as $product) {
            $map = $this->typeMap[$product->productable_type] ?? null;
            if (!$map) {
                continue;
            }
            [$dateClass, $fk] = $map;
            $dateCol = $dateClass === DayTourDate::class ? 'tour_date' : 'start_date';

            $dates = $dateClass::where($fk, $product->productable_id)
                ->where('is_active', true)
                ->where($dateCol, '>=', now()->toDateString())
                ->orderBy($dateCol)
                ->get();

            foreach ($dates as $date) {
                $isDayTour = $date instanceof DayTourDate;
                $start = Carbon::parse($isDayTour ? $date->tour_date : $date->start_date);
                $end = $isDayTour ? $start->copy() : Carbon::parse($date->end_date ?? $date->start_date);

                // Kültür/yurt dışı tarihlerinde fiyat kolonları kaldırıldı — tek kaynak
                // pazaryeri fiyat matrisi; günübirlik tarihler kendi kolonlarını korur.
                $matrixPrice = $isDayTour ? null : $date->marketplacePrices()->first();

                $departures[] = [
                    'product' => $product,
                    'date' => $date,
                    'date_class' => $dateClass,
                    'start' => $start,
                    'end' => $end,
                    'adult_price' => $date->adult_price ?? $matrixPrice?->adult_price,
                    'child_price' => $date->child_price ?? $date->child_price_1 ?? $matrixPrice?->child_price_1 ?? null,
                    'currency' => $isDayTour ? 'TRY' : ($matrixPrice?->currency ?? $date->currency ?? 'TRY'),
                ];
            }
        }

        // Kültür + yurt dışının hepsini, günübirliğin bir kısmını al (pano çeşitliliği)
        $cultural = array_filter($departures, fn ($d) => $d['date_class'] !== DayTourDate::class);
        $day = array_filter($departures, fn ($d) => $d['date_class'] === DayTourDate::class);
        shuffle($day);

        return array_merge(array_values($cultural), array_slice(array_values($day), 0, 10));
    }

    /** Yaklaşan kalkışlar için gerçekçi, ağırlıklı satış durumu. */
    private function weightedStatus(): string
    {
        $r = rand(1, 100);
        return match (true) {
            $r <= 25 => 'potential',
            $r <= 50 => 'offer_sent',
            $r <= 60 => 'revised',
            $r <= 85 => 'confirmed',
            default => 'in_progress',
        };
    }

    private function attachPassengers(Sale $sale, Customer $customer, int $needed): void
    {
        $passengers = \App\Models\CustomerPassenger::where('customer_id', $customer->id)->get();

        if ($passengers->count() < $needed) {
            $faker = \Faker\Factory::create('tr_TR');
            for ($j = $passengers->count(); $j < $needed; $j++) {
                \App\Models\CustomerPassenger::create([
                    'customer_id' => $customer->id,
                    'first_name' => $faker->firstName,
                    'last_name' => $customer->last_name,
                    'gender' => $faker->randomElement(['male', 'female']),
                    'birth_date' => $faker->dateTimeBetween('-40 years', '-5 years')->format('Y-m-d'),
                    'relationship' => 'Diğer',
                ]);
            }
            $passengers = \App\Models\CustomerPassenger::where('customer_id', $customer->id)->get();
        }

        foreach ($passengers->take($needed) as $idx => $p) {
            $sale->passengers()->attach($p->id, [
                'seat_number' => rand(1, 45),
                'special_request' => $idx === 0 ? 'Vejetaryen yemek' : null,
            ]);
        }
    }

    /**
     * Panonun tüm rozet durumlarını göstermek için: bir kalkışı manuel kesin
     * kalkışa al, bir kalkışı da iptal et.
     */
    private function showcaseStates(array $affected, OperationService $operations, ?int $userId): void
    {
        $dates = array_values($affected);

        // İlk kültür/yurt dışı kalkışını manuel kesin kalkışa al
        foreach ($dates as $date) {
            if (($date instanceof TourDate || $date instanceof InternationalTourDate)) {
                $op = $operations->forDate($date, true);
                if ($op && $op->departure_status !== 'guaranteed') {
                    $operations->markGuaranteed($date, $op, 'manual', $userId);
                }
                break;
            }
        }

        // Son kalkışı iptal et (kırmızı rozet vitrin)
        $last = end($dates);
        if ($last) {
            $op = $operations->forDate($last, true);
            if ($op && !$op->isTerminal()) {
                $operations->cancelDeparture($last, $op, 'Yetersiz katılım (demo iptali).', $userId);
            }
        }
    }
}
