<?php

use Illuminate\Database\QueryException;
use Modules\Catalog\Models\DepartureTimeSlot;
use Modules\Catalog\Models\Destination;
use Modules\Catalog\Models\EvCompany;
use Modules\Routing\Models\EvRoute;

test('an ev route belongs to a company and two destinations', function () {
    $company = EvCompany::factory()->create();
    $from = Destination::factory()->create();
    $to = Destination::factory()->create();

    $route = EvRoute::factory()->create([
        'ev_company_id' => $company->id,
        'from_destination_id' => $from->id,
        'to_destination_id' => $to->id,
    ]);

    expect($route->company)->toBeInstanceOf(EvCompany::class)
        ->and($route->company->is($company))->toBeTrue()
        ->and($route->fromDestination)->toBeInstanceOf(Destination::class)
        ->and($route->fromDestination->is($from))->toBeTrue()
        ->and($route->toDestination)->toBeInstanceOf(Destination::class)
        ->and($route->toDestination->is($to))->toBeTrue();
});

test('is_active casts to boolean', function () {
    $route = EvRoute::factory()->create([
        'is_active' => 0,
    ]);

    expect($route->is_active)->toBeFalse();
});

test('isReverseOf detects a route with from/to swapped', function () {
    $a = Destination::factory()->create();
    $b = Destination::factory()->create();

    $outbound = EvRoute::factory()->create(['from_destination_id' => $a->id, 'to_destination_id' => $b->id]);
    $return = EvRoute::factory()->create(['from_destination_id' => $b->id, 'to_destination_id' => $a->id]);
    $unrelated = EvRoute::factory()->create();

    expect($return->isReverseOf($outbound))->toBeTrue()
        ->and($outbound->isReverseOf($return))->toBeTrue()
        ->and($unrelated->isReverseOf($outbound))->toBeFalse()
        ->and($outbound->isReverseOf($outbound))->toBeFalse();
});

test('a route can be attached to time slots via the pivot, carrying its own is_active flag', function () {
    $route = EvRoute::factory()->create();
    $morningSlot = DepartureTimeSlot::factory()->create();
    $eveningSlot = DepartureTimeSlot::factory()->create();

    $route->timeSlots()->attach([
        $morningSlot->id => ['is_active' => true],
        $eveningSlot->id => ['is_active' => false],
    ]);

    $route->refresh();

    expect($route->timeSlots)->toHaveCount(2);

    $attachedMorning = $route->timeSlots->firstWhere('id', $morningSlot->id);
    $attachedEvening = $route->timeSlots->firstWhere('id', $eveningSlot->id);

    expect($attachedMorning->pivot->is_active)->toBeTrue()
        ->and($attachedEvening->pivot->is_active)->toBeFalse();

    expect($morningSlot->routes)->toHaveCount(1)
        ->and($morningSlot->routes->first()->is($route))->toBeTrue();
});

test('a route cannot have the same from and to destination', function () {
    $destination = Destination::factory()->create();

    expect(fn () => EvRoute::factory()->create([
        'from_destination_id' => $destination->id,
        'to_destination_id' => $destination->id,
    ]))->toThrow(InvalidArgumentException::class);
});

test('a route cannot be attached to the same time slot twice', function () {
    $route = EvRoute::factory()->create();
    $slot = DepartureTimeSlot::factory()->create();

    $route->timeSlots()->attach($slot->id, ['is_active' => true]);

    expect(fn () => $route->timeSlots()->attach($slot->id, ['is_active' => true]))
        ->toThrow(QueryException::class);
});
