<?php

declare(strict_types=1);

usesApiSuite();

function disable_bird_transport_for_api_test(): void
{
    api_fixtures()->setModuleConfig('bird', 'enabled', 'false');
}

it('returns the raw 202 gather webhook contract over HTTP', function (): void {
    api_test_covers('POST /bird/voice/calls/webhook/inbound', 'happy');

    disable_bird_transport_for_api_test();

    $session = api_fixtures()->createUserSession(['modules_bird_voice_call_webhooks_trigger']);
    $north = api_fixtures()->createDepartment([
        'name' => 'North HTTP',
        'order_priority' => 1,
    ]);
    $south = api_fixtures()->createDepartment([
        'name' => 'South HTTP',
        'order_priority' => 2,
    ]);

    api_fixtures()->createDepartmentGate([
        'department' => $north['id'],
        'is_entrance' => true,
        'is_exit' => false,
        'name' => 'North Gate',
        'config' => [
            'type' => 'PHONE_CALL',
            'phone_number' => '+4511111111',
            'call_duration_threshold' => 5,
        ],
    ]);
    api_fixtures()->createDepartmentGate([
        'department' => $south['id'],
        'is_entrance' => true,
        'is_exit' => false,
        'name' => 'South Gate',
        'config' => [
            'type' => 'PHONE_CALL',
            'phone_number' => '+4522222222',
            'call_duration_threshold' => 5,
        ],
    ]);

    $response = api_client()->post('/bird/voice/calls/webhook/inbound', [
        'payload' => [
            'endKey' => '#',
            'input' => 'dtmf',
            'maxNumKeys' => 1,
            'retries' => 3,
            'say' => [
                'locale' => 'en-US',
                'voice' => 'female',
            ],
            'speechLocale' => 'en-US',
            'timeout' => 30,
        ],
        'request' => [
            'callId' => '212c606f-a906-4a50-be0b-db95d74f2ffd',
            'channelId' => 'a2545e48-fe8c-5741-9bdc-42a081076bc9',
            'workspaceId' => '3d5fae4f-9c2d-41aa-9840-28b18e6a94bc',
        ],
        'waitConditions' => [
            'events' => [
                [
                    'action' => 'continue',
                    'name' => 'call_command_gather_finished',
                ],
            ],
            'timeout' => 'PT10M',
        ],
    ], $session['headers']);

    $response->assertStatus(202);

    expect($response->headers['content-type'] ?? '')->toContain('application/json');
    expect($response->json)->toBeArray();
    expect($response->json)->not->toHaveKey('success');
    expect($response->json['statusCode'] ?? null)->toBe(202);
    expect($response->json['statusText'] ?? null)->toBe('Accepted');
    expect($response->json['result']['status'] ?? null)->toBe('accepted');
    expect($response->json['event']['callCommand']['type'] ?? null)->toBe('gather');
    expect($response->json['event']['callCommand']['gather']['input'] ?? null)->toBe('dtmf');
    expect($response->json['event']['callCommand']['gather']['maxNumKeys'] ?? null)->toBe(1);
    expect($response->json['event']['callCommand']['gather']['say']['locale'] ?? null)->toBe('en-US');
    expect($response->json['event']['callCommand']['gather']['say']['voice'] ?? null)->toBe('female');
    expect($response->json['event']['callCommand']['gather']['say']['text'] ?? null)->toContain('Choose department.');
});

it('still prompts for department selection when only one department is eligible', function (): void {
    disable_bird_transport_for_api_test();

    $session = api_fixtures()->createUserSession(['modules_bird_voice_call_webhooks_trigger']);
    $solo = api_fixtures()->createDepartment([
        'name' => 'Solo HTTP',
        'order_priority' => 1,
    ]);

    api_fixtures()->createDepartmentGate([
        'department' => $solo['id'],
        'is_entrance' => true,
        'is_exit' => false,
        'name' => 'Solo Gate',
        'config' => [
            'type' => 'PHONE_CALL',
            'phone_number' => '+4533333333',
            'call_duration_threshold' => 5,
        ],
    ]);

    $response = api_client()->post('/bird/voice/calls/webhook/inbound', [
        'payload' => [
            'endKey' => '#',
            'retries' => 3,
            'timeout' => 30,
        ],
        'request' => [
            'callId' => '212c606f-a906-4a50-be0b-db95d74f2ffe',
            'channelId' => 'a2545e48-fe8c-5741-9bdc-42a081076bc9',
            'workspaceId' => '3d5fae4f-9c2d-41aa-9840-28b18e6a94bc',
        ],
        'waitConditions' => [
            'events' => [
                [
                    'action' => 'continue',
                    'name' => 'call_command_gather_finished',
                ],
            ],
            'timeout' => 'PT10M',
        ],
    ], $session['headers']);

    $response->assertStatus(202);

    expect($response->json['event']['callCommand']['gather']['maxNumKeys'] ?? null)->toBe(1);
    expect($response->json['event']['callCommand']['gather']['say']['text'] ?? null)->toContain('Choose department.');
    expect($response->json['event']['callCommand']['gather']['say']['text'] ?? null)->toContain('Press 1 for Solo HTTP.');
});

it('accepts the legacy initial webhook body with top-level call identifiers', function (): void {
    disable_bird_transport_for_api_test();

    $session = api_fixtures()->createUserSession(['modules_bird_voice_call_webhooks_trigger']);
    $solo = api_fixtures()->createDepartment([
        'name' => 'Legacy HTTP',
        'order_priority' => 1,
    ]);

    api_fixtures()->createDepartmentGate([
        'department' => $solo['id'],
        'is_entrance' => true,
        'is_exit' => false,
        'name' => 'Legacy Gate',
        'config' => [
            'type' => 'PHONE_CALL',
            'phone_number' => '+4533333399',
            'call_duration_threshold' => 5,
        ],
    ]);

    $response = api_client()->post('/bird/voice/calls/webhook/inbound', [
        'callId' => '212c606f-a906-4a50-be0b-db95d74f2ff1',
        'channelId' => 'a2545e48-fe8c-5741-9bdc-42a081076bc9',
        'workspaceId' => '3d5fae4f-9c2d-41aa-9840-28b18e6a94bc',
    ], $session['headers']);

    $response->assertStatus(200);

    expect($response->json['status'] ?? null)->toBe('gather');
    expect($response->json['completed'] ?? null)->toBeFalse();
    expect($response->json['stage'] ?? null)->toBe('department_select');
    expect($response->json['gather']['input'] ?? null)->toBe('dtmf');
    expect($response->json['gather']['maxNumKeys'] ?? null)->toBe(1);
    expect($response->json['gather']['retries'] ?? null)->toBe(3);
    expect($response->json['gather']['timeout'] ?? null)->toBe(30);
    expect($response->json['gather']['endKey'] ?? null)->toBe('#');
    expect($response->json['gatherInput'] ?? null)->toBe('dtmf');
    expect($response->json['gatherMaxNumKeys'] ?? null)->toBe(1);
    expect($response->json['gatherRetries'] ?? null)->toBe(3);
    expect($response->json['gatherTimeout'] ?? null)->toBe(30);
    expect($response->json['gatherEndKey'] ?? null)->toBe('#');
    expect($response->json['gatherSayLocale'] ?? null)->toBe('en-US');
    expect($response->json['gatherSayVoice'] ?? null)->toBe('female');
    expect($response->json['gather']['say']['locale'] ?? null)->toBe('en-US');
    expect($response->json['gather']['say']['voice'] ?? null)->toBe('female');
    expect($response->json['gather']['say']['text'] ?? null)->toContain('Choose department.');
    expect($response->json['gather']['say']['text'] ?? null)->toContain('Press 1 for Legacy HTTP.');
});

it('returns native flow gather data after a top-level department selection when distinct gate choices exist', function (): void {
    disable_bird_transport_for_api_test();

    $session = api_fixtures()->createUserSession(['modules_bird_voice_call_webhooks_trigger']);
    $north = api_fixtures()->createDepartment([
        'name' => 'North Flow',
        'order_priority' => 1,
    ]);
    $south = api_fixtures()->createDepartment([
        'name' => 'South Flow',
        'order_priority' => 2,
    ]);

    api_fixtures()->createDepartmentGate([
        'department' => $north['id'],
        'is_entrance' => true,
        'is_exit' => false,
        'name' => 'North Entrance',
        'config' => [
            'type' => 'PHONE_CALL',
            'phone_number' => '+4511111199',
            'call_duration_threshold' => 5,
        ],
    ]);
    api_fixtures()->createDepartmentGate([
        'department' => $north['id'],
        'is_entrance' => false,
        'is_exit' => true,
        'name' => 'North Exit',
        'config' => [
            'type' => 'PHONE_CALL',
            'phone_number' => '+4511111188',
            'call_duration_threshold' => 5,
        ],
    ]);
    api_fixtures()->createDepartmentGate([
        'department' => $south['id'],
        'is_entrance' => true,
        'is_exit' => false,
        'name' => 'South Entrance',
        'config' => [
            'type' => 'PHONE_CALL',
            'phone_number' => '+4522222299',
            'call_duration_threshold' => 5,
        ],
    ]);

    $callId = 'bird-flow-' . bin2hex(random_bytes(8));
    $initialResponse = api_client()->post('/bird/voice/calls/webhook/inbound', [
        'callId' => $callId,
        'channelId' => 'a2545e48-fe8c-5741-9bdc-42a081076bc9',
        'workspaceId' => '3d5fae4f-9c2d-41aa-9840-28b18e6a94bc',
    ], $session['headers']);

    $initialResponse->assertStatus(200);

    $prompt = (string)($initialResponse->json['prompt'] ?? '');
    expect($prompt)->toContain('Press 1 for North Flow.');

    $response = api_client()->post('/bird/voice/calls/webhook/inbound', [
        'callId' => $callId,
        'channelId' => 'a2545e48-fe8c-5741-9bdc-42a081076bc9',
        'workspaceId' => '3d5fae4f-9c2d-41aa-9840-28b18e6a94bc',
        'keys' => '1',
    ], $session['headers']);

    $response->assertStatus(200);

    expect($response->json['status'] ?? null)->toBe('gather');
    expect($response->json['completed'] ?? null)->toBeFalse();
    expect($response->json['stage'] ?? null)->toBe('gate_type_select');
    expect($response->json['prompt'] ?? null)->toContain('You selected North Flow.');
    expect($response->json['gather']['say']['text'] ?? null)->toContain('Press 1 for entrance. Press 2 for exit.');
    expect($response->json['selection']['departmentId'] ?? null)->toBe((int)$north['id']);
    expect($response->json['selection']['departmentName'] ?? null)->toBe('North Flow');
});

it('opens the gate immediately after a top-level department selection when entrance and exit share the same gate', function (): void {
    disable_bird_transport_for_api_test();

    $session = api_fixtures()->createUserSession(['modules_bird_voice_call_webhooks_trigger']);
    $shared = api_fixtures()->createDepartment([
        'name' => 'Shared Flow',
        'order_priority' => 1,
    ]);

    $sharedGate = api_fixtures()->createDepartmentGate([
        'department' => $shared['id'],
        'is_entrance' => true,
        'is_exit' => true,
        'name' => 'Shared Both',
        'config' => [
            'type' => 'PHONE_CALL',
            'phone_number' => '+4511111177',
            'call_duration_threshold' => 5,
        ],
    ]);

    $callId = 'bird-shared-' . bin2hex(random_bytes(8));
    $initialResponse = api_client()->post('/bird/voice/calls/webhook/inbound', [
        'callId' => $callId,
        'channelId' => 'a2545e48-fe8c-5741-9bdc-42a081076bc9',
        'workspaceId' => '3d5fae4f-9c2d-41aa-9840-28b18e6a94bc',
    ], $session['headers']);

    $initialResponse->assertStatus(200);

    $prompt = (string)($initialResponse->json['prompt'] ?? '');
    expect($prompt)->toContain('Press 1 for Shared Flow.');

    $response = api_client()->post('/bird/voice/calls/webhook/inbound', [
        'callId' => $callId,
        'channelId' => 'a2545e48-fe8c-5741-9bdc-42a081076bc9',
        'workspaceId' => '3d5fae4f-9c2d-41aa-9840-28b18e6a94bc',
        'keys' => '1',
    ], $session['headers']);

    $response->assertStatus(200);

    expect($response->json['status'] ?? null)->toBeIn(['completed', 'failed']);
    expect($response->json['completed'] ?? null)->toBeTrue();
    expect($response->json['action'] ?? null)->toBeIn(['gate_opened', 'gate_open_failed']);
    expect($response->json['departmentId'] ?? null)->toBe((int)$shared['id']);
    expect($response->json['departmentName'] ?? null)->toBe('Shared Flow');
    expect($response->json['gateType'] ?? null)->toBeNull();
    expect($response->json['gateId'] ?? null)->toBe((int)$sharedGate['id']);
});

it('uses a multi-digit gather contract when 10 departments are eligible', function (): void {
    disable_bird_transport_for_api_test();

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

    for ($index = 1; $index <= 10; $index++) {
        $department = api_fixtures()->createDepartment([
            'name' => 'Department ' . $index . ' HTTP',
            'order_priority' => $index,
        ]);

        api_fixtures()->createDepartmentGate([
            'department' => $department['id'],
            'is_entrance' => true,
            'is_exit' => false,
            'name' => 'Gate ' . $index,
            'config' => [
                'type' => 'PHONE_CALL',
                'phone_number' => sprintf('+45444444%02d', $index),
                'call_duration_threshold' => 5,
            ],
        ]);
    }

    $response = api_client()->post('/bird/voice/calls/webhook/inbound', [
        'payload' => [
            'endKey' => '#',
            'retries' => 3,
            'timeout' => 30,
        ],
        'request' => [
            'callId' => '212c606f-a906-4a50-be0b-db95d74f2fff',
            'channelId' => 'a2545e48-fe8c-5741-9bdc-42a081076bc9',
            'workspaceId' => '3d5fae4f-9c2d-41aa-9840-28b18e6a94bc',
        ],
        'waitConditions' => [
            'events' => [
                [
                    'action' => 'continue',
                    'name' => 'call_command_gather_finished',
                ],
            ],
            'timeout' => 'PT10M',
        ],
    ], $session['headers']);

    $response->assertStatus(202);

    expect($response->json['event']['callCommand']['gather']['maxNumKeys'] ?? null)->toBe(2);
    expect($response->json['event']['callCommand']['gather']['say']['text'] ?? null)->toContain('Enter the option number followed by pound.');
    expect(preg_match(
        '/Press [1-9][0-9]+ for Department 10 HTTP\./',
        (string)($response->json['event']['callCommand']['gather']['say']['text'] ?? '')
    ))->toBe(1);
});

it('returns a raw 400 transport error for malformed webhook payloads', function (): void {
    api_test_covers('POST /bird/voice/calls/webhook/inbound', 'failure');

    disable_bird_transport_for_api_test();

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

    $response = api_client()->post('/bird/voice/calls/webhook/inbound', [
        'request' => [
            'callId' => 'broken',
        ],
    ], $session['headers']);

    $response->assertStatus(400);

    expect($response->headers['content-type'] ?? '')->toContain('application/json');
    expect($response->json)->toBeArray();
    expect($response->json)->not->toHaveKey('success');
    expect($response->json['statusCode'] ?? null)->toBe(400);
    expect($response->json['statusText'] ?? null)->toBe('Bad Request');
    expect($response->json['error']['message'] ?? null)->toContain('Malformed inbound Bird webhook payload');
});
