<?php

declare(strict_types=1);

use classes\db;
use Predis\Client as PredisClient;
use Tests\Support\Api\ApiCleanup;
use Tests\Support\Api\ApiFixtures;
use Tests\Support\Api\ApiSchemaBootstrap;

require_once dirname(__DIR__, 2) . '/vendor/autoload.php';
require_once __DIR__ . '/bootstrap.php';
require_once __DIR__ . '/Api/ApiCleanup.php';
require_once __DIR__ . '/Api/ApiFixtures.php';
require_once __DIR__ . '/Api/ApiSchemaBootstrap.php';

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

$action = strtolower(trim((string)($argv[1] ?? '')));
if ($action === '') {
    edge_gateway_e2e_fixture_fail('Missing action. Expected create or cleanup.');
}

try {
    if ($action === 'create') {
        $context = edge_gateway_e2e_fixture_context();
        $fixtures = $context['fixtures'];
        $department = $fixtures->createDepartment([
            'name' => 'Edge Gateway E2E Department',
        ]);
        $session = $fixtures->createEdgeOperatorSession((int)$department['id'], [], [
            'display_name' => 'Edge Gateway E2E Operator',
        ]);

        edge_gateway_e2e_fixture_output([
            'department_id' => (int)$department['id'],
            'user_id' => (int)$session['user']['id'],
            'group_id' => (int)$session['user']['group_id'],
            'customer_number' => (int)$session['user']['customer_number'],
            'auth_token' => (string)$session['token'],
            'broker_secret' => edge_test_broker_secret(),
        ]);
    }

    if ($action === 'cleanup') {
        $encoded = trim((string)($argv[2] ?? ''));
        if ($encoded === '') {
            edge_gateway_e2e_fixture_fail('Cleanup requires a base64url payload argument.');
        }

        $payload = json_decode(base64_decode(strtr($encoded, '-_', '+/')) ?: '', true);
        if (!is_array($payload)) {
            edge_gateway_e2e_fixture_fail('Invalid cleanup payload.');
        }

        $context = edge_gateway_e2e_fixture_context();
        $db = $context['mysqli'];
        $departmentId = (int)($payload['department_id'] ?? 0);
        $userId = (int)($payload['user_id'] ?? 0);
        $groupId = (int)($payload['group_id'] ?? 0);

        if ($departmentId > 0) {
            $gatewayIds = edge_gateway_e2e_gateway_ids($db, $departmentId);
            edge_gateway_e2e_delete_by_gateway_ids($db, 'edge_gateway_operation_events', $gatewayIds);
            edge_gateway_e2e_delete_by_gateway_ids($db, 'edge_gateway_operations', $gatewayIds);
            edge_gateway_e2e_delete_by_gateway_ids($db, 'edge_gateway_command_jobs', $gatewayIds);
            edge_gateway_e2e_delete_by_gateway_ids($db, 'edge_gateway_log_entries', $gatewayIds);
            edge_gateway_e2e_delete_by_gateway_ids($db, 'edge_gateway_shell_sessions', $gatewayIds);
            edge_gateway_e2e_delete_by_gateway_ids($db, 'edge_gateway_device_inventory', $gatewayIds);
            edge_gateway_e2e_delete_by_gateway_ids($db, 'edge_gateway_relay_bindings', $gatewayIds);
            edge_gateway_e2e_delete_by_gateway_ids($db, 'edge_gateway_audit_logs', $gatewayIds);

            $db->query('DELETE FROM edge_gateway_claim_tokens WHERE department_id = ' . $departmentId);
            $db->query('DELETE FROM edge_gateways WHERE department_id = ' . $departmentId);
            $db->query('DELETE FROM department_variables WHERE department_id = ' . $departmentId);
        }

        if ($userId > 0) {
            $db->query('DELETE FROM tokens WHERE user_id = ' . $userId);
            $db->query('DELETE FROM users WHERE id = ' . $userId);
        }

        if ($groupId > 0) {
            $db->query('DELETE FROM groups_permissions WHERE group_id = ' . $groupId);
            $db->query('DELETE FROM groups WHERE id = ' . $groupId);
        }

        if ($departmentId > 0) {
            $db->query('DELETE FROM departments WHERE id = ' . $departmentId);
        }

        edge_gateway_e2e_fixture_output(['ok' => true]);
    }

    edge_gateway_e2e_fixture_fail('Unsupported action: ' . $action);
} catch (Throwable $throwable) {
    edge_gateway_e2e_fixture_fail($throwable->getMessage());
}

/**
 * @return array{mysqli:mysqli,fixtures:ApiFixtures}
 */
function edge_gateway_e2e_fixture_context(): array
{
    static $context = null;

    if ($context !== null) {
        return $context;
    }

    $dbConfig = edge_gateway_e2e_db_config();
    $GLOBALS['CONFIG_DB'] = $dbConfig;
    $GLOBALS['response'] = new class {
        public function internal_server_error(string $message): void
        {
            throw new RuntimeException($message);
        }
    };

    $db = new db($dbConfig);
    $db->connect();
    $GLOBALS['db'] = $db;

    $mysqli = $db->conn();
    mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
    $mysqli->set_charset('utf8mb4');

    (new ApiSchemaBootstrap($mysqli))->ensureSchema();

    $context = [
        'mysqli' => $mysqli,
        'fixtures' => new ApiFixtures($mysqli, edge_gateway_e2e_redis_client(), new ApiCleanup()),
    ];

    return $context;
}

/**
 * @return array{host:string,user:string,password:string,database:string,port:int}
 */
function edge_gateway_e2e_db_config(): array
{
    $target = strtolower(trim((string)(getenv('CONFIG_DB_TARGET') ?: 'live')));
    if ($target !== 'debug') {
        $target = 'live';
    }

    $host = edge_gateway_e2e_config_value('CONFIG_DB_HOST', 'CONFIG_DB_DEBUG_HOST', $target);
    $user = edge_gateway_e2e_config_value('CONFIG_DB_USER', 'CONFIG_DB_DEBUG_USER', $target);
    $password = edge_gateway_e2e_config_value('CONFIG_DB_PASSWORD', 'CONFIG_DB_DEBUG_PASSWORD', $target);
    $database = edge_gateway_e2e_config_value('CONFIG_DB_DATABASE', 'CONFIG_DB_DEBUG_DATABASE', $target);
    $port = (int)(edge_gateway_e2e_config_value('CONFIG_DB_PORT', 'CONFIG_DB_DEBUG_PORT', $target) ?: '3306');

    if ($host === '' || $user === '' || $database === '') {
        throw new RuntimeException('Missing database configuration for edge gateway E2E fixtures.');
    }

    return [
        'host' => $host,
        'user' => $user,
        'password' => $password,
        'database' => $database,
        'port' => $port > 0 ? $port : 3306,
    ];
}

function edge_gateway_e2e_config_value(string $liveKey, string $debugKey, string $target): string
{
    $liveValue = trim((string)(getenv($liveKey) ?: ''));
    $debugValue = trim((string)(getenv($debugKey) ?: ''));

    if ($target === 'debug' && $debugValue !== '') {
        return $debugValue;
    }

    return $liveValue;
}

function edge_gateway_e2e_redis_client(): ?PredisClient
{
    $target = strtolower(trim((string)(getenv('CONFIG_DB_TARGET') ?: 'live')));
    if ($target !== 'debug') {
        $target = 'live';
    }

    $host = edge_gateway_e2e_config_value('REDIS_CONFIG_HOST', 'REDIS_CONFIG_DEBUG_HOST', $target);
    if ($host === '') {
        return null;
    }

    $parameters = [
        'scheme' => 'tcp',
        'host' => $host,
        'port' => (int)(edge_gateway_e2e_config_value('REDIS_CONFIG_PORT', 'REDIS_CONFIG_DEBUG_PORT', $target) ?: '6379'),
        'database' => (int)(edge_gateway_e2e_config_value('REDIS_CONFIG_DATABASE', 'REDIS_CONFIG_DEBUG_DATABASE', $target) ?: '0'),
        'password' => edge_gateway_e2e_config_value('REDIS_CONFIG_PASSWORD', 'REDIS_CONFIG_DEBUG_PASSWORD', $target),
    ];

    $user = edge_gateway_e2e_config_value('REDIS_CONFIG_USER', 'REDIS_CONFIG_DEBUG_USER', $target);
    if ($user !== '') {
        $parameters['username'] = $user;
    }

    return new PredisClient($parameters);
}

/**
 * @return array<int, int>
 */
function edge_gateway_e2e_gateway_ids(mysqli $db, int $departmentId): array
{
    $ids = [];
    $result = $db->query('SELECT id FROM edge_gateways WHERE department_id = ' . $departmentId);
    if ($result === false) {
        return [];
    }

    while ($row = $result->fetch_assoc()) {
        if (isset($row['id']) && is_numeric($row['id'])) {
            $ids[] = (int)$row['id'];
        }
    }

    $result->free();

    return $ids;
}

/**
 * @param array<int, int> $gatewayIds
 */
function edge_gateway_e2e_delete_by_gateway_ids(mysqli $db, string $table, array $gatewayIds): void
{
    $gatewayIds = array_values(array_unique(array_filter(array_map('intval', $gatewayIds), static fn(int $id): bool => $id > 0)));
    if ($gatewayIds === []) {
        return;
    }

    $db->query('DELETE FROM `' . $table . '` WHERE gateway_id IN (' . implode(', ', $gatewayIds) . ')');
}

/**
 * @param array<string, mixed> $payload
 */
function edge_gateway_e2e_fixture_output(array $payload): void
{
    echo json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . PHP_EOL;
    exit(0);
}

function edge_gateway_e2e_fixture_fail(string $message): never
{
    fwrite(STDERR, $message . PHP_EOL);
    exit(1);
}
