<?php
declare(strict_types=1);

require_once dirname(__DIR__) . '/db_bootstrap.php';
require_once dirname(__DIR__) . '/output_devices_lib.php';

$conn = ensure_db(true);
if (!($conn instanceof mysqli)) throw new RuntimeException('Database unavailable.');
ua_output_ensure_schema($conn);
foreach (['ua_output_routes','ua_output_jobs'] as $scopeTable) {
    $scopeColumn = $conn->query("SHOW COLUMNS FROM {$scopeTable} LIKE 'instance_key'")->fetch_assoc();
    if (!preg_match('/varchar\((\d+)\)/i', (string)($scopeColumn['Type'] ?? ''), $scopeLength) || (int)$scopeLength[1] < 160) {
        throw new RuntimeException('Output scope column is too short: ' . $scopeTable);
    }
}

$root = dirname(__DIR__);
$projectRoot = dirname($root);
$baseScope = 'test-output-' . bin2hex(random_bytes(5));
$deviceId = 'device-' . bin2hex(random_bytes(8));
$deviceScope = ua_output_device_scope($baseScope, $deviceId);
$longBaseScope = 'local:server:' . str_repeat('a', 64);
$longDeviceId = 'f91c69d8-fb22-4f49-be37-880a91c4b3d0';
$longDeviceScope = ua_output_device_scope($longBaseScope, $longDeviceId);

if (!ua_output_scope_is_device_child($baseScope, $deviceScope)) {
    throw new RuntimeException('Device scope validation failed.');
}
if ($longDeviceScope !== $longBaseScope . ':device:' . $longDeviceId) {
    throw new RuntimeException('Long device scope was truncated.');
}
if (ua_output_scope_is_device_child($baseScope, 'agent:999:device:' . $deviceId)) {
    throw new RuntimeException('Cross-scope device authorization became possible.');
}

try {
    $saved = ua_output_save_routes($conn, [
        'route_keys'=>['invoice_thermal'],
        'routes'=>[
            'invoice_thermal'=>[
                'device_name'=>'QA Shared Printer',
                'agent_host'=>'192.168.50.25',
                'agent_token'=>'qa-pairing-token',
                'paper_size'=>'80mm',
                'copies'=>2,
                'is_enabled'=>1,
            ],
        ],
    ], 0, $deviceScope);
    if ($saved !== 1) throw new RuntimeException('Unexpected route save count.');

    $deviceRoute = ua_output_route($conn, 'invoice_thermal', $deviceScope);
    if (($deviceRoute['device_name'] ?? '') !== 'QA Shared Printer') throw new RuntimeException('Device route was not loaded.');
    if (($deviceRoute['agent_host'] ?? '') !== '192.168.50.25') throw new RuntimeException('Network print host was not preserved.');
    if (($deviceRoute['agent_token'] ?? '') !== 'qa-pairing-token') throw new RuntimeException('Pairing token was not preserved.');
    if ((int)($deviceRoute['copies'] ?? 0) !== 2) throw new RuntimeException('Copy count was not preserved.');

    ua_output_save_routes($conn, [
        'route_keys'=>['invoice_a4'],
        'routes'=>[
            'invoice_a4'=>[
                'device_name'=>'QA Default Printer',
                'agent_host'=>'127.0.0.1',
                'paper_size'=>'A4',
                'copies'=>1,
                'is_enabled'=>1,
            ],
        ],
    ], 0, $baseScope);
    $fallback = ua_output_route($conn, 'invoice_a4', $deviceScope);
    if (($fallback['device_name'] ?? '') !== 'QA Default Printer') throw new RuntimeException('Base route fallback failed.');

    foreach ([
        'agent_output_devices.php',
        'output_route_config.php',
        'contract_print_log.php',
        'assets/js/ua_output_router.js',
        'assets/js/ua_output_file_router.js',
        'assets/css/agent_output_devices.css',
    ] as $relative) {
        if (!is_file($root . '/' . $relative)) throw new RuntimeException('Missing output routing file: ' . $relative);
    }

    $agentSource = (string)file_get_contents($projectRoot . '/launcher/OutputDeviceAgent.cs');
    foreach (['http://+:9123/', 'X-UA-Output-Token', 'SemaphoreSlim printQueue', 'pairing_local_only', '"/print-file"'] as $needle) {
        if (strpos($agentSource, $needle) === false) throw new RuntimeException('Output agent is missing: ' . $needle);
    }
    $routerSource = (string)file_get_contents($root . '/assets/js/ua_output_router.js');
    foreach (['ua_output_device_id_v1', 'resolveDeviceRoute', 'route.proxyUrl ||'] as $needle) {
        if (strpos($routerSource, $needle) === false) throw new RuntimeException('Browser output router is missing: ' . $needle);
    }
    $fileRouterSource = (string)file_get_contents($root . '/assets/js/ua_output_file_router.js');
    foreach (["output_file_proxy.php", 'X-UA-Contract-Id', 'data-ua-print-contract'] as $needle) {
        if (strpos($fileRouterSource, $needle) === false) throw new RuntimeException('Contract output router is missing: ' . $needle);
    }
    $fleetSource = (string)file_get_contents($root . '/output_fleet_lib.php');
    foreach (['ua_output_fleet_dispatch_file', "'print-file'", 'pull_queue'] as $needle) {
        if (strpos($fleetSource, $needle) === false) throw new RuntimeException('Central contract fleet route is missing: ' . $needle);
    }

    echo json_encode([
        'ok'=>true,
        'device_scope'=>$deviceScope,
        'local_host'=>'127.0.0.1',
        'shared_host'=>'192.168.50.25',
        'per_command_route'=>true,
        'base_fallback'=>true,
        'remote_token_required'=>true,
        'long_scope_preserved'=>true,
        'contract_file_printing'=>true,
    ], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . PHP_EOL;
} finally {
    ua_output_ensure_schema($conn);
    $baseEscaped = $conn->real_escape_string($baseScope);
    $deviceEscaped = $conn->real_escape_string($deviceScope);
    @$conn->query("DELETE FROM ua_output_routes WHERE instance_key IN ('{$baseEscaped}','{$deviceEscaped}')");
    @$conn->query("DELETE FROM ua_output_jobs WHERE instance_key IN ('{$baseEscaped}','{$deviceEscaped}')");
}
