<?php

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

$conn = ensure_db(true);
$key = 'RULE-' . bin2hex(random_bytes(5));
$conn->begin_transaction();
try {
  $saved = ua_agent_repo_save($conn, [
    'code'=>$key,
    'full_name'=>'Rules Integration Agent',
    'username'=>strtolower($key),
    'is_active'=>1,
    'portal_enabled'=>1,
    'pos_enabled'=>1,
    'commission_type'=>'percent',
    'commission_value'=>10,
    'credit_limit'=>100,
  ]);
  if (!$saved['ok']) throw new RuntimeException($saved['error']);
  $agentId = (int)$saved['id'];

  $charge = ua_agent_service_post_charge($conn, [
    'agent_id'=>$agentId,
    'entry_type'=>'TEST_CHARGE',
    'amount'=>80,
    'idempotency_key'=>'RULE_CHARGE:' . $key,
    'source_type'=>'test',
    'source_id'=>$key,
    'description'=>'Commission test',
  ], false);
  if (!$charge['ok']) throw new RuntimeException($charge['error']);
  if (abs((float)$charge['commission_amount'] - 8.0) > 0.001) throw new RuntimeException('Commission calculation failed.');
  if (abs(ua_agent_ledger_balance($conn, $agentId) - 72.0) > 0.001) throw new RuntimeException('Net balance after commission is invalid.');

  $overLimit = ua_agent_service_post_charge($conn, [
    'agent_id'=>$agentId,
    'entry_type'=>'TEST_LIMIT',
    'amount'=>40,
    'idempotency_key'=>'RULE_LIMIT:' . $key,
    'source_type'=>'test',
    'source_id'=>$key,
    'description'=>'Credit limit test',
  ], false);
  if ($overLimit['ok'] || stripos((string)$overLimit['error'], 'حد ائتمان') === false) {
    throw new RuntimeException('Credit limit was not enforced.');
  }
  if (abs(ua_agent_ledger_balance($conn, $agentId) - 72.0) > 0.001) {
    throw new RuntimeException('Rejected charge changed the balance.');
  }

  $sync = ua_agent_sync_enqueue($conn, [
    'agent_id'=>$agentId,
    'instance_id'=>'rules-test-instance',
    'direction'=>'OUTBOUND',
    'event_type'=>'RULE_TEST',
    'idempotency_key'=>'RULE_SYNC:' . $key,
    'payload'=>['test'=>true],
  ]);
  if (!$sync['ok']) throw new RuntimeException($sync['error']);
  $syncId = (int)$sync['event']['id'];
  if (!ua_agent_sync_mark($conn, $syncId, 'FAILED', [], 'Temporary failure')) {
    throw new RuntimeException('Sync failure scheduling failed.');
  }
  $syncRow = $conn->query("SELECT status,attempts,available_at FROM agent_sync_events WHERE id={$syncId}")->fetch_assoc();
  if (($syncRow['status'] ?? '') !== 'FAILED' || (int)($syncRow['attempts'] ?? 0) !== 1 || strtotime((string)$syncRow['available_at']) <= time()) {
    throw new RuntimeException('Sync retry backoff was not scheduled.');
  }
  if (!ua_agent_sync_retry($conn, $syncId)) throw new RuntimeException('Manual sync retry failed.');
  $retryRow = $conn->query("SELECT status FROM agent_sync_events WHERE id={$syncId}")->fetch_assoc();
  if (($retryRow['status'] ?? '') !== 'PENDING') throw new RuntimeException('Manual retry did not restore PENDING state.');

  $conn->rollback();
  $escaped = $conn->real_escape_string($key);
  $left = $conn->query("SELECT COUNT(*) c FROM agents WHERE code='{$escaped}'")->fetch_assoc();
  if ((int)$left['c'] !== 0) throw new RuntimeException('Rollback left test data.');
  echo json_encode([
    'ok'=>true,
    'commission_amount'=>8,
    'net_balance'=>72,
    'credit_limit_blocked'=>true,
    'sync_backoff_and_retry'=>true,
    'rows_after_rollback'=>0,
  ], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) . PHP_EOL;
} catch (Throwable $e) {
  @$conn->rollback();
  fwrite(STDERR, $e->getMessage() . PHP_EOL);
  exit(1);
}
