<?php

use Firebase\JWT\JWT;
use Modules\Booking\Enums\BookingChannel;
use Modules\Booking\Models\Booking;
use Modules\Catalog\Models\DepartureTimeSlot;
use Modules\Payment\Enums\PaymentMethod;
use Modules\Payment\Models\Payment;
use Modules\Routing\Models\EvRoute;
use Modules\Routing\Models\RoutePricing;
use Modules\Shared\Enums\VehicleOption;

beforeEach(function () {
    config(['services.fastapi_agent.jwt_secret' => 'test-fastapi-agent-secret-0123456789ABCDEF']);
    config(['services.fastapi_agent.jwt_algorithm' => 'HS256']);
});

function fastApiAgentToken(string $openid): string
{
    return JWT::encode([
        'sub' => $openid,
        'iat' => time(),
        'exp' => time() + 3600,
    ], 'test-fastapi-agent-secret-0123456789ABCDEF', 'HS256');
}

test('a FastAPI JWT booking is stored against the verified openid, ignoring a spoofed body value', function () {
    config(['booking.back_seat_enabled' => true]);

    $route = EvRoute::factory()->create(['is_active' => true]);
    $timeSlot = DepartureTimeSlot::factory()->create();
    $route->timeSlots()->attach($timeSlot->id, ['is_active' => true]);
    RoutePricing::factory()->create([
        'ev_route_id' => $route->id,
        'vehicle_option' => VehicleOption::BackSeat,
        'price' => '15000.00',
    ]);

    $token = fastApiAgentToken('real-customer-openid');

    $this->withHeader('Authorization', "Bearer {$token}")
        ->withHeader('Device-Type', 'android') // the agent's own channel always wins, ignored here.
        ->postJson('/api/v1/bookings', [
            'ev_route_id' => $route->id,
            'departure_time_slot_id' => $timeSlot->id,
            'travel_date' => now()->addDay()->toDateString(),
            'selections' => [['vehicle_option' => 'back_seat', 'passenger_count' => 1]],
            'passenger_name' => 'Jane Doe',
            'passenger_phone' => '+959123456789',
            'pickup_address' => '123 Pickup St',
            'dropoff_address' => '456 Dropoff Ave',
            'openid' => 'spoofed-openid',
        ])
        ->assertCreated();

    $booking = Booking::sole();
    expect($booking->openid)->toBe('real-customer-openid')
        ->and($booking->user_id)->toBeNull()
        ->and($booking->created_by_channel)->toBe(BookingChannel::Agent);
});

test('a FastAPI JWT can list and show only its own openid\'s bookings', function () {
    $mine = Booking::factory()->create(['openid' => 'agent-openid-mine']);
    Payment::factory()->completed()->create(['booking_id' => $mine->id, 'gateway' => PaymentMethod::KbzMiniApp]);
    Booking::factory()->create(['openid' => 'agent-openid-someone-else']);

    $token = fastApiAgentToken('agent-openid-mine');

    $this->withHeader('Authorization', "Bearer {$token}")
        ->getJson('/api/v1/bookings')
        ->assertSuccessful()
        ->assertJsonCount(1, 'data')
        ->assertJsonPath('data.0.id', $mine->id);

    $this->withHeader('Authorization', "Bearer {$token}")
        ->getJson("/api/v1/bookings/{$mine->booking_ref}")
        ->assertSuccessful()
        ->assertJsonPath('data.id', $mine->id);
});

test('a FastAPI JWT gets a 404 for a booking belonging to a different openid', function () {
    $someoneElses = Booking::factory()->create(['openid' => 'agent-openid-someone-else']);

    $token = fastApiAgentToken('agent-openid-mine');

    $this->withHeader('Authorization', "Bearer {$token}")
        ->getJson("/api/v1/bookings/{$someoneElses->booking_ref}")
        ->assertNotFound();
});
