<?php

use App\Enums\OverrideScope;
use App\Models\DeliveryCalendarOverride;
use App\Models\DeliverySchedule;
use App\Models\ProfitCenter;
use App\Models\ProfitCenterSupplierSchedule;
use App\Models\Supplier;
use App\Models\WorkCalendar;
use App\Enums\WorkDayType;
use App\Enums\DataSource;
use App\Services\DeliveryCalendarService;
use Tests\TestCase;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Carbon;

uses(TestCase::class, RefreshDatabase::class);

it('returns true for a scheduled delivery day', function () {
    $pc = ProfitCenter::factory()->create();
    $supplier = Supplier::factory()->create();
    $schedule = DeliverySchedule::factory()->create([
        'monday' => true,
    ]);
    ProfitCenterSupplierSchedule::factory()->create([
        'profit_center_id' => $pc->id,
        'supplier_id' => $supplier->id,
        'delivery_schedule_id' => $schedule->id,
    ]);
    $service = app(DeliveryCalendarService::class);
    $monday = Carbon::parse('2026-04-13'); // Monday
    expect($service->isDeliveryDay($pc, $supplier, $monday))->toBeTrue();
});

it('returns false for a non-scheduled delivery day', function () {
    $pc = ProfitCenter::factory()->create();
    $supplier = Supplier::factory()->create();
    $schedule = DeliverySchedule::factory()->create([
        'monday' => true,
        'tuesday' => false,
    ]);
    ProfitCenterSupplierSchedule::factory()->create([
        'profit_center_id' => $pc->id,
        'supplier_id' => $supplier->id,
        'delivery_schedule_id' => $schedule->id,
    ]);
    $service = app(DeliveryCalendarService::class);
    $tuesday = Carbon::parse('2026-04-14'); // Tuesday
    expect($service->isDeliveryDay($pc, $supplier, $tuesday))->toBeFalse();
});

it('respects official holidays (WorkCalendar)', function () {
    $pc = ProfitCenter::factory()->create();
    $supplier = Supplier::factory()->create();
    $schedule = DeliverySchedule::factory()->create(['monday' => true]);
    ProfitCenterSupplierSchedule::factory()->create([
        'profit_center_id' => $pc->id,
        'supplier_id' => $supplier->id,
        'delivery_schedule_id' => $schedule->id,
    ]);
    $monday = Carbon::parse('2026-04-13'); // Monday
    // Mark this Monday as a holiday
    WorkCalendar::create([
        'date' => '2026-04-13',
        'type' => WorkDayType::Holiday,
        'data_source' => DataSource::Manual,
    ]);
    $service = app(DeliveryCalendarService::class);
    expect($service->isDeliveryDay($pc, $supplier, $monday))->toBeFalse();
});

it('respects general supplier override over holidays', function () {
    $pc = ProfitCenter::factory()->create();
    $supplier = Supplier::factory()->create();
    $schedule = DeliverySchedule::factory()->create(['monday' => true]);
    ProfitCenterSupplierSchedule::factory()->create([
        'profit_center_id' => $pc->id,
        'supplier_id' => $supplier->id,
        'delivery_schedule_id' => $schedule->id,
    ]);
    $monday = Carbon::parse('2026-04-13'); // Monday
    WorkCalendar::create([
        'date' => '2026-04-13',
        'type' => WorkDayType::Holiday,
        'data_source' => DataSource::Manual,
    ]);
    DeliveryCalendarOverride::create([
        'supplier_id' => $supplier->id,
        'override_scope' => OverrideScope::General->value,
        'date' => '2026-04-13',
        'is_delivery_day' => true,
    ]);
    $service = app(DeliveryCalendarService::class);
    expect($service->isDeliveryDay($pc, $supplier, $monday))->toBeTrue();
});

it('respects general supplier override to block delivery on a normal day', function () {
    $pc = ProfitCenter::factory()->create();
    $supplier = Supplier::factory()->create();
    $schedule = DeliverySchedule::factory()->create(['monday' => true]);
    ProfitCenterSupplierSchedule::factory()->create([
        'profit_center_id' => $pc->id,
        'supplier_id' => $supplier->id,
        'delivery_schedule_id' => $schedule->id,
    ]);
    $monday = Carbon::parse('2026-04-13'); // Monday
    DeliveryCalendarOverride::create([
        'supplier_id' => $supplier->id,
        'override_scope' => OverrideScope::General->value,
        'date' => '2026-04-13',
        'is_delivery_day' => false,
    ]);
    $service = app(DeliveryCalendarService::class);
    expect($service->isDeliveryDay($pc, $supplier, $monday))->toBeFalse();
});

it('respects delivery-schedule-specific override over general override', function () {
    $pc = ProfitCenter::factory()->create();
    $supplier = Supplier::factory()->create();
    $schedule = DeliverySchedule::factory()->create(['monday' => true]);
    ProfitCenterSupplierSchedule::factory()->create([
        'profit_center_id' => $pc->id,
        'supplier_id' => $supplier->id,
        'delivery_schedule_id' => $schedule->id,
    ]);
    $monday = Carbon::parse('2026-04-13');
    // Általános tiltás
    DeliveryCalendarOverride::create([
        'supplier_id' => $supplier->id,
        'override_scope' => OverrideScope::General->value,
        'date' => '2026-04-13',
        'is_delivery_day' => false,
    ]);
    // Szállítási sablon-specifikus engedélyezés
    DeliveryCalendarOverride::create([
        'supplier_id' => $supplier->id,
        'override_scope' => OverrideScope::Region->value,
        'delivery_schedule_id' => $schedule->id,
        'date' => '2026-04-13',
        'is_delivery_day' => true,
    ]);
    $service = app(DeliveryCalendarService::class);
    // A sablon-specifikus győz az általánossal szemben
    expect($service->isDeliveryDay($pc, $supplier, $monday))->toBeTrue();
});

it('delivery-schedule override does not affect profit centers with different schedule', function () {
    $supplier = Supplier::factory()->create();
    $scheduleA = DeliverySchedule::factory()->create(['monday' => true]);
    $scheduleB = DeliverySchedule::factory()->create(['monday' => true]);
    $pcA = ProfitCenter::factory()->create();
    $pcB = ProfitCenter::factory()->create();
    ProfitCenterSupplierSchedule::factory()->create([
        'profit_center_id' => $pcA->id,
        'supplier_id' => $supplier->id,
        'delivery_schedule_id' => $scheduleA->id,
    ]);
    ProfitCenterSupplierSchedule::factory()->create([
        'profit_center_id' => $pcB->id,
        'supplier_id' => $supplier->id,
        'delivery_schedule_id' => $scheduleB->id,
    ]);
    $monday = Carbon::parse('2026-04-13');
    // Csak az A sablont tiltjuk
    DeliveryCalendarOverride::create([
        'supplier_id' => $supplier->id,
        'override_scope' => OverrideScope::Region->value,
        'delivery_schedule_id' => $scheduleA->id,
        'date' => '2026-04-13',
        'is_delivery_day' => false,
    ]);
    $service = app(DeliveryCalendarService::class);
    expect($service->isDeliveryDay($pcA, $supplier, $monday))->toBeFalse();
    expect($service->isDeliveryDay($pcB, $supplier, $monday))->toBeTrue();
});

it('respects profit-center-specific override over region and general overrides', function () {
    $pc = ProfitCenter::factory()->create(['city' => 'Budapest']);
    $supplier = Supplier::factory()->create();
    $schedule = DeliverySchedule::factory()->create(['monday' => true]);
    ProfitCenterSupplierSchedule::factory()->create([
        'profit_center_id' => $pc->id,
        'supplier_id' => $supplier->id,
        'delivery_schedule_id' => $schedule->id,
    ]);
    $monday = Carbon::parse('2026-04-13');
    // Általános tiltás
    DeliveryCalendarOverride::create([
        'supplier_id' => $supplier->id,
        'override_scope' => OverrideScope::General->value,
        'date' => '2026-04-13',
        'is_delivery_day' => false,
    ]);
    // Sablon-specifikus tiltás is
    DeliveryCalendarOverride::create([
        'supplier_id' => $supplier->id,
        'override_scope' => OverrideScope::Region->value,
        'delivery_schedule_id' => $schedule->id,
        'date' => '2026-04-13',
        'is_delivery_day' => false,
    ]);
    // De erre a konkrét PC-re engedélyezve van
    DeliveryCalendarOverride::create([
        'supplier_id' => $supplier->id,
        'override_scope' => OverrideScope::ProfitCenter->value,
        'profit_center_id' => $pc->id,
        'date' => '2026-04-13',
        'is_delivery_day' => true,
    ]);
    $service = app(DeliveryCalendarService::class);
    expect($service->isDeliveryDay($pc, $supplier, $monday))->toBeTrue();
});

it('profit-center-specific override only affects the targeted profit center', function () {
    $pc1 = ProfitCenter::factory()->create(['city' => 'Budapest']);
    $pc2 = ProfitCenter::factory()->create(['city' => 'Budapest']);
    $supplier = Supplier::factory()->create();
    $schedule = DeliverySchedule::factory()->create(['monday' => true]);
    ProfitCenterSupplierSchedule::factory()->create([
        'profit_center_id' => $pc1->id,
        'supplier_id' => $supplier->id,
        'delivery_schedule_id' => $schedule->id,
    ]);
    ProfitCenterSupplierSchedule::factory()->create([
        'profit_center_id' => $pc2->id,
        'supplier_id' => $supplier->id,
        'delivery_schedule_id' => $schedule->id,
    ]);
    $monday = Carbon::parse('2026-04-13');
    // Csak pc1-re van tiltás
    DeliveryCalendarOverride::create([
        'supplier_id' => $supplier->id,
        'override_scope' => OverrideScope::ProfitCenter->value,
        'profit_center_id' => $pc1->id,
        'date' => '2026-04-13',
        'is_delivery_day' => false,
    ]);
    $service = app(DeliveryCalendarService::class);
    expect($service->isDeliveryDay($pc1, $supplier, $monday))->toBeFalse();
    expect($service->isDeliveryDay($pc2, $supplier, $monday))->toBeTrue();
});

it('calculates available delivery dates in a range', function () {
    $pc = ProfitCenter::factory()->create();
    $supplier = Supplier::factory()->create();
    $schedule = DeliverySchedule::factory()->create([
        'monday' => true,
        'wednesday' => true,
        'friday' => true,
    ]);
    ProfitCenterSupplierSchedule::factory()->create([
        'profit_center_id' => $pc->id,
        'supplier_id' => $supplier->id,
        'delivery_schedule_id' => $schedule->id,
    ]);
    $start = Carbon::parse('2026-04-13'); // Monday
    $end = Carbon::parse('2026-04-19');   // Sunday
    $service = app(DeliveryCalendarService::class);
    $dates = $service->getAvailableDeliveryDates($pc, $supplier, $start, $end);
    // Should be Mon, Wed, Fri
    expect($dates)->toHaveCount(3);
    $dateStrings = $dates->map(fn($d) => $d->toDateString());
    expect($dateStrings)->toContain('2026-04-13');
    expect($dateStrings)->toContain('2026-04-15');
    expect($dateStrings)->toContain('2026-04-17');
});
