<?php

function selfserve_openapi_content_or_skip(): string
{
    $candidates = [
        dirname(__DIR__, 6) . DIRECTORY_SEPARATOR . 'openapi.yaml',
        dirname(__DIR__, 5) . DIRECTORY_SEPARATOR . 'openapi.yaml',
        dirname(__DIR__, 4) . DIRECTORY_SEPARATOR . 'openapi.yaml',
        dirname(__DIR__, 3) . DIRECTORY_SEPARATOR . 'openapi.yaml',
        dirname(__DIR__, 2) . DIRECTORY_SEPARATOR . 'openapi.yaml',
    ];

    foreach ($candidates as $candidate) {
        if (!is_file($candidate)) {
            continue;
        }

        $content = file_get_contents($candidate);
        if ($content !== false) {
            return $content;
        }
    }

    test()->markTestSkipped('openapi.yaml is not available in this runtime environment.');
}

function selfserve_openapi_path_block_or_fail(string $content, string $path): string
{
    $path_marker = '  ' . $path . ':';
    $start = strpos($content, $path_marker);
    if ($start === false) {
        throw new RuntimeException("OpenAPI path block not found: {$path}");
    }

    $rest = substr($content, $start + strlen($path_marker));
    $next_path = strpos($rest, "\n  /");
    if ($next_path === false) {
        return substr($content, $start);
    }

    return substr($content, $start, strlen($path_marker) + $next_path);
}

it('documents self-serve machine type, eligibility, summary, and webhook endpoints', function (): void {
    $content = selfserve_openapi_content_or_skip();
    $allowedPathBlock = selfserve_openapi_path_block_or_fail($content, '/department/selfserve/vehicle/allowed');
    $summaryPathBlock = selfserve_openapi_path_block_or_fail($content, '/department/selfserve/washes/summary');

    expect($content)->toContain('/department/selfserve/machine-types:');
    expect($content)->toContain('/department/selfserve/vehicle/allowed:');
    expect($content)->toContain('/department/selfserve/washes/summary:');
    expect($content)->toContain('/relay/button/press/post:');
    expect($content)->toContain('/relay/machine/on/post:');
    expect($content)->toContain('/modules/self-serve/lane/wash/in-progress:');
    expect($content)->toContain('/modules/self-serve/lane/wash/my-active-wash:');
    expect($content)->toContain('/modules/self-serve/lane/relay/machine/status:');
    expect($content)->toContain('/modules/self-serve/lane/relay/machine/set:');
    expect($content)->toContain('/modules/self-serve/lane/gate/open:');
    expect($content)->toContain('/modules/self-serve/lane/relay/machine_program_picker/status:');
    expect($content)->toContain('/modules/self-serve/lane/relay/machine_program_picker/set:');
    expect($content)->toContain('/modules/self-serve/lane/relay/machine_cleaner/status:');
    expect($content)->toContain('/modules/self-serve/lane/relay/machine_cleaner/set:');
    expect($allowedPathBlock)->toContain('name: vehicle_type_id');
    expect($allowedPathBlock)->toContain('name: vehicle_type');
    expect($allowedPathBlock)->toContain('may evaluate any registration plate');
    expect($allowedPathBlock)->toContain('Persisted self-serve answers are only applied');
    expect($summaryPathBlock)->toContain('name: vehicle_type_id');
    expect($summaryPathBlock)->toContain('name: vehicle_type');
});

it('documents the all-in-one self-serve studio replacement API', function (): void {
    $content = selfserve_openapi_content_or_skip();

    expect($content)->toContain('/department/selfserve/studio/graph:');
    expect($content)->toContain('/department/selfserve/studio/layout:');
    expect($content)->toContain('/department/selfserve/studio/validate:');
    expect($content)->toContain('/department/selfserve/studio/simulate:');
    expect($content)->toContain('/department/selfserve/studio/path-outcomes:');
    expect($content)->toContain('/department/selfserve/studio/path-outcomes/stream:');
    expect($content)->toContain('/department/selfserve/studio/path-confirmations:');
    expect($content)->toContain('/department/selfserve/studio/publish:');
    expect($content)->toContain('/department/selfserve/studio/rollback:');
    expect($content)->toContain('/department/selfserve/studio/gateway-action:');
    expect($content)->toContain('SelfserveStudioGraph:');
    expect($content)->toContain('SelfserveStudioGraphSaveRequest:');
    expect($content)->toContain('SelfserveStudioLayout:');
    expect($content)->toContain('SelfserveStudioPathOutcomesRequest:');
    expect($content)->toContain('SelfserveStudioPathOutcomesResponse:');
    expect($content)->toContain('SelfserveStudioPathResult:');
    expect($content)->toContain('SelfserveStudioPathProgress:');
    expect($content)->toContain('SelfserveStudioPathConfirmationRequest:');
    expect($content)->toContain('SelfserveStudioPathConfirmation:');
    expect($content)->toContain('projectSelfserveStudioPathOutcomes');
    expect($content)->toContain('streamSelfserveStudioPathOutcomes');
    expect($content)->toContain('confirmSelfserveStudioPath');
    expect($content)->toContain('runSelfserveStudioGatewayAction');
});

it('defines reusable self-serve wash and machine type schemas', function (): void {
    $content = selfserve_openapi_content_or_skip();

    expect($content)->toContain('SelfserveMachineType:');
    expect($content)->toContain('SelfserveVehicleAllowedResponse:');
    expect($content)->toContain('SelfserveWashSummary:');
    expect($content)->toContain('MachineButtonPressWebhookResponse:');
    expect($content)->toContain('DepartmentSelfserveVehicleConditionMutationResponse:');
    expect($content)->toContain('DepartmentLane:');
    expect($content)->toContain('selfserve_enabled:');
    expect($content)->toContain('blocked_reason:');
    expect($content)->toContain('machine_type_id:');
    expect($content)->toContain('SelfServeLaneMachineRelayStatus:');
    expect($content)->toContain('        wash_started_at:');
});

it('documents in-progress self-serve wash start and machine relay fields', function (): void {
    $content = selfserve_openapi_content_or_skip();
    $inProgressPathBlock = selfserve_openapi_path_block_or_fail($content, '/modules/self-serve/lane/wash/in-progress');

    expect($inProgressPathBlock)->toContain('included_minutes:');
    expect($inProgressPathBlock)->toContain('machine_relay_enabled:');
    expect($inProgressPathBlock)->toContain('machine_relay_enabled_at:');
    expect($inProgressPathBlock)->toContain('machine_start_triggered_at:');
    expect($inProgressPathBlock)->toContain('wash_started_at:');
});

it('documents self-serve machine wash included minutes in config schemas', function (): void {
    $content = selfserve_openapi_content_or_skip();

    expect($content)->toContain('SelfServeConfigEntry:');
    expect($content)->toContain('machine_wash_minutes_included');
    expect($content)->toContain('SelfServeConfig:');
});

it('documents property gate lane commands and sanitized gate failure responses', function (): void {
    $content = selfserve_openapi_content_or_skip();
    $commandPathBlock = selfserve_openapi_path_block_or_fail($content, '/modules/self-serve/lane/command');
    $gateOpenPathBlock = selfserve_openapi_path_block_or_fail($content, '/modules/self-serve/lane/gate/open');

    expect($commandPathBlock)->toContain('OPEN_PROPERTY_ACCESS_GATE');
    expect($commandPathBlock)->toContain('OPEN_PROPERTY_EXIT_GATE');
    expect($commandPathBlock)->toContain('wash_type:');
    expect($commandPathBlock)->toContain('wash_mode:');
    expect($commandPathBlock)->toContain('Command execution failed');
    expect($commandPathBlock)->toContain('Failed to execute command: Failed to open property access gate.');

    expect($gateOpenPathBlock)->toContain('Gate open failed');
    expect($gateOpenPathBlock)->toContain('Failed to open entrance gate.');
});
