<?php

usesApiSuite();

function selfserve_customer_start_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_customer_start_make_available(int $laneId): void
{
    selfserve_customer_start_ensure_legacy_redis_constant();

    $lane = (new \classes\selfserve())->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);
}

it('allows the customer self-serve start sequence without department access', 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,
    ]);
    $headers = api_fixtures()->bearerHeaders(
        api_fixtures()->createAuthToken((int)$scenario['customer']['id'])
    );
    $laneId = (int)$scenario['lane']['id'];
    $reg = (string)$scenario['vehicle']['reg'];

    selfserve_customer_start_make_available($laneId);

    api_client()
        ->get('/department/selfserve/vehicle/allowed?lane_id=' . $laneId . '&reg=' . urlencode($reg), $headers)
        ->assertStatus(200)
        ->assertSuccess(true);

    $summaryResponse = api_client()
        ->get('/department/selfserve/washes/summary?lane_id=' . $laneId . '&reg=' . urlencode($reg), $headers)
        ->assertStatus(200)
        ->assertSuccess(true);

    expect($summaryResponse->data()['session']['customer_number'] ?? null)
        ->toBe((int)$scenario['customer']['customer_number']);

    api_client()
        ->post('/modules/self-serve/lane/services/allowed', [
            'lane_id' => $laneId,
            'task_ids' => [(int)$scenario['tasks'][1]['id']],
        ], $headers)
        ->assertStatus(200)
        ->assertSuccess(true);

    $startResponse = api_client()
        ->post('/modules/self-serve/lane/command', [
            'lane_id' => $laneId,
            'command' => 'START',
            'license_plate' => $reg,
            'wash_type' => 'Manual',
            'defer_relay_side_effects' => true,
        ], $headers)
        ->assertStatus(200)
        ->assertSuccess(true);

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

it('marks the active customer session relay-enabled after machine relay enable', function (): void {
    $group = api_fixtures()->createGroup([], [
        'list_own_department_selfserve_vehicle_conditions',
        'add_own_department_selfserve_vehicle_conditions',
        'modules_selfserve_lane_relay_enable_machine',
    ]);
    $scenario = api_fixtures()->createSelfServeScenario([
        'customer' => ['group_id' => $group['id']],
        'department_selfserve_enabled' => true,
        'lane_selfserve_enabled' => true,
        'session' => [
            'status' => 'READY_FOR_MACHINE_START',
            'machine_relay_enabled' => 0,
            'machine_relay_enabled_at' => null,
            'machine_start_triggered' => 0,
            'machine_start_triggered_at' => null,
            'wash_started_at' => null,
        ],
    ]);
    $headers = api_fixtures()->bearerHeaders(
        api_fixtures()->createAuthToken((int)$scenario['customer']['id'])
    );
    $laneId = (int)$scenario['lane']['id'];
    $reg = (string)$scenario['vehicle']['reg'];
    $machineTaskId = (int)$scenario['tasks'][1]['id'];

    selfserve_customer_start_make_available($laneId);

    api_client()
        ->get('/department/selfserve/vehicle/allowed?lane_id=' . $laneId . '&reg=' . urlencode($reg), $headers)
        ->assertStatus(200)
        ->assertSuccess(true);

    api_client()
        ->post('/modules/self-serve/lane/services/allowed', [
            'lane_id' => $laneId,
            'task_ids' => [$machineTaskId],
        ], $headers)
        ->assertStatus(200)
        ->assertSuccess(true);

    api_client()
        ->post('/modules/self-serve/lane/command', [
            'lane_id' => $laneId,
            'command' => 'START',
            'license_plate' => $reg,
            'wash_type' => 'Machine',
            'defer_relay_side_effects' => true,
        ], $headers)
        ->assertStatus(200)
        ->assertSuccess(true);

    api_client()
        ->post('/modules/self-serve/lane/relay/machine/enable', [
            'lane_id' => $laneId,
        ], $headers)
        ->assertStatus(200)
        ->assertSuccess(true);

    $activeResponse = api_client()
        ->get('/modules/self-serve/lane/wash/my-active-wash', $headers)
        ->assertStatus(200)
        ->assertSuccess(true);

    expect($activeResponse->data()['session']['status'] ?? null)->toBe('MACHINE_RELAY_ENABLED')
        ->and($activeResponse->data()['session']['machine_relay_enabled'] ?? null)->toBeTrue()
        ->and($activeResponse->data()['session']['machine_start_triggered'] ?? null)->toBeFalse();
});

it('derives allowed services from v2 session task snapshots when task rows are not legacy records', 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,
    ]);
    $headers = api_fixtures()->bearerHeaders(
        api_fixtures()->createAuthToken((int)$scenario['customer']['id'])
    );
    $laneId = (int)$scenario['lane']['id'];
    $v2TaskId = 900000 + $laneId;

    $sessionTask = (new \objects\selfserve_wash_session_tasks_o())->addSnapshot(
        (int)$scenario['session']['id'],
        $v2TaskId,
        'V2 path editor machine task',
        'Task exists only in the session snapshot.',
        ['MACHINE', 'PROGRAM_PICKER'],
        ['program_picker', 6, 'start'],
        (int)$scenario['product']['id'],
    );

    try {
        $response = api_client()
            ->post('/modules/self-serve/lane/services/allowed', [
                'lane_id' => $laneId,
                'task_ids' => [$v2TaskId],
            ], $headers)
            ->assertStatus(200)
            ->assertSuccess(true);

        expect($response->data()['allowed_services'] ?? [])->toBe([
            'MACHINE',
            'PROGRAM_PICKER',
        ]);
    } finally {
        $sessionTask->delete();
    }
});

it('derives allowed services from published v2 config task snapshots when no session exists yet', 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,
        'session' => [
            'status' => 'COMPLETED',
            'completed_at' => date('Y-m-d H:i:s'),
            'wash_started_at' => date('Y-m-d H:i:s'),
        ],
    ]);
    $headers = api_fixtures()->bearerHeaders(
        api_fixtures()->createAuthToken((int)$scenario['customer']['id'])
    );
    $laneId = (int)$scenario['lane']['id'];
    $departmentId = (int)$scenario['department']['id'];
    $productId = (int)$scenario['product']['id'];
    $v2TaskId = 910000 + $laneId;

    $configVersion = (new \objects\selfserve_config_versions_o())->add(
        $departmentId,
        \modules\selfserve\classes\selfserve_config_versioning::STATUS_PUBLISHED,
        1,
        [
            'schema_version' => 2,
            'tasks' => [
                [
                    'id' => $v2TaskId,
                    'department' => $departmentId,
                    'lane' => $laneId,
                    'product' => $productId,
                    'machine_type_id' => 0,
                    'task' => 'Published v2 machine task',
                    'description' => 'Task exists only in the published config snapshot.',
                    'order_priority' => 10,
                    'services' => ['MACHINE', 'PROGRAM_PICKER'],
                ],
            ],
        ],
        null,
        null,
        null,
        date('Y-m-d H:i:s'),
    );

    try {
        $response = api_client()
            ->post('/modules/self-serve/lane/services/allowed', [
                'lane_id' => $laneId,
                'task_ids' => [$v2TaskId],
            ], $headers)
            ->assertStatus(200)
            ->assertSuccess(true);

        expect($response->data()['allowed_services'] ?? [])->toBe([
            'MACHINE',
            'PROGRAM_PICKER',
        ]);
    } finally {
        $configVersion->delete();
    }
});

it('keeps questions visible but disables machine services and tasks when machine wash is globally 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' => true,
        'machine_wash_enabled' => false,
    ]);
    $headers = api_fixtures()->bearerHeaders(
        api_fixtures()->createAuthToken((int)$scenario['customer']['id'])
    );
    $laneId = (int)$scenario['lane']['id'];
    $reg = (string)$scenario['vehicle']['reg'];
    $productId = (int)$scenario['product']['id'];
    $machineTaskId = (int)$scenario['tasks'][1]['id'];

    $allowedResponse = api_client()
        ->get(
            '/department/selfserve/vehicle/allowed?lane_id=' . $laneId
                . '&reg=' . urlencode($reg)
                . '&vehicle_type=' . $productId,
            $headers
        )
        ->assertStatus(200)
        ->assertSuccess(true);

    expect($allowedResponse->data()['questions'] ?? [])->not->toBeEmpty()
        ->and($allowedResponse->data()['allowed_services'] ?? [])->not->toContain('MACHINE')
        ->and($allowedResponse->data()['machine_available'] ?? null)->toBeFalse()
        ->and($allowedResponse->data()['machine_wash_enabled'] ?? null)->toBeFalse()
        ->and($allowedResponse->data()['allowed'] ?? null)->toBeFalse();

    foreach ($allowedResponse->data()['tasks'] ?? [] as $task) {
        expect($task['services'] ?? [])->not->toContain('MACHINE');
    }

    $serviceResponse = api_client()
        ->post('/modules/self-serve/lane/services/allowed', [
            'lane_id' => $laneId,
            'task_ids' => [$machineTaskId],
        ], $headers)
        ->assertStatus(200)
        ->assertSuccess(true);

    expect($serviceResponse->data()['allowed_services'] ?? [])->not->toContain('MACHINE');
});

it('keeps long generated task descriptions when refreshing vehicle eligibility snapshots', 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,
    ]);
    $headers = api_fixtures()->bearerHeaders(
        api_fixtures()->createAuthToken((int)$scenario['customer']['id'])
    );
    $laneId = (int)$scenario['lane']['id'];
    $reg = (string)$scenario['vehicle']['reg'];
    $productId = (int)$scenario['product']['id'];
    $taskId = (int)$scenario['tasks'][1]['id'];
    $longDescription = str_repeat('Hvis ja - vaelg tagboerste program (#6) og lift program (#2) / ', 6);

    $statement = api_test_runtime()->db()->prepare(
        'UPDATE department_selfserve_tasks SET description = ? WHERE id = ?'
    );
    $statement->bind_param('si', $longDescription, $taskId);
    $statement->execute();

    api_client()
        ->get(
            '/department/selfserve/vehicle/allowed?lane_id=' . $laneId
                . '&reg=' . urlencode($reg)
                . '&vehicle_type=' . $productId,
            $headers
        )
        ->assertStatus(200)
        ->assertSuccess(true);

    $sessionTask = api_test_runtime()->queryOne(
        'SELECT description FROM selfserve_wash_session_tasks'
            . ' WHERE session_id = ' . (int)$scenario['session']['id']
            . ' AND task_id = ' . $taskId
            . ' LIMIT 1'
    );

    expect($sessionTask['description'] ?? null)->toBe($longDescription);
});

it('does not create an active wash preview session from read-only eligibility checks', 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,
    ]);
    $headers = api_fixtures()->bearerHeaders(
        api_fixtures()->createAuthToken((int)$scenario['customer']['id'])
    );
    $laneId = (int)$scenario['lane']['id'];
    $reg = (string)$scenario['vehicle']['reg'];
    $productId = (int)$scenario['product']['id'];
    $sessionId = (int)$scenario['session']['id'];

    api_test_runtime()->db()->query(
        'DELETE FROM selfserve_wash_session_events WHERE session_id = ' . $sessionId
    );
    api_test_runtime()->db()->query(
        'DELETE FROM selfserve_wash_session_tasks WHERE session_id = ' . $sessionId
    );
    api_test_runtime()->db()->query(
        'DELETE FROM selfserve_wash_session_answers WHERE session_id = ' . $sessionId
    );
    api_test_runtime()->db()->query(
        'DELETE FROM selfserve_wash_sessions WHERE id = ' . $sessionId
    );

    selfserve_customer_start_make_available($laneId);

    api_client()
        ->get(
            '/department/selfserve/vehicle/allowed?lane_id=' . $laneId
                . '&reg=' . urlencode($reg)
                . '&vehicle_type=' . $productId,
            $headers
        )
        ->assertStatus(200)
        ->assertSuccess(true);

    $openSession = api_test_runtime()->queryOne(
        'SELECT id FROM selfserve_wash_sessions'
            . ' WHERE lane_id = ' . $laneId
            . ' AND reg = "' . api_test_runtime()->db()->real_escape_string($reg) . '"'
            . ' AND completed_at IS NULL'
            . ' AND deleted_at IS NULL'
            . ' LIMIT 1'
    );

    expect($openSession)->toBeNull();
});

it('creates a durable wash session from customer start after read-only eligibility', 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,
    ]);
    $headers = api_fixtures()->bearerHeaders(
        api_fixtures()->createAuthToken((int)$scenario['customer']['id'])
    );
    $laneId = (int)$scenario['lane']['id'];
    $reg = (string)$scenario['vehicle']['reg'];
    $productId = (int)$scenario['product']['id'];
    $sessionId = (int)$scenario['session']['id'];

    api_test_runtime()->db()->query(
        'DELETE FROM selfserve_wash_session_events WHERE session_id = ' . $sessionId
    );
    api_test_runtime()->db()->query(
        'DELETE FROM selfserve_wash_session_tasks WHERE session_id = ' . $sessionId
    );
    api_test_runtime()->db()->query(
        'DELETE FROM selfserve_wash_session_answers WHERE session_id = ' . $sessionId
    );
    api_test_runtime()->db()->query(
        'DELETE FROM selfserve_wash_sessions WHERE id = ' . $sessionId
    );

    selfserve_customer_start_make_available($laneId);

    api_client()
        ->get(
            '/department/selfserve/vehicle/allowed?lane_id=' . $laneId
                . '&reg=' . urlencode($reg)
                . '&vehicle_type=' . $productId,
            $headers
        )
        ->assertStatus(200)
        ->assertSuccess(true);

    api_client()
        ->post('/modules/self-serve/lane/command', [
            'lane_id' => $laneId,
            'command' => 'START',
            'license_plate' => $reg,
            'defer_relay_side_effects' => true,
        ], $headers)
        ->assertStatus(200)
        ->assertSuccess(true);

    $openSession = api_test_runtime()->queryOne(
        'SELECT id, status, customer_number FROM selfserve_wash_sessions'
            . ' WHERE lane_id = ' . $laneId
            . ' AND reg = "' . api_test_runtime()->db()->real_escape_string($reg) . '"'
            . ' AND completed_at IS NULL'
            . ' AND deleted_at IS NULL'
            . ' ORDER BY id DESC LIMIT 1'
    );

    expect($openSession)->not->toBeNull()
        ->and((int)$openSession['customer_number'])->toBe((int)$scenario['customer']['customer_number'])
        ->and($openSession['status'])->toBe('READY_FOR_MACHINE_START');

    selfserve_customer_start_make_available($laneId);
});

it('refreshes an active wash summary with vehicle type without a namespace error', 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,
        'session' => [
            'status' => 'MACHINE_RELAY_ENABLED',
            'machine_relay_enabled' => 1,
            'machine_relay_enabled_at' => date('Y-m-d H:i:s'),
            'completed_at' => null,
        ],
    ]);
    $headers = api_fixtures()->bearerHeaders(
        api_fixtures()->createAuthToken((int)$scenario['customer']['id'])
    );
    $sessionId = (int)$scenario['session']['id'];
    $productId = (int)$scenario['product']['id'];

    $summaryResponse = api_client()
        ->get(
            '/department/selfserve/washes/summary?session_id=' . $sessionId
                . '&vehicle_type=' . $productId,
            $headers
        )
        ->assertStatus(200)
        ->assertSuccess(true);

    expect($summaryResponse->data()['session']['id'] ?? null)->toBe($sessionId)
        ->and($summaryResponse->data()['session']['status'] ?? null)->toBe('MACHINE_RELAY_ENABLED');
});

it('does not create a replacement session when refreshing a completed summary with vehicle type', 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,
        'session' => [
            'status' => 'COMPLETED',
            'completed_at' => date('Y-m-d H:i:s'),
        ],
    ]);
    $headers = api_fixtures()->bearerHeaders(
        api_fixtures()->createAuthToken((int)$scenario['customer']['id'])
    );
    $laneId = (int)$scenario['lane']['id'];
    $reg = (string)$scenario['vehicle']['reg'];
    $productId = (int)$scenario['product']['id'];
    $sessionId = (int)$scenario['session']['id'];

    selfserve_customer_start_make_available($laneId);

    $summaryResponse = api_client()
        ->get(
            '/department/selfserve/washes/summary?lane_id=' . $laneId
                . '&reg=' . urlencode($reg)
                . '&vehicle_type=' . $productId,
            $headers
        )
        ->assertStatus(200)
        ->assertSuccess(true);

    expect($summaryResponse->data()['session']['id'] ?? null)->toBe($sessionId)
        ->and($summaryResponse->data()['session']['status'] ?? null)->toBe('COMPLETED');

    $openSession = api_test_runtime()->queryOne(
        'SELECT id FROM selfserve_wash_sessions'
            . ' WHERE lane_id = ' . $laneId
            . ' AND reg = "' . api_test_runtime()->db()->real_escape_string($reg) . '"'
            . ' AND completed_at IS NULL'
            . ' AND deleted_at IS NULL'
            . ' LIMIT 1'
    );

    expect($openSession)->toBeNull();
});
