<?php

declare(strict_types=1);

usesApiSuite();

it('serves whole-department expected relay states and records successful physical completion only', function (): void {
    $scenario = api_fixtures()->createSelfServeScenario([
        'department' => [
            'name' => 'Edge Expected State Department',
        ],
        'relay_ids' => [
            'entry' => 'expected-entry',
            'exit' => 'expected-exit',
            'machine' => 'expected-machine',
            'program_picker' => 'expected-program',
            'cleaner' => 'expected-cleaner',
        ],
    ]);
    $departmentId = (int)$scenario['department']['id'];
    $laneId = (int)$scenario['lane']['id'];
    api_fixtures()->setDepartmentShellyTransportMode($departmentId, 'gateway');
    $session = api_fixtures()->createEdgeOperatorSession($departmentId, [
        'modules_selfserve_lane_relay_machine_status_set',
        'modules_selfserve_lane_relay_machine_cleaner_status_set',
    ]);
    $gateway = api_fixtures()->createClaimedEdgeGateway([
        'department_id' => $departmentId,
        'label' => 'Expected State Gateway',
    ]);

    $relayIps = [
        'expected-entry' => '10.41.0.11',
        'expected-exit' => '10.41.0.12',
        'expected-machine' => '10.41.0.13',
        'expected-program' => '10.41.0.14',
        'expected-cleaner' => '10.41.0.15',
    ];
    foreach ($relayIps as $relayId => $ip) {
        api_fixtures()->createEdgeRelayBinding([
            'gateway_id' => (int)$gateway['id'],
            'department_id' => $departmentId,
            'relay_id' => $relayId,
            'device_id' => 'device-' . $relayId,
            'local_ip' => $ip,
            'metadata' => [
                'device_type' => 'SHELLY_SWITCH',
            ],
        ]);
    }

    $queueResponse = api_client()->post('/modules/self-serve/lane/hardware/batch/set', [
        'lane_id' => $laneId,
        'transport' => 'gateway',
        'commands' => [
            ['target' => 'MACHINE', 'on' => true],
            ['target' => 'CLEANER', 'on' => false],
        ],
    ], $session['headers']);

    $queueResponse
        ->assertStatus(202)
        ->assertEnvelope()
        ->assertSuccess();

    $expectedResponse = api_client()->post('/edge-agent/gateways/' . (int)$gateway['id'] . '/expected-relay-states', [
        'agent_token' => (string)$gateway['agent_token'],
        'wait_seconds' => 0,
    ]);

    $expectedResponse
        ->assertStatus(200)
        ->assertEnvelope()
        ->assertSuccess();

    $lanes = $expectedResponse->data()['lanes'] ?? [];
    expect($lanes)->toHaveKey((string)$laneId);
    $laneStates = $lanes[(string)$laneId];

    expect(array_keys($laneStates))->toBe([
        'ENTRANCE_GATE',
        'EXIT_GATE',
        'MACHINE',
        'PROGRAM_PICKER',
        'CLEANER',
    ])
        ->and($laneStates['MACHINE']['device'])->toBe([
            'ip' => '10.41.0.13',
            'id' => 'device-expected-machine',
            'type' => 'SHELLY_SWITCH',
        ])
        ->and($laneStates['MACHINE']['state'])->toBeTrue()
        ->and($laneStates['MACHINE']['completed'])->toBeNull()
        ->and($laneStates['CLEANER']['state'])->toBeFalse()
        ->and($laneStates['CLEANER']['completed'])->toBeNull()
        ->and($laneStates['ENTRANCE_GATE']['completed'])->not->toBeNull();
    expect($expectedResponse->data())->toHaveKey('CLEANER')
        ->and($expectedResponse->data()['MACHINE']['device'] ?? null)->toBe($laneStates['MACHINE']['device'])
        ->and($expectedResponse->data()['CLEANER']['completed'])->toBeNull();

    $machineUpdated = (string)$laneStates['MACHINE']['updated'];
    $cleanerUpdated = (string)$laneStates['CLEANER']['updated'];

    $resultResponse = api_client()->post('/edge-agent/gateways/' . (int)$gateway['id'] . '/relay-state-results', [
        'agent_token' => (string)$gateway['agent_token'],
        'results' => [
            [
                'lane_id' => $laneId,
                'role' => 'MACHINE',
                'state' => true,
                'updated' => $machineUpdated,
                'ok' => true,
                'completed' => '2026-07-01T09:10:00+00:00',
            ],
            [
                'lane_id' => $laneId,
                'role' => 'CLEANER',
                'state' => false,
                'updated' => $cleanerUpdated,
                'ok' => false,
                'skipped' => true,
                'error' => 'Relay offline',
            ],
        ],
    ]);

    $resultResponse
        ->assertStatus(200)
        ->assertEnvelope()
        ->assertSuccess();

    expect($resultResponse->data()['summary'] ?? [])
        ->toHaveKey('completed', 1)
        ->toHaveKey('skipped', 1)
        ->toHaveKey('failed', 0);

    $afterResult = api_client()->post('/edge-agent/gateways/' . (int)$gateway['id'] . '/expected-relay-states', [
        'agent_token' => (string)$gateway['agent_token'],
        'wait_seconds' => 0,
    ]);

    $afterResult
        ->assertStatus(200)
        ->assertEnvelope()
        ->assertSuccess();

    $afterLaneStates = $afterResult->data()['lanes'][(string)$laneId] ?? [];
    expect($afterLaneStates['MACHINE']['completed'] ?? null)->not->toBeNull()
        ->and($afterLaneStates['CLEANER']['completed'] ?? null)->toBeNull()
        ->and($afterLaneStates['CLEANER']['last_error'] ?? null)->toBe('Relay offline');

    $staleResponse = api_client()->post('/edge-agent/gateways/' . (int)$gateway['id'] . '/relay-state-results', [
        'agent_token' => (string)$gateway['agent_token'],
        'results' => [[
            'lane_id' => $laneId,
            'role' => 'CLEANER',
            'state' => false,
            'updated' => '2000-01-01 00:00:00',
            'ok' => true,
            'completed' => '2026-07-01T09:11:00+00:00',
        ]],
    ]);

    $staleResponse
        ->assertStatus(200)
        ->assertEnvelope()
        ->assertSuccess();

    expect($staleResponse->data()['summary']['stale'] ?? null)->toBe(1)
        ->and($staleResponse->data()['rejected'][0]['reason'] ?? null)->toBe('STALE_STATE');
});
