<?php

declare(strict_types=1);

usesApiSuite();

function vehicles_without_customer_vehicles_deleted_at(callable $callback): void
{
    $db = api_test_runtime()->db();
    $column = $db->query("SHOW COLUMNS FROM `customer_vehicles` LIKE 'deleted_at'");
    if ($column === false) {
        throw new RuntimeException('Unable to inspect customer_vehicles.deleted_at test column.');
    }

    $hadColumn = (int)$column->num_rows > 0;
    if ($hadColumn) {
        $db->query('ALTER TABLE `customer_vehicles` DROP COLUMN `deleted_at`');
    }

    try {
        $callback();
    } finally {
        if ($hadColumn) {
            $db->query('ALTER TABLE `customer_vehicles` ADD COLUMN `deleted_at` DATETIME NULL');
        }
    }
}

it('defaults wash subscriptions to false when a customer creates a vehicle without the field', function (): void {
    api_test_covers('POST /vehicles', 'happy');

    $session = api_fixtures()->createUserSession(['add_vehicle']);

    $response = api_client()->post('/vehicles', [
        'type' => 53,
        'reg' => 'DEFAULTOWN',
    ], $session['headers']);

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

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

    $row = api_fixtures()->fetchRowById('customer_vehicles', $vehicleId);
    expect($row)->not->toBeNull();
    expect((int)$row['customer_id'])->toBe((int)$session['user']['customer_number']);
    expect((int)$row['wash_subscription'])->toBe(0);
    expect($response->data())->toMatchArray([
        'id' => $vehicleId,
        'customer_id' => (int)$session['user']['customer_number'],
        'reg' => 'DEFAULTOWN',
        'wash_subscription' => false,
    ]);

    api_fixtures()->cleanupDeleteById('customer_vehicles', $vehicleId);
    api_fixtures()->cleanupDeleteWhere('customer_vehicle_subscription_versions', ['vehicle_id' => $vehicleId]);
});

it('defaults wash subscriptions to false when a superuser creates a vehicle for another customer without the field', function (): void {
    api_test_covers('POST /vehicles', 'happy');

    $targetCustomer = api_fixtures()->createUser(['display_name' => 'Vehicle Default Target Customer']);
    $session = api_fixtures()->createUserSession(['add_vehicle_other']);

    $response = api_client()->post('/vehicles', [
        'customer_id' => $targetCustomer['customer_number'],
        'type' => 53,
        'reg' => 'DEFAULTSU',
    ], $session['headers']);

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

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

    $row = api_fixtures()->fetchRowById('customer_vehicles', $vehicleId);
    expect($row)->not->toBeNull();
    expect((int)$row['customer_id'])->toBe((int)$targetCustomer['customer_number']);
    expect((int)$row['wash_subscription'])->toBe(0);
    expect($response->data())->toMatchArray([
        'id' => $vehicleId,
        'customer_id' => (int)$targetCustomer['customer_number'],
        'reg' => 'DEFAULTSU',
        'wash_subscription' => false,
    ]);

    api_fixtures()->cleanupDeleteById('customer_vehicles', $vehicleId);
    api_fixtures()->cleanupDeleteWhere('customer_vehicle_subscription_versions', ['vehicle_id' => $vehicleId]);
});

it('still honors an explicit wash subscription true value on vehicle create', function (): void {
    api_test_covers('POST /vehicles', 'happy');

    $session = api_fixtures()->createUserSession(['add_vehicle']);

    $response = api_client()->post('/vehicles', [
        'type' => 53,
        'reg' => 'EXPLICITON',
        'wash_subscription' => true,
    ], $session['headers']);

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

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

    $row = api_fixtures()->fetchRowById('customer_vehicles', $vehicleId);
    expect($row)->not->toBeNull();
    expect((int)$row['wash_subscription'])->toBe(1);
    expect($response->data())->toMatchArray([
        'id' => $vehicleId,
        'reg' => 'EXPLICITON',
        'wash_subscription' => true,
    ]);

    api_fixtures()->cleanupDeleteById('customer_vehicles', $vehicleId);
    api_fixtures()->cleanupDeleteWhere('customer_vehicle_subscription_versions', ['vehicle_id' => $vehicleId]);
});

it('returns the newest vehicle last_order_id that still has order items', function (): void {
    api_test_covers('GET /vehicles', 'happy');

    $session = api_fixtures()->createUserSession(['list_own_vehicles']);
    $department = api_fixtures()->createDepartment(['name' => 'Vehicle API Department']);
    $vehicle = api_fixtures()->createVehicle([
        'customer_id' => $session['user']['customer_number'],
        'type' => 53,
        'reg' => 'SIDSTEV1',
        'reference' => 'VEHICLE-LAST-WASH',
    ]);

    $olderOrder = api_fixtures()->createOrder([
        'customer_id' => $session['user']['customer_number'],
        'cashier_id' => $session['user']['id'],
        'department_id' => $department['id'],
        'reference' => 'OLDER-ORDER',
        'reg_1' => $vehicle['reg'],
    ]);
    api_fixtures()->createOrderItem([
        'order_id' => $olderOrder['id'],
        'product_id' => 53,
        'cashier_id' => $session['user']['id'],
        'price' => 599,
        'quantity' => 1,
    ]);

    $newerOrder = api_fixtures()->createOrder([
        'customer_id' => $session['user']['customer_number'],
        'cashier_id' => $session['user']['id'],
        'department_id' => $department['id'],
        'reference' => 'NEWER-ORDER',
        'reg_1' => $vehicle['reg'],
    ]);

    $response = api_client()->get('/vehicles?id=' . $vehicle['id'], $session['headers']);

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

    expect($newerOrder['id'])->toBeGreaterThan($olderOrder['id']);
    expect($response->data())->toMatchArray([
        'id' => $vehicle['id'],
        'reg' => $vehicle['reg'],
        'last_order_id' => $olderOrder['id'],
    ]);
});

it('returns a null vehicle last_order_id when no order with items exists', function (): void {
    api_test_covers('GET /vehicles', 'happy');

    $session = api_fixtures()->createUserSession(['list_own_vehicles']);
    $department = api_fixtures()->createDepartment(['name' => 'Vehicle API Department Null']);
    $vehicle = api_fixtures()->createVehicle([
        'customer_id' => $session['user']['customer_number'],
        'type' => 53,
        'reg' => 'SIDSTEV2',
        'reference' => 'VEHICLE-NO-LAST-WASH',
    ]);

    api_fixtures()->createOrder([
        'customer_id' => $session['user']['customer_number'],
        'cashier_id' => $session['user']['id'],
        'department_id' => $department['id'],
        'reference' => 'EMPTY-ORDER-1',
        'reg_1' => $vehicle['reg'],
    ]);
    api_fixtures()->createOrder([
        'customer_id' => $session['user']['customer_number'],
        'cashier_id' => $session['user']['id'],
        'department_id' => $department['id'],
        'reference' => 'EMPTY-ORDER-2',
        'reg_1' => $vehicle['reg'],
    ]);

    $response = api_client()->get('/vehicles?id=' . $vehicle['id'], $session['headers']);

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

    expect($response->data())->toMatchArray([
        'id' => $vehicle['id'],
        'reg' => $vehicle['reg'],
        'last_order_id' => null,
    ]);
});

it('lists and summarizes vehicles through the user-scoped superuser route', function (): void {
    api_test_covers('GET /superuser/users/{user_id}/vehicles', 'happy');
    api_test_covers('GET /superuser/users/{user_id}/vehicles/summary', 'happy');

    $targetUser = api_fixtures()->createUser(['display_name' => 'Scoped Vehicle Customer']);
    $otherUser = api_fixtures()->createUser(['display_name' => 'Other Vehicle Customer']);
    $vehicle = api_fixtures()->createVehicle([
        'customer_id' => $targetUser['customer_number'],
        'type' => 53,
        'reg' => 'SCOPEDV1',
        'wash_subscription' => 1,
        'reference' => 'Scoped fleet',
    ]);
    api_fixtures()->createVehicle([
        'customer_id' => $otherUser['customer_number'],
        'type' => 53,
        'reg' => 'OTHERV1',
        'wash_subscription' => 1,
    ]);
    $session = api_fixtures()->createUserSession(['list_vehicles_other']);

    $response = api_client()->get(
        '/superuser/users/' . $targetUser['id'] . '/vehicles?page=1&limit=20',
        $session['headers']
    );
    $summary = api_client()->get(
        '/superuser/users/' . $targetUser['id'] . '/vehicles/summary',
        $session['headers']
    );

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

    $rows = $response->data();
    expect(array_column($rows, 'reg'))->toContain('SCOPEDV1');
    expect(array_column($rows, 'reg'))->not->toContain('OTHERV1');
    expect($rows[0])->toMatchArray([
        'id' => $vehicle['id'],
        'customer_id' => $targetUser['customer_number'],
        'reg' => 'SCOPEDV1',
    ]);
    expect($response->meta()['user_context'])->toMatchArray([
        'user_id' => $targetUser['id'],
        'customer_number' => $targetUser['customer_number'],
    ]);
    expect($summary->data())->toMatchArray([
        'total' => 1,
        'wash_subscription' => 1,
        'self_service' => 0,
    ]);
});

it('lists and summarizes user-scoped superuser vehicles when customer vehicles has no deleted at column', function (): void {
    vehicles_without_customer_vehicles_deleted_at(function (): void {
        api_test_covers('GET /superuser/users/{user_id}/vehicles', 'happy');
        api_test_covers('GET /superuser/users/{user_id}/vehicles/summary', 'happy');

        $customerVehiclesDeletedAtColumn = api_test_runtime()->db()->query(
            "SHOW COLUMNS FROM `customer_vehicles` LIKE 'deleted_at'"
        );
        expect($customerVehiclesDeletedAtColumn)->not->toBeFalse();
        expect((int)$customerVehiclesDeletedAtColumn->num_rows)->toBe(0);

        $targetUser = api_fixtures()->createUser(['display_name' => 'Scoped Vehicle Legacy Schema Customer']);
        $otherUser = api_fixtures()->createUser(['display_name' => 'Other Vehicle Legacy Schema Customer']);
        $vehicle = api_fixtures()->createVehicle([
            'customer_id' => $targetUser['customer_number'],
            'type' => 53,
            'reg' => 'LEGACYV1',
            'wash_subscription' => 1,
            'reference' => 'Legacy schema fleet',
        ]);
        api_fixtures()->createVehicle([
            'customer_id' => $otherUser['customer_number'],
            'type' => 53,
            'reg' => 'LEGACYOTHER',
            'wash_subscription' => 1,
        ]);
        $session = api_fixtures()->createUserSession(['list_vehicles_other']);

        $response = api_client()->get(
            '/superuser/users/' . $targetUser['id'] . '/vehicles?page=1&limit=20',
            $session['headers']
        );
        $summary = api_client()->get(
            '/superuser/users/' . $targetUser['id'] . '/vehicles/summary',
            $session['headers']
        );

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

        $rows = $response->data();
        expect(array_column($rows, 'reg'))->toContain('LEGACYV1');
        expect(array_column($rows, 'reg'))->not->toContain('LEGACYOTHER');
        expect($rows[0])->toMatchArray([
            'id' => $vehicle['id'],
            'customer_id' => $targetUser['customer_number'],
            'reg' => 'LEGACYV1',
        ]);
        expect($response->meta()['user_context'])->toMatchArray([
            'user_id' => $targetUser['id'],
            'customer_number' => $targetUser['customer_number'],
        ]);
        expect($summary->data())->toMatchArray([
            'total' => 1,
            'wash_subscription' => 1,
            'self_service' => 0,
        ]);
    });
});

it('creates vehicles through the user-scoped superuser route and rejects mismatched customer ids', function (): void {
    api_test_covers('POST /superuser/users/{user_id}/vehicles', 'happy');
    api_test_covers('POST /superuser/users/{user_id}/vehicles', 'failure');

    $targetUser = api_fixtures()->createUser(['display_name' => 'Scoped Vehicle Create Customer']);
    $otherUser = api_fixtures()->createUser(['display_name' => 'Scoped Vehicle Mismatch Customer']);
    $session = api_fixtures()->createUserSession(['add_vehicle_other']);

    $created = api_client()->post('/superuser/users/' . $targetUser['id'] . '/vehicles', [
        'type' => 53,
        'reg' => 'SCOPEDADD',
        'wash_subscription' => true,
        'reference' => 'Created from user detail',
    ], $session['headers']);
    $mismatch = api_client()->post('/superuser/users/' . $targetUser['id'] . '/vehicles', [
        'customer_id' => $otherUser['customer_number'],
        'type' => 53,
        'reg' => 'BADSCOPED',
    ], $session['headers']);

    $created
        ->assertStatus(200)
        ->assertEnvelope()
        ->assertSuccess();
    $mismatch
        ->assertStatus(400)
        ->assertEnvelope()
        ->assertError();

    $vehicleId = (int)($created->data()['id'] ?? 0);
    expect($vehicleId)->toBeGreaterThan(0);
    expect($created->data())->toMatchArray([
        'customer_id' => $targetUser['customer_number'],
        'reg' => 'SCOPEDADD',
        'wash_subscription' => true,
        'reference' => 'Created from user detail',
    ]);
    api_fixtures()->cleanupDeleteById('customer_vehicles', $vehicleId);
    api_fixtures()->cleanupDeleteWhere('customer_vehicle_subscription_versions', ['vehicle_id' => $vehicleId]);
});

it('edits and deletes only matching customer vehicles through the user-scoped superuser route', function (): void {
    api_test_covers('PUT /superuser/users/{user_id}/vehicles', 'happy');
    api_test_covers('PUT /superuser/users/{user_id}/vehicles', 'failure');
    api_test_covers('DELETE /superuser/users/{user_id}/vehicles', 'happy');
    api_test_covers('DELETE /superuser/users/{user_id}/vehicles', 'failure');

    $targetUser = api_fixtures()->createUser(['display_name' => 'Scoped Vehicle Edit Customer']);
    $otherUser = api_fixtures()->createUser(['display_name' => 'Scoped Vehicle Guard Customer']);
    $vehicle = api_fixtures()->createVehicle([
        'customer_id' => $targetUser['customer_number'],
        'type' => 53,
        'reg' => 'SCOPEDIT',
        'wash_subscription' => 0,
    ]);
    $otherVehicle = api_fixtures()->createVehicle([
        'customer_id' => $otherUser['customer_number'],
        'type' => 53,
        'reg' => 'SCOPEBAD',
        'wash_subscription' => 0,
    ]);
    $deletableVehicle = api_fixtures()->createVehicle([
        'customer_id' => $targetUser['customer_number'],
        'type' => 53,
        'reg' => 'SCOPEDEL',
        'wash_subscription' => 0,
    ]);
    $session = api_fixtures()->createUserSession(['edit_vehicle_other', 'delete_vehicle_other']);

    $edited = api_client()->put('/superuser/users/' . $targetUser['id'] . '/vehicles', [
        'id' => $vehicle['id'],
        'reg' => 'SCOPEDOK',
        'reference' => 'Updated reference',
    ], $session['headers']);
    $moved = api_client()->put('/superuser/users/' . $targetUser['id'] . '/vehicles', [
        'id' => $vehicle['id'],
        'customer_id' => $otherUser['customer_number'],
    ], $session['headers']);
    $foreignEdit = api_client()->put('/superuser/users/' . $targetUser['id'] . '/vehicles', [
        'id' => $otherVehicle['id'],
        'reg' => 'SHOULDFAIL',
    ], $session['headers']);
    $deleted = api_client()->delete(
        '/superuser/users/' . $targetUser['id'] . '/vehicles?id=' . $deletableVehicle['id'],
        null,
        $session['headers']
    );
    $foreignDelete = api_client()->delete(
        '/superuser/users/' . $targetUser['id'] . '/vehicles?id=' . $otherVehicle['id'],
        null,
        $session['headers']
    );

    $edited
        ->assertStatus(200)
        ->assertEnvelope()
        ->assertSuccess();
    $moved
        ->assertStatus(400)
        ->assertEnvelope()
        ->assertError();
    $foreignEdit
        ->assertStatus(404)
        ->assertEnvelope()
        ->assertError();
    $deleted
        ->assertStatus(200)
        ->assertEnvelope()
        ->assertSuccess();
    $foreignDelete
        ->assertStatus(404)
        ->assertEnvelope()
        ->assertError();

    expect($edited->data())->toMatchArray([
        'id' => $vehicle['id'],
        'customer_id' => $targetUser['customer_number'],
        'reg' => 'SCOPEDOK',
        'reference' => 'Updated reference',
    ]);
});
