<?php

app_require('classes/object_property.php');
app_require('objects/department_lanes_o.php');
app_require('modules/selfserve/classes/selfserve_lane.php');
app_require('modules/selfserve/classes/selfserve_wash_flow.php');
app_require('modules/selfserve/helpers/selfserve_lane_relay.php');

use modules\selfserve\classes\selfserve_lane;
use modules\selfserve\classes\selfserve_wash_flow;
use modules\selfserve\helpers\selfserve_lane_relay;

class SelfserveWashCompletionRelayValueFake extends \classes\object_property
{
    public function __construct(private readonly mixed $storedValue) {}

    public function value(): mixed
    {
        return $this->storedValue;
    }
}

class SelfserveWashCompletionDepartmentLaneFake extends \objects\department_lanes_o
{
    public function __construct(string $machineRelayId = 'relay-machine', string $cleanerRelayId = 'relay-cleaner')
    {
        $this->relay_machine_id = new SelfserveWashCompletionRelayValueFake($machineRelayId);
        $this->relay_machine_cleaner_id = new SelfserveWashCompletionRelayValueFake($cleanerRelayId);
        $this->relay_machine_program_picker_id = new SelfserveWashCompletionRelayValueFake('');
    }

    public function exists(): bool
    {
        return true;
    }
}

class SelfserveWashCompletionRelayLaneFake extends selfserve_lane
{
    /** @var selfserve_lane_relay[] */
    public array $statusReads = [];
    /** @var array<int,array{0:selfserve_lane_relay,1:bool}> */
    public array $relayWrites = [];

    public function __construct(bool $reportedOn)
    {
        $this->id = 77;
        $this->reportedOn = $reportedOn;
        $this->department_lane = new SelfserveWashCompletionDepartmentLaneFake();
    }

    private bool $reportedOn;

    public function getRelayStatus(selfserve_lane_relay $relay): array
    {
        $this->statusReads[] = $relay;
        return ['on' => $this->reportedOn];
    }

    public function setRelayStatusHard(selfserve_lane_relay $relay, bool $on): bool
    {
        $this->relayWrites[] = [$relay, $on];
        return true;
    }
}

class SelfserveWashCompletionFlowHarness extends selfserve_wash_flow
{
    public function __construct() {}

    public function turnOffConfiguredRelay(selfserve_lane $lane, selfserve_lane_relay $relay): void
    {
        $this->turnOffRelayIfConfigured($lane, $relay);
    }
}

it('forces machine and cleaner relays off when a self-serve wash session is completed', function (): void {
    $washFlow = file_get_contents(app_path('modules/selfserve/classes/selfserve_wash_flow.php'));

    expect($washFlow)->not->toBeFalse();
    expect($washFlow)->toContain('$this->disableMachineRelayForCompletedWash($laneId);');
    expect($washFlow)->toContain('bool $disableRelays = true');
    expect($washFlow)->toContain('if ($disableRelays) {');

    $methodOffset = strpos($washFlow, 'protected function disableMachineRelayForCompletedWash');
    expect($methodOffset)->not->toBeFalse();
    $methodBody = substr($washFlow, (int)$methodOffset, 1500);

    expect($methodBody)->toContain('$this->turnOffRelayIfConfigured($lane, selfserve_lane_relay::MACHINE);');
    expect($methodBody)->toContain('$this->turnOffRelayIfConfigured($lane, selfserve_lane_relay::MACHINE_CLEANER);');

    $helperOffset = strpos($washFlow, 'protected function turnOffRelayIfConfigured');
    expect($helperOffset)->not->toBeFalse();
    $helperBody = substr($washFlow, (int)$helperOffset, 1500);

    expect($helperBody)->toContain('$lane->setRelayStatusHard($relay, false);');
    expect($helperBody)->not->toContain('$lane->getRelayStatus($relay)');
});

it('always dispatches completion relay off for configured machine relays without a status precheck', function (): void {
    $lane = new SelfserveWashCompletionRelayLaneFake(reportedOn: false);
    $flow = new SelfserveWashCompletionFlowHarness();

    $flow->turnOffConfiguredRelay($lane, selfserve_lane_relay::MACHINE);
    $flow->turnOffConfiguredRelay($lane, selfserve_lane_relay::MACHINE_CLEANER);

    expect($lane->statusReads)->toBe([])
        ->and($lane->relayWrites)->toBe([
            [selfserve_lane_relay::MACHINE, false],
            [selfserve_lane_relay::MACHINE_CLEANER, false],
        ]);
});

it('normal STOP completion skips duplicate completion relay cleanup after STOP already disabled relays', function (): void {
    $commandTrait = file_get_contents(app_path('modules/selfserve/traits/selfserve_lane_command_t.php'));

    expect($commandTrait)->not->toBeFalse();
    $methodOffset = strpos($commandTrait, 'protected function completeLatestSessionForStop(?int $subuser_id = null): void');
    expect($methodOffset)->not->toBeFalse();

    $methodBody = substr($commandTrait, (int)$methodOffset, 1500);
    expect($methodBody)->toContain(<<<'PHP'
(new \modules\selfserve\classes\selfserve_wash_flow())->completeLatestSessionForLane(
                $this->id,
                $this->getLicensePlate() ?: null,
                $this->getCustomerNumber() ?: null,
                method_exists($this, 'getLastInvoiceOrderId') ? $this->getLastInvoiceOrderId() : null,
                false,
                $subuser_id
            );
PHP);
});
