<?php

require_once dirname(__DIR__) . '/db_bootstrap.php';
require_once dirname(__DIR__) . '/agent_service.php';
require_once dirname(__DIR__) . '/install_link_lib.php';

function sync_test_request(string $url, string $instanceId, string $key, int $timestamp, string $nonce, string $body, bool $validSignature = true): array {
  $http_response_header = [];
  $signature = hash_hmac('sha256', $timestamp . '.' . $nonce . '.' . $body, $validSignature ? $key : 'invalid-key');
  $context = stream_context_create([
    'http'=>[
      'method'=>'POST',
      'header'=>implode("\r\n", [
        'Content-Type: application/json',
        'X-UA-Instance: ' . $instanceId,
        'X-UA-Timestamp: ' . $timestamp,
        'X-UA-Nonce: ' . $nonce,
        'X-UA-Signature: ' . $signature,
      ]),
      'content'=>$body,
      'ignore_errors'=>true,
      'timeout'=>10,
    ],
  ]);
  $response = @file_get_contents($url, false, $context);
  $headers = $http_response_header ?? [];
  $status = 0;
  if ($headers && preg_match('/\s(\d{3})\s/', $headers[0], $match)) $status = (int)$match[1];
  return ['status'=>$status,'body'=>json_decode((string)$response, true) ?: []];
}

$conn = ensure_db(true);
ua_agent_schema_migrate($conn);
ua_link_ensure_schema($conn);
$suffix = bin2hex(random_bytes(5));
$instanceId = 'sync_test_' . $suffix;
$agentCode = 'SYNC-' . strtoupper($suffix);
$key = hash('sha256', 'sync-secret-' . $suffix);
$agentId = 0;

try {
  $instanceName = 'Agent Sync Integration Test';
  $installType = 'agent';
  $status = 'approved';
  $stmt = $conn->prepare("INSERT INTO ua_link_requests (instance_id,instance_name,install_type,request_secret_hash,status,approved_at,created_at,updated_at) VALUES (?,?,?,?,?,NOW(),NOW(),NOW())");
  if (!$stmt) throw new RuntimeException($conn->error);
  $stmt->bind_param('sssss', $instanceId,$instanceName,$installType,$key,$status);
  if (!$stmt->execute()) throw new RuntimeException($stmt->error);
  $stmt->close();

  $saved = ua_agent_repo_save($conn, [
    'code'=>$agentCode,
    'full_name'=>'Sync Integration Agent',
    'username'=>strtolower($agentCode),
    'linked_instance_id'=>$instanceId,
    'is_active'=>1,
    'portal_enabled'=>1,
    'pos_enabled'=>1,
  ]);
  if (!$saved['ok']) throw new RuntimeException($saved['error']);
  $agentId = (int)$saved['id'];

  $url = 'http://127.0.0.1:8080/mikrotik/admin/api/agent_sync/status.php';
  $body = '{}';
  $timestamp = time();
  $nonce = 'nonce-' . $suffix;
  $valid = sync_test_request($url, $instanceId, $key, $timestamp, $nonce, $body, true);
  $replay = sync_test_request($url, $instanceId, $key, $timestamp, $nonce, $body, true);
  $badSignature = sync_test_request($url, $instanceId, $key, $timestamp, 'bad-' . $suffix, $body, false);
  $stale = sync_test_request($url, $instanceId, $key, $timestamp - 900, 'stale-' . $suffix, $body, true);

  if ($valid['status'] !== 200 || empty($valid['body']['ok'])) {
    throw new RuntimeException('Valid signed request failed: ' . json_encode($valid, JSON_UNESCAPED_UNICODE));
  }
  if ($replay['status'] !== 409 || ($replay['body']['error'] ?? '') !== 'REPLAYED_REQUEST') {
    throw new RuntimeException('Replay protection failed: ' . json_encode($replay, JSON_UNESCAPED_UNICODE));
  }
  if ($badSignature['status'] !== 401 || ($badSignature['body']['error'] ?? '') !== 'INVALID_SIGNATURE') throw new RuntimeException('Invalid signature was not rejected.');
  if ($stale['status'] !== 401 || ($stale['body']['error'] ?? '') !== 'STALE_REQUEST') throw new RuntimeException('Stale request was not rejected.');

  echo json_encode([
    'ok'=>true,
    'valid_request'=>$valid['status'],
    'replay_request'=>$replay['status'],
    'invalid_signature'=>$badSignature['status'],
    'stale_request'=>$stale['status'],
  ], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) . PHP_EOL;
} catch (Throwable $e) {
  fwrite(STDERR, $e->getMessage() . PHP_EOL);
  $exitCode = 1;
} finally {
  $instanceEsc = $conn->real_escape_string($instanceId);
  if ($agentId > 0) {
    @$conn->query("DELETE FROM agent_activity_log WHERE agent_id={$agentId}");
    @$conn->query("DELETE FROM agent_sync_events WHERE agent_id={$agentId}");
    @$conn->query("DELETE FROM agent_ledger_entries WHERE agent_id={$agentId}");
    @$conn->query("DELETE FROM agents WHERE id={$agentId}");
  }
  @$conn->query("DELETE FROM agent_sync_nonces WHERE instance_id='{$instanceEsc}'");
  @$conn->query("DELETE FROM ua_link_requests WHERE instance_id='{$instanceEsc}'");
  $agentLeft = @$conn->query("SELECT COUNT(*) c FROM agents WHERE code='" . $conn->real_escape_string($agentCode) . "'");
  $linkLeft = @$conn->query("SELECT COUNT(*) c FROM ua_link_requests WHERE instance_id='{$instanceEsc}'");
  $nonceLeft = @$conn->query("SELECT COUNT(*) c FROM agent_sync_nonces WHERE instance_id='{$instanceEsc}'");
  $leftCount = ($agentLeft ? (int)$agentLeft->fetch_assoc()['c'] : 1)
    + ($linkLeft ? (int)$linkLeft->fetch_assoc()['c'] : 1)
    + ($nonceLeft ? (int)$nonceLeft->fetch_assoc()['c'] : 1);
  if ($leftCount !== 0) {
    fwrite(STDERR, "Sync test cleanup left {$leftCount} rows.\n");
    $exitCode = 1;
  }
}

exit($exitCode ?? 0);
