<?php

app_require('classes/edge_gateway_manager.php');
app_require('classes/shelly_transport_resolver.php');

use classes\edge_gateway_manager;
use classes\gateway_shelly_transport;
use classes\shelly_transport_resolver;
use interfaces\shelly_transport_i;

class ShellyTransportResolverManagerFake extends edge_gateway_manager
{
    /** @var array<int,string> */
    public array $modesByDepartment = [];
    /** @var array<int,int> */
    public array $calls = [];

    public function __construct()
    {
    }

    public function getDepartmentTransportMode(int $departmentId): string
    {
        $this->calls[] = $departmentId;

        return $this->modesByDepartment[$departmentId] ?? self::TRANSPORT_MODE_CLOUD;
    }
}

class ShellyTransportResolverTransportFake implements shelly_transport_i
{
    public function __construct(public readonly string $name)
    {
    }

    public function requireModuleEnabled(): void
    {
    }

    public function requireValidSecretKey(): void
    {
    }

    public function sendPostRequest(string $endpoint, array $data, ?int $department_id = null): array|object|null
    {
        return [
            'name' => $this->name,
            'endpoint' => $endpoint,
            'department_id' => $department_id,
        ];
    }
}

it('resolves the injected gateway transport when a department is in gateway mode', function (): void {
    $manager = new ShellyTransportResolverManagerFake();
    $manager->modesByDepartment[17] = edge_gateway_manager::TRANSPORT_MODE_GATEWAY;

    $cloudTransport = new ShellyTransportResolverTransportFake('cloud');
    $gatewayTransport = new ShellyTransportResolverTransportFake('gateway');

    $resolver = new shelly_transport_resolver($manager, $cloudTransport, $gatewayTransport);

    expect($resolver->resolveForDepartment(17))->toBe($gatewayTransport);
    expect($manager->calls)->toBe([17]);
});

it('resolves the injected cloud transport when a department is in cloud mode', function (): void {
    $manager = new ShellyTransportResolverManagerFake();
    $manager->modesByDepartment[22] = edge_gateway_manager::TRANSPORT_MODE_CLOUD;

    $cloudTransport = new ShellyTransportResolverTransportFake('cloud');
    $gatewayTransport = new ShellyTransportResolverTransportFake('gateway');

    $resolver = new shelly_transport_resolver($manager, $cloudTransport, $gatewayTransport);

    expect($resolver->resolveForDepartment(22))->toBe($cloudTransport);
    expect($manager->calls)->toBe([22]);
});

it('lets relay tests override the department transport without changing department mode', function (): void {
    $manager = new ShellyTransportResolverManagerFake();
    $manager->modesByDepartment[17] = edge_gateway_manager::TRANSPORT_MODE_CLOUD;

    $cloudTransport = new ShellyTransportResolverTransportFake('cloud');
    $gatewayTransport = new ShellyTransportResolverTransportFake('gateway');

    $resolver = new shelly_transport_resolver($manager, $cloudTransport, $gatewayTransport);

    expect($resolver->resolveForDepartment(17, 'local'))->toBe($gatewayTransport);
    expect($resolver->resolveForDepartment(17, 'gateway'))->toBe($gatewayTransport);
    expect($resolver->resolveForDepartment(17, 'cloud'))->toBe($cloudTransport);
    expect($manager->calls)->toBe([]);
});

it('marks non-injected local and gateway overrides as local-only gateway transport', function (): void {
    $manager = new ShellyTransportResolverManagerFake();
    $resolver = new shelly_transport_resolver($manager);

    foreach (['local', 'gateway'] as $override) {
        $transport = $resolver->resolveForDepartment(17, $override);
        $localOnly = new ReflectionProperty($transport, 'localOnly');

        expect($transport)->toBeInstanceOf(gateway_shelly_transport::class);
        expect($localOnly->getValue($transport))->toBeTrue();
    }
    expect($manager->calls)->toBe([]);
});
