<?php

usesApiSuite();

function selfserve_lane_command_ensure_legacy_redis_constant(): void
{
    if (defined('redis')) {
        return;
    }

    global $REDIS_CONFIG;

    $REDIS_CONFIG = [
        'host' => getenv('REDIS_CONFIG_HOST') ?: getenv('REDIS_CONFIG_DEBUG_HOST') ?: 'redis',
        'user' => getenv('REDIS_CONFIG_USER') ?: getenv('REDIS_CONFIG_DEBUG_USER') ?: 'default',
        'database' => getenv('REDIS_CONFIG_DATABASE') ?: getenv('REDIS_CONFIG_DEBUG_DATABASE') ?: '0',
        'password' => getenv('REDIS_CONFIG_PASSWORD') ?: getenv('REDIS_CONFIG_DEBUG_PASSWORD') ?: '',
        'port' => getenv('REDIS_CONFIG_PORT') ?: getenv('REDIS_CONFIG_DEBUG_PORT') ?: '6379',
    ];

    define('redis', (new \classes\redis())->connect());
}

function selfserve_lane_command_lane(int $laneId): \modules\selfserve\classes\selfserve_lane
{
    selfserve_lane_command_ensure_legacy_redis_constant();

    return (new \classes\selfserve())->lane($laneId);
}

function selfserve_lane_command_make_available(int $laneId): void
{
    $lane = selfserve_lane_command_lane($laneId);
    $lane->setLaneStatus(\modules\selfserve\helpers\selfserve_lane_status::AVAILABLE);
    $lane->setLaneState(\modules\selfserve\helpers\selfserve_lane_state::IDLE);
    $lane->setCustomerNumber(0);
    $lane->setLicensePlate('');
    $lane->setWashStartTime(0);
}

function selfserve_lane_command_make_occupied(int $laneId, int $customerNumber, string $licensePlate): void
{
    $lane = selfserve_lane_command_lane($laneId);
    $lane->setLaneStatus(\modules\selfserve\helpers\selfserve_lane_status::OCCUPIED);
    $lane->setLaneState(\modules\selfserve\helpers\selfserve_lane_state::IN_WASH);
    $lane->setCustomerNumber($customerNumber);
    $lane->setLicensePlate($licensePlate);
    $lane->setWashStartTime(time() - 60);
}

it('allows customer self-serve permission to execute START without department access when department and lane are enabled', function (): void {
    $group = api_fixtures()->createGroup([], [
        'list_own_department_selfserve_vehicle_conditions',
        'add_own_department_selfserve_vehicle_conditions',
    ]);
    $scenario = api_fixtures()->createSelfServeScenario([
        'customer' => ['group_id' => $group['id']],
        'department_selfserve_enabled' => true,
        'lane_selfserve_enabled' => true,
    ]);
    selfserve_lane_command_make_available((int)$scenario['lane']['id']);
    $token = api_fixtures()->createAuthToken((int)$scenario['customer']['id']);

    $response = api_client()->post('/modules/self-serve/lane/command', [
        'lane_id' => (int)$scenario['lane']['id'],
        'command' => 'START',
        'license_plate' => (string)$scenario['vehicle']['reg'],
        'wash_type' => 'Manual',
        'defer_relay_side_effects' => true,
    ], api_fixtures()->bearerHeaders($token));

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

    expect($response->data()['status'] ?? null)->toBe('OCCUPIED')
        ->and($response->data()['customer_number'] ?? null)->toBe((int)$scenario['customer']['customer_number']);
});

it('denies customer START when department self-serve is disabled', function (): void {
    $group = api_fixtures()->createGroup([], [
        'list_own_department_selfserve_vehicle_conditions',
        'add_own_department_selfserve_vehicle_conditions',
    ]);
    $scenario = api_fixtures()->createSelfServeScenario([
        'customer' => ['group_id' => $group['id']],
        'department_selfserve_enabled' => false,
        'lane_selfserve_enabled' => true,
    ]);
    selfserve_lane_command_make_available((int)$scenario['lane']['id']);
    $token = api_fixtures()->createAuthToken((int)$scenario['customer']['id']);

    $response = api_client()->post('/modules/self-serve/lane/command', [
        'lane_id' => (int)$scenario['lane']['id'],
        'command' => 'START',
        'license_plate' => (string)$scenario['vehicle']['reg'],
    ], api_fixtures()->bearerHeaders($token));

    $response
        ->assertStatus(403)
        ->assertMissingPermissions([
            'department_access_' . (int)$scenario['department']['id'],
            'add_own_department_selfserve_vehicle_conditions',
        ]);
});

it('denies customer START when lane self-serve is disabled', function (): void {
    $group = api_fixtures()->createGroup([], [
        'list_own_department_selfserve_vehicle_conditions',
        'add_own_department_selfserve_vehicle_conditions',
    ]);
    $scenario = api_fixtures()->createSelfServeScenario([
        'customer' => ['group_id' => $group['id']],
        'department_selfserve_enabled' => true,
        'lane_selfserve_enabled' => false,
    ]);
    selfserve_lane_command_make_available((int)$scenario['lane']['id']);
    $token = api_fixtures()->createAuthToken((int)$scenario['customer']['id']);

    $response = api_client()->post('/modules/self-serve/lane/command', [
        'lane_id' => (int)$scenario['lane']['id'],
        'command' => 'START',
        'license_plate' => (string)$scenario['vehicle']['reg'],
    ], api_fixtures()->bearerHeaders($token));

    $response
        ->assertStatus(403)
        ->assertMissingPermissions([
            'department_access_' . (int)$scenario['department']['id'],
            'add_own_department_selfserve_vehicle_conditions',
        ]);
});

it('denies a customer STOP for another customers active lane', function (): void {
    $scenario = api_fixtures()->createSelfServeScenario([
        'department_selfserve_enabled' => true,
        'lane_selfserve_enabled' => true,
    ]);
    selfserve_lane_command_make_occupied(
        (int)$scenario['lane']['id'],
        (int)$scenario['customer']['customer_number'],
        (string)$scenario['vehicle']['reg']
    );
    $otherSession = api_fixtures()->createUserSession([
        'list_own_department_selfserve_vehicle_conditions',
    ]);

    $response = api_client()->post('/modules/self-serve/lane/command', [
        'lane_id' => (int)$scenario['lane']['id'],
        'command' => 'STOP',
    ], $otherSession['headers']);

    $response
        ->assertStatus(403)
        ->assertMissingPermissions([
            'department_access_' . (int)$scenario['department']['id'],
            'list_own_department_selfserve_vehicle_conditions',
        ]);
});

it('still allows elevated operators with department access to execute lane commands', function (): void {
    $scenario = api_fixtures()->createSelfServeScenario([
        'department_selfserve_enabled' => false,
        'lane_selfserve_enabled' => false,
    ]);
    selfserve_lane_command_make_available((int)$scenario['lane']['id']);
    $session = api_fixtures()->createUserSession([
        'department_access_' . (int)$scenario['department']['id'],
        'modules_selfserve_lane_command_execute',
        'modules_selfserve_lane_command_execute_start',
    ]);

    $response = api_client()->post('/modules/self-serve/lane/command', [
        'lane_id' => (int)$scenario['lane']['id'],
        'command' => 'START',
        'license_plate' => 'OP' . (int)$scenario['lane']['id'],
        'wash_type' => 'Manual',
        'defer_relay_side_effects' => true,
    ], $session['headers']);

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

    expect($response->data()['status'] ?? null)->toBe('OCCUPIED');
});

it('keeps operator-only commands elevated-only for customers and reports command permissions', function (): void {
    $group = api_fixtures()->createGroup([], [
        'list_own_department_selfserve_vehicle_conditions',
    ]);
    $scenario = api_fixtures()->createSelfServeScenario([
        'customer' => ['group_id' => $group['id']],
        'department_selfserve_enabled' => true,
        'lane_selfserve_enabled' => true,
    ]);
    selfserve_lane_command_make_available((int)$scenario['lane']['id']);
    $token = api_fixtures()->createAuthToken((int)$scenario['customer']['id']);

    $response = api_client()->post('/modules/self-serve/lane/command', [
        'lane_id' => (int)$scenario['lane']['id'],
        'command' => 'RESET',
    ], api_fixtures()->bearerHeaders($token));

    $response
        ->assertStatus(403)
        ->assertMissingPermissions([
            'department_access_' . (int)$scenario['department']['id'],
        ]);
});
