<?php

declare(strict_types=1);

usesApiSuite();

function order_booking_create_payload(array $customer, array $department, array $product, string $reference): array
{
    return [
        'customer_number' => (int)$customer['customer_number'],
        'department' => (int)$department['id'],
        'reg_1' => $reference,
        'datetime' => '2026-07-07 10:00:00',
        'note' => '',
        'reference' => $reference,
        'po' => '',
        'pickup' => false,
        'items' => [
            [
                'id' => (int)$product['id'],
                'quantity' => 1,
            ],
        ],
    ];
}

function order_booking_create_department(string $name): array
{
    $branding = api_fixtures()->createBranding([
        'name' => $name . ' Brand',
        'address' => 'API Booking Street 1',
    ]);

    return api_fixtures()->createDepartment([
        'name' => $name,
        'branding' => (int)$branding['id'],
    ]);
}

function order_booking_create_department_price(int $departmentId, int $productId, int $price): void
{
    $statement = api_test_runtime()->db()->prepare(
        'INSERT INTO `product_department_prices` (`department_id`, `product_id`, `price`)
         VALUES (?, ?, ?)
         ON DUPLICATE KEY UPDATE `price` = VALUES(`price`)'
    );
    $statement->bind_param('iii', $departmentId, $productId, $price);
    $statement->execute();
    $statement->close();
}

it('lets customers create their own order bookings without booking permissions', function (): void {
    api_test_covers('POST /order-bookings', 'auth');

    $session = api_fixtures()->createUserSession(['user']);
    $department = order_booking_create_department('Own Booking Department');
    $product = api_fixtures()->createProduct(['name' => 'Own Booking Product']);

    $response = api_client()->post(
        '/order-bookings',
        order_booking_create_payload($session['user'], $department, $product, 'OWNBOOK1'),
        $session['headers']
    );

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

    $bookingId = (int)($response->data()['id'] ?? 0);
    expect($bookingId)->toBeGreaterThan(0);

    $row = api_fixtures()->fetchRowById('order_bookings', $bookingId);
    expect($row)->not->toBeNull();
    expect((int)($row['customer_number'] ?? 0))->toBe((int)$session['user']['customer_number']);

    api_fixtures()->cleanupDeleteById('order_bookings', $bookingId);
});

it('normalizes booking item prices from server-side customer and department pricing', function (): void {
    api_test_covers('POST /order-bookings', 'pricing');

    $session = api_fixtures()->createUserSession(['user']);
    $department = order_booking_create_department('Own Booking Pricing Department');
    $product = api_fixtures()->createProduct([
        'name' => 'Booking Price Normalized Product',
        'price' => 0,
        'is_wash' => 0,
        'display_in_booking_form' => 1,
    ]);
    order_booking_create_department_price((int)$department['id'], (int)$product['id'], 425);

    $payload = order_booking_create_payload($session['user'], $department, $product, 'PRICEFIX1');
    $payload['items'][0]['price'] = 0;

    $response = api_client()->post('/order-bookings', $payload, $session['headers']);

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

    $bookingId = (int)($response->data()['id'] ?? 0);
    expect($bookingId)->toBeGreaterThan(0);

    $responseItems = $response->data()['items'] ?? [];
    expect($responseItems)
        ->toBeArray()
        ->and((int)($responseItems[0]['price'] ?? 0))->toBe(425);

    $row = api_fixtures()->fetchRowById('order_bookings', $bookingId);
    $storedItems = json_decode((string)($row['items'] ?? '[]'), true);
    expect($storedItems)
        ->toBeArray()
        ->and((int)($storedItems[0]['price'] ?? 0))->toBe(425);

    api_fixtures()->cleanupDeleteWhere('product_department_prices', [
        'department_id' => (int)$department['id'],
        'product_id' => (int)$product['id'],
    ]);
    api_fixtures()->cleanupDeleteById('order_bookings', $bookingId);
});

it('blocks subusers creating own customer order bookings without the bookings add node', function (): void {
    api_test_covers('POST /order-bookings', 'auth');

    $customer = api_fixtures()->createUser(['display_name' => 'Subuser Booking Customer']);
    $session = api_fixtures()->createSubuserSession((int)$customer['customer_number'], []);
    $department = order_booking_create_department('Subuser Booking Department');
    $product = api_fixtures()->createProduct(['name' => 'Subuser Booking Product']);

    $response = api_client()->post(
        '/order-bookings',
        order_booking_create_payload($customer, $department, $product, 'SUBBOOK1'),
        $session['headers']
    );

    $response
        ->assertStatus(403)
        ->assertEnvelope()
        ->assertSuccess(false)
        ->assertMissingPermissions(['add_own_bookings']);
});

it('lets subusers create own customer order bookings with the bookings add node', function (): void {
    api_test_covers('POST /order-bookings', 'auth');

    $customer = api_fixtures()->createUser(['display_name' => 'Subuser Booking Customer With Add']);
    $session = api_fixtures()->createSubuserSession((int)$customer['customer_number'], ['BOOKINGS_ADD']);
    $department = order_booking_create_department('Subuser Booking Add Department');
    $product = api_fixtures()->createProduct(['name' => 'Subuser Booking Add Product']);

    $response = api_client()->post(
        '/order-bookings',
        order_booking_create_payload($customer, $department, $product, 'SUBBOOK2'),
        $session['headers']
    );

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

    $bookingId = (int)($response->data()['id'] ?? 0);
    expect($bookingId)->toBeGreaterThan(0);

    $row = api_fixtures()->fetchRowById('order_bookings', $bookingId);
    expect($row)->not->toBeNull();
    expect((int)($row['customer_number'] ?? 0))->toBe((int)$customer['customer_number']);

    api_fixtures()->cleanupDeleteById('order_bookings', $bookingId);
});

it('still requires elevated access for creating another customer order booking', function (): void {
    api_test_covers('POST /order-bookings', 'auth');

    $session = api_fixtures()->createUserSession(['user']);
    $otherCustomer = api_fixtures()->createUser(['display_name' => 'Other Booking Customer']);
    $department = api_fixtures()->createDepartment(['name' => 'Other Booking Department']);
    $product = api_fixtures()->createProduct(['name' => 'Other Booking Product']);

    $response = api_client()->post(
        '/order-bookings',
        order_booking_create_payload($otherCustomer, $department, $product, 'OTHBOOK1'),
        $session['headers']
    );

    $response
        ->assertStatus(403)
        ->assertEnvelope()
        ->assertSuccess(false)
        ->assertMissingPermissions(['add_bookings']);
});

it('lets department-scoped users create order bookings for another customer', function (): void {
    api_test_covers('POST /order-bookings', 'happy');

    $customer = api_fixtures()->createUser(['display_name' => 'Department Booking Customer']);
    $department = order_booking_create_department('Department Scoped Booking Department');
    $product = api_fixtures()->createProduct(['name' => 'Department Scoped Booking Product']);
    $session = api_fixtures()->createUserSession([
        'add_bookings',
        'department_access_' . $department['id'],
    ]);

    $response = api_client()->post(
        '/order-bookings',
        order_booking_create_payload($customer, $department, $product, 'DEPTBOOK'),
        $session['headers']
    );

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

    $bookingId = (int)($response->data()['id'] ?? 0);
    expect($bookingId)->toBeGreaterThan(0);

    api_fixtures()->cleanupDeleteById('order_bookings', $bookingId);
});
