<?php

declare(strict_types=1);

usesApiSuite();

function reference_suggestion_by_reference(array $suggestions, string $reference): ?array
{
    foreach ($suggestions as $suggestion) {
        if (($suggestion['reference'] ?? null) === $reference) {
            return $suggestion;
        }
    }

    return null;
}

it('returns ranked POS reference suggestions from bookings, orders, and customer vehicles', function (): void {
    api_test_covers('GET /orders/reference-suggestions', 'happy');

    $department = api_fixtures()->createDepartment();
    $customer = api_fixtures()->createUser(['display_name' => 'Reference Suggestion Customer']);
    $cashier = api_fixtures()->createUser(['display_name' => 'Reference Suggestion Cashier']);

    api_fixtures()->createOrderBooking([
        'customer_number' => $customer['customer_number'],
        'department' => $department['id'],
        'reference' => 'REF-BOOKING',
        'datetime' => '2026-05-13 09:00:00',
        'created_at' => '2026-05-01 08:00:00',
        'reg_1' => 'BOOK1',
    ]);
    api_fixtures()->createOrder([
        'customer_id' => $customer['customer_number'],
        'cashier_id' => $cashier['id'],
        'department_id' => $department['id'],
        'reference' => 'REF-HISTORY',
        'created_at' => '2026-05-10 10:00:00',
        'reg_1' => 'HIST1',
    ]);
    api_fixtures()->createVehicle([
        'customer_id' => $customer['customer_number'],
        'type' => 53,
        'reg' => 'VEH1',
        'reference' => 'REF-VEHICLE',
        'created_at' => '2026-05-08 12:00:00',
    ]);

    api_fixtures()->createOrderBooking([
        'customer_number' => $customer['customer_number'],
        'department' => $department['id'],
        'reference' => 'REF-SHARED',
        'datetime' => '2026-05-15 11:00:00',
        'reg_1' => 'SHARED1',
    ]);
    api_fixtures()->createOrder([
        'customer_id' => $customer['customer_number'],
        'cashier_id' => $cashier['id'],
        'department_id' => $department['id'],
        'reference' => 'REF-SHARED',
        'created_at' => '2026-05-12 10:00:00',
        'reg_1' => 'SHARED1',
    ]);
    api_fixtures()->createVehicle([
        'customer_id' => $customer['customer_number'],
        'type' => 53,
        'reg' => 'SHARED1',
        'reference' => 'REF-SHARED',
        'created_at' => '2026-05-09 12:00:00',
    ]);

    $deletedOrder = api_fixtures()->createOrder([
        'customer_id' => $customer['customer_number'],
        'cashier_id' => $cashier['id'],
        'department_id' => $department['id'],
        'reference' => 'REF-DELETED',
    ]);
    api_test_runtime()->db()
        ->query("UPDATE orders SET deleted_at = '2026-05-10 12:00:00' WHERE id = " . (int)$deletedOrder['id']);
    api_fixtures()->createOrder([
        'customer_id' => $customer['customer_number'],
        'cashier_id' => $cashier['id'],
        'department_id' => $department['id'],
        'reference' => '',
    ]);

    $session = api_fixtures()->createUserSession([
        'list_orders',
        'department_access_' . $department['id'],
    ]);

    $response = api_client()->get('/orders/reference-suggestions?' . http_build_query([
        'search' => 'REF',
        'department_id' => $department['id'],
        'customer_id' => $customer['customer_number'],
        'reg_1' => 'SHARED1',
        'limit' => 10,
    ]), $session['headers']);

    $response
        ->assertStatus(200)
        ->assertEnvelope()
        ->assertSuccess();

    $suggestions = $response->data();
    expect($suggestions)->toBeArray();

    $booking = reference_suggestion_by_reference($suggestions, 'REF-BOOKING');
    $history = reference_suggestion_by_reference($suggestions, 'REF-HISTORY');
    $vehicle = reference_suggestion_by_reference($suggestions, 'REF-VEHICLE');
    $shared = reference_suggestion_by_reference($suggestions, 'REF-SHARED');

    expect($booking['source'] ?? null)->toBe('booking');
    expect($booking['source_created_at'] ?? null)->toBe('2026-05-13 09:00:00');
    expect($history['source'] ?? null)->toBe('order');
    expect($vehicle['source'] ?? null)->toBe('vehicle');
    expect($shared['source'] ?? null)->toBe('booking');
    expect($shared['section'] ?? null)->toBe('this_vehicle');
    expect($booking['section'] ?? null)->toBe('other_customer_vehicle');
    expect($history['section'] ?? null)->toBe('other_customer_vehicle');
    expect($vehicle['section'] ?? null)->toBe('other_customer_vehicle');
    expect($shared['usage_count'] ?? null)->toBe(3);
    expect($shared['last_used_at'] ?? null)->toBe('2026-05-15 11:00:00');
    expect(reference_suggestion_by_reference($suggestions, 'REF-DELETED'))->toBeNull();
    expect(reference_suggestion_by_reference($suggestions, ''))->toBeNull();
});

it('orders reference suggestions by match relevance before context and frequency', function (): void {
    $department = api_fixtures()->createDepartment();
    $customer = api_fixtures()->createUser(['display_name' => 'Reference Ranking Customer']);
    $cashier = api_fixtures()->createUser(['display_name' => 'Reference Ranking Cashier']);

    api_fixtures()->createOrder([
        'customer_id' => $customer['customer_number'],
        'cashier_id' => $cashier['id'],
        'department_id' => $department['id'],
        'reference' => 'ABC',
        'created_at' => '2026-05-01 08:00:00',
        'reg_1' => 'OTHER1',
    ]);
    api_fixtures()->createOrderBooking([
        'customer_number' => $customer['customer_number'],
        'department' => $department['id'],
        'reference' => 'ABC-PREFIX',
        'datetime' => '2026-05-16 08:00:00',
        'reg_1' => 'MATCH1',
    ]);
    api_fixtures()->createOrder([
        'customer_id' => $customer['customer_number'],
        'cashier_id' => $cashier['id'],
        'department_id' => $department['id'],
        'reference' => 'X-ABC-CONTAINS',
        'created_at' => '2026-05-17 08:00:00',
        'reg_1' => 'MATCH1',
    ]);

    $session = api_fixtures()->createUserSession([
        'list_orders',
        'department_access_' . $department['id'],
    ]);

    $response = api_client()->get('/orders/reference-suggestions?' . http_build_query([
        'search' => 'ABC',
        'department_id' => $department['id'],
        'customer_id' => $customer['customer_number'],
        'reg_1' => 'MATCH1',
    ]), $session['headers']);

    $response
        ->assertStatus(200)
        ->assertEnvelope()
        ->assertSuccess();

    $references = array_map(
        static fn(array $suggestion): string => (string)($suggestion['reference'] ?? ''),
        is_array($response->data()) ? $response->data() : []
    );

    expect(array_slice($references, 0, 3))->toBe(['ABC', 'ABC-PREFIX', 'X-ABC-CONTAINS']);
});

it('does not return vehicle reference suggestions outside the authorized department context', function (): void {
    api_test_covers('GET /orders/reference-suggestions', 'security');

    $authorizedDepartment = api_fixtures()->createDepartment();
    $otherDepartment = api_fixtures()->createDepartment();
    $authorizedCustomer = api_fixtures()->createUser(['display_name' => 'Authorized Reference Customer']);
    $otherCustomer = api_fixtures()->createUser(['display_name' => 'Other Tenant Reference Customer']);
    $cashier = api_fixtures()->createUser(['display_name' => 'Reference Security Cashier']);

    api_fixtures()->createOrder([
        'customer_id' => $authorizedCustomer['customer_number'],
        'cashier_id' => $cashier['id'],
        'department_id' => $authorizedDepartment['id'],
        'reference' => 'SAFE-DEPARTMENT-REF',
        'reg_1' => 'SAFE1',
    ]);
    api_fixtures()->createOrder([
        'customer_id' => $otherCustomer['customer_number'],
        'cashier_id' => $cashier['id'],
        'department_id' => $otherDepartment['id'],
        'reference' => 'LEAK-ORDER-REF',
        'reg_1' => 'LEAK1',
    ]);
    api_fixtures()->createVehicle([
        'customer_id' => $otherCustomer['customer_number'],
        'type' => 53,
        'reg' => 'LEAK1',
        'reference' => 'LEAK-VEHICLE-REF',
    ]);

    $session = api_fixtures()->createUserSession([
        'list_orders',
        'department_access_' . $authorizedDepartment['id'],
    ]);

    $response = api_client()->get('/orders/reference-suggestions?' . http_build_query([
        'search' => 'LEAK',
        'department_id' => $authorizedDepartment['id'],
        'customer_id' => $otherCustomer['customer_number'],
        'reg_1' => 'LEAK1',
    ]), $session['headers']);

    $response
        ->assertStatus(200)
        ->assertEnvelope()
        ->assertSuccess();

    $suggestions = $response->data();
    expect($suggestions)->toBeArray();
    expect(reference_suggestion_by_reference($suggestions, 'LEAK-VEHICLE-REF'))->toBeNull();
    expect(reference_suggestion_by_reference($suggestions, 'LEAK-ORDER-REF'))->toBeNull();
});

it('enforces authentication, list permission, and department access for reference suggestions', function (): void {
    api_test_covers('GET /orders/reference-suggestions', 'auth');

    $department = api_fixtures()->createDepartment();

    api_client()->get('/orders/reference-suggestions?department_id=' . $department['id'])
        ->assertStatus(400)
        ->assertEnvelope()
        ->assertSuccess(false)
        ->assertMessage('Invalid session');

    $missingListPermission = api_fixtures()->createUserSession([
        'department_access_' . $department['id'],
    ]);
    api_client()->get('/orders/reference-suggestions?department_id=' . $department['id'], $missingListPermission['headers'])
        ->assertStatus(403)
        ->assertEnvelope()
        ->assertSuccess(false)
        ->assertMissingPermissions(['list_orders']);

    $missingDepartmentAccess = api_fixtures()->createUserSession(['list_orders']);
    api_client()->get('/orders/reference-suggestions?department_id=' . $department['id'], $missingDepartmentAccess['headers'])
        ->assertStatus(403)
        ->assertEnvelope()
        ->assertSuccess(false)
        ->assertMissingPermissions(['department_access_' . $department['id']]);
});
