<?php

$_SERVER['REQUEST_URI'] = $_SERVER['REQUEST_URI'] ?? '/';

app_require('routes/birdVoiceWebhooksRoute.php');

final class BirdVoiceWebhookRouteTestDouble extends \routes\birdVoiceWebhooksRoute
{
    public array $departmentNames = [];
    public array $rawState = [];
    public array $ttls = [];

    public function mapDepartments(array $ids): array
    {
        return $this->buildDepartmentOptionMap($ids);
    }

    public function departmentPrompt(array $map): string
    {
        return $this->buildDepartmentPromptText($map);
    }

    public function gatePrompt(string $name): string
    {
        return $this->buildGateTypePromptText($name);
    }

    public function gatePromptForOptions(string $name, array $options): string
    {
        return $this->buildGateTypePromptText($name, $options);
    }

    public function selectDepartment(array $map, string $digit): ?int
    {
        return $this->resolveDepartmentIdByDigit($map, $digit);
    }

    public function selectGateType(string $digit, array $options = []): ?string
    {
        return $this->resolveGateTypeByDigit($digit, $options);
    }

    public function mapGateOptions(array $types): array
    {
        return $this->buildGateOptionMap($types);
    }

    public function normalizeMenuDigit(?string $input): ?string
    {
        return $this->normalizeMenuDigitInput($input);
    }

    public function storeState(string $callId, array $state): void
    {
        $this->saveIvrState($callId, $state);
    }

    public function loadState(string $callId): ?array
    {
        return $this->readIvrState($callId);
    }

    public function removeState(string $callId): void
    {
        $this->clearIvrState($callId);
    }

    public function stateKey(string $callId): string
    {
        return $this->ivrStateKey($callId);
    }

    protected function getDepartmentNameById(int $departmentId): string
    {
        return $this->departmentNames[$departmentId] ?? ('Department ' . $departmentId);
    }

    protected function writeIvrStateRaw(string $key, string $value, int $ttlSeconds): void
    {
        $this->rawState[$key] = $value;
        $this->ttls[$key] = $ttlSeconds;
    }

    protected function readIvrStateRaw(string $key): ?string
    {
        return $this->rawState[$key] ?? null;
    }

    protected function deleteIvrStateRaw(string $key): void
    {
        unset($this->rawState[$key], $this->ttls[$key]);
    }
}

it('builds deterministic department digit map without capping options', function (): void {
    $route = new BirdVoiceWebhookRouteTestDouble();
    $route->departmentNames = [
        11 => 'Nord',
        22 => 'Syd',
        33 => 'Vest',
        44 => 'Ost',
        55 => 'Midt',
        66 => 'Aalborg',
        77 => 'Odense',
        88 => 'Esbjerg',
        99 => 'Kolding',
        111 => 'Roskilde',
    ];

    $map = $route->mapDepartments([
        ['department_id' => 11, 'department_name' => 'Nord', 'has_entrance_gate' => true, 'has_exit_gate' => false],
        ['department_id' => 22, 'department_name' => 'Syd', 'has_entrance_gate' => false, 'has_exit_gate' => true],
        0,
        -5,
        ['department_id' => 33, 'department_name' => 'Vest', 'has_entrance_gate' => true, 'has_exit_gate' => true],
        44,
        55,
        66,
        77,
        88,
        99,
        111,
    ]);

    expect($map)->toHaveCount(10);
    expect(array_keys($map))->toBe([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
    expect($map['1']['department_id'])->toBe(11);
    expect($map['2']['department_id'])->toBe(22);
    expect($map['3']['department_id'])->toBe(33);
    expect($map['10']['department_id'])->toBe(111);
    expect($map['1']['department_name'])->toBe('Nord');
    expect($map['2']['department_name'])->toBe('Syd');
    expect($map['3']['department_name'])->toBe('Vest');
    expect($map['10']['department_name'])->toBe('Roskilde');
    expect($map['1']['has_entrance_gate'])->toBeTrue();
    expect($map['1']['has_exit_gate'])->toBeFalse();
    expect($map['2']['has_entrance_gate'])->toBeFalse();
    expect($map['2']['has_exit_gate'])->toBeTrue();
});

it('resolves department ids by selected digit', function (): void {
    $route = new BirdVoiceWebhookRouteTestDouble();
    $map = [
        '1' => ['department_id' => 101, 'department_name' => 'A'],
        '2' => ['department_id' => 202, 'department_name' => 'B'],
    ];

    expect($route->selectDepartment($map, '1'))->toBe(101);
    expect($route->selectDepartment($map, '2'))->toBe(202);
    expect($route->selectDepartment($map + ['10' => ['department_id' => 1001, 'department_name' => 'J']], '10'))->toBe(1001);
    expect($route->selectDepartment($map, '9'))->toBeNull();
    expect($route->selectDepartment($map, ''))->toBeNull();
});

it('builds compact gate option maps and resolves selected gate type by digit', function (): void {
    $route = new BirdVoiceWebhookRouteTestDouble();
    $both = $route->mapGateOptions(['entrance', 'exit']);
    $exitOnly = $route->mapGateOptions(['exit']);
    $entranceOnly = $route->mapGateOptions(['entrance']);

    expect($both)->toBe(['1' => 'entrance', '2' => 'exit']);
    expect($exitOnly)->toBe(['1' => 'exit']);
    expect($entranceOnly)->toBe(['1' => 'entrance']);

    expect($route->selectGateType('1', $both))->toBe('entrance');
    expect($route->selectGateType('2', $both))->toBe('exit');
    expect($route->selectGateType('1', $exitOnly))->toBe('exit');
    expect($route->selectGateType('2', $exitOnly))->toBeNull();
    expect($route->selectGateType('0', $both))->toBeNull();
    expect($route->selectGateType('x', $both))->toBeNull();
});

it('stores, loads and clears ivr state with ttl', function (): void {
    $route = new BirdVoiceWebhookRouteTestDouble();
    $callId = 'abc-123';
    $state = [
        'stage' => 'department_select',
        'department_options' => ['1' => ['department_id' => 5, 'department_name' => 'North']],
        'gate_options' => ['1' => 'entrance'],
        'gather_template' => ['timeout' => 30],
    ];

    $route->storeState($callId, $state);

    $key = $route->stateKey($callId);
    expect($route->loadState($callId))->toBe($state);
    expect($route->ttls[$key] ?? null)->toBe(1200);

    $route->removeState($callId);
    expect($route->loadState($callId))->toBeNull();
});

it('builds department prompts with multi-digit guidance and compact gate prompts', function (): void {
    $route = new BirdVoiceWebhookRouteTestDouble();

    $prompt = $route->departmentPrompt([
        '1' => ['department_id' => 1, 'department_name' => 'Nord'],
        '2' => ['department_id' => 2, 'department_name' => 'Syd'],
        '3' => ['department_id' => 3, 'department_name' => 'Vest'],
        '4' => ['department_id' => 4, 'department_name' => 'Ost'],
        '5' => ['department_id' => 5, 'department_name' => 'Midt'],
        '6' => ['department_id' => 6, 'department_name' => 'Aalborg'],
        '7' => ['department_id' => 7, 'department_name' => 'Odense'],
        '8' => ['department_id' => 8, 'department_name' => 'Esbjerg'],
        '9' => ['department_id' => 9, 'department_name' => 'Kolding'],
        '10' => ['department_id' => 10, 'department_name' => 'Roskilde'],
    ]);

    expect($prompt)->toContain('Choose department.');
    expect($prompt)->toContain('Enter the option number followed by pound.');
    expect($prompt)->toContain('Press 1 for Nord');
    expect($prompt)->toContain('Press 10 for Roskilde');

    $gatePrompt = $route->gatePromptForOptions('Nord', ['1' => 'exit']);
    expect($gatePrompt)->toContain('You selected Nord.');
    expect($gatePrompt)->toContain('Press 1 for exit.');
    expect($gatePrompt)->not->toContain('Press 2 for exit.');
});

it('normalizes menu digit input from Bird dtmf payload values', function (): void {
    $route = new BirdVoiceWebhookRouteTestDouble();

    expect($route->normalizeMenuDigit('1'))->toBe('1');
    expect($route->normalizeMenuDigit('1#'))->toBe('1');
    expect($route->normalizeMenuDigit(' 2## '))->toBe('2');
    expect($route->normalizeMenuDigit('10#'))->toBe('10');
    expect($route->normalizeMenuDigit('12#'))->toBe('12');
    expect($route->normalizeMenuDigit('09'))->toBeNull();
    expect($route->normalizeMenuDigit('*'))->toBeNull();
    expect($route->normalizeMenuDigit(null))->toBeNull();
});
