<?php
// get_swap.php (PDO) — GET/POST
// ✅ action=assets  : قائمة العملات للـ Picker حسب قواعد التبديل + أرصدة ledger_entries
// ✅ action=quote   : تسعير (Stable + مصارفة YER/YER_NEW مقابل USD/SAR) بدون تنفيذ
// ✅ action=execute : تنفيذ التبديل وإنشاء قيدين في ledger_entries (خصم + إضافة)
// ✅ التوثيق: Session أو user_id + user_token (user_sessions.user_token)

if (session_status() === PHP_SESSION_NONE) session_start();

/* ================= CORS ================= */
$frontendOrigin = 'https://eazzybit.com';
$reqOrigin = $_SERVER['HTTP_ORIGIN'] ?? '';
if ($reqOrigin === $frontendOrigin) {
  header("Access-Control-Allow-Origin: {$frontendOrigin}");
  header("Vary: Origin");
  header("Access-Control-Allow-Credentials: true");
}
header("Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With");
header("Access-Control-Allow-Methods: GET, POST, OPTIONS");
header("Access-Control-Max-Age: 600");
header("Content-Type: application/json; charset=UTF-8");

/* ================= DEBUG ================= */
$DEBUG_MODE = true;
if ($DEBUG_MODE) { ini_set('display_errors', 1); error_reporting(E_ALL); }
else { ini_set('display_errors', 0); error_reporting(0); }

if (($_SERVER['REQUEST_METHOD'] ?? '') === 'OPTIONS') { http_response_code(204); exit; }

/* ================= Helpers ================= */
function respond(bool $success, string $message, array $extra = [], int $status = 200): void {
  http_response_code($status);
  echo json_encode(
    array_merge(['success' => $success, 'message' => $message], $extra),
    JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES
  );
  exit;
}

function log_error(Throwable $e): void {
  $dir = __DIR__ . '/../../logs';
  if (!is_dir($dir)) @mkdir($dir, 0755, true);
  $file = $dir . '/api_errors_' . date('Y-m-d') . '.log';
  $line = "[" . date('Y-m-d H:i:s') . "] " . $e->getMessage() . " | " . $e->getFile() . ":" . $e->getLine() . PHP_EOL;
  @file_put_contents($file, $line, FILE_APPEND | LOCK_EX);
}

function safe_float($v): float {
  $x = is_numeric($v) ? (float)$v : 0.0;
  return is_finite($x) ? $x : 0.0;
}
function safe_int($v, int $default = 0): int {
  if ($v === null || $v === '') return $default;
  return (int)$v;
}
function safe_code($v): string {
  $s = strtoupper(trim((string)$v));
  $s = preg_replace('/[^A-Z0-9_]/', '', $s);
  return $s ?: '';
}
function read_input(): array {
  $method = $_SERVER['REQUEST_METHOD'] ?? 'GET';
  if ($method === 'POST') {
    $raw  = file_get_contents('php://input') ?: '';
    $json = json_decode($raw, true);
    if (is_array($json)) return $json;
    return $_POST ?? [];
  }
  return $_GET ?? [];
}

function normalize_type($t): string { return strtolower(trim((string)$t)); }
function is_fiat_type($t): bool {
  $t = normalize_type($t);
  return in_array($t, ['fiat','cash','currency'], true);
}
function is_crypto_type($t): bool {
  $t = normalize_type($t);
  return in_array($t, ['crypto','coin','token'], true);
}
function is_fiat_by_code(string $code): bool {
  // ✅ أكواد الريال بعد التحديث:
  // YER = قديم, YER_NEW = جديد
  // (اختياري) دعم توافق قديم: YER_OLD
  $FIAT = ['USD','YER','YER_NEW','YER_OLD','SAR','AED','KWD','QAR','BHD','OMR','EUR','GBP','SYP','TRY'];
  return in_array(strtoupper($code), $FIAT, true);
}
function row_is_fiat(array $r): bool {
  $code = strtoupper((string)($r['code'] ?? ''));
  if (isset($r['type']) && (is_fiat_type($r['type']) || is_crypto_type($r['type']))) {
    return is_fiat_type($r['type']);
  }
  return is_fiat_by_code($code);
}

/* ================= DB ================= */
require_once __DIR__ . '/../config.php';
if (!isset($conn) || !($conn instanceof PDO)) {
  respond(false, 'اتصال قاعدة البيانات غير متوفر.', [], 500);
}

/* ================= AUTH: Session أو user_id+user_token ================= */
function resolveUserId(PDO $conn, array $in): int {
  $sid = isset($_SESSION['user_id']) ? (int)$_SESSION['user_id'] : 0;
  if ($sid > 0) return $sid;

  $uid = isset($in['user_id']) ? (int)$in['user_id'] : 0;
  $tok = trim((string)($in['user_token'] ?? ''));
  if ($uid <= 0 || $tok === '') return 0;

  $st = $conn->prepare("
    SELECT user_id
    FROM user_sessions
    WHERE user_id = :uid
      AND user_token = :tok
      AND is_online = 1
    LIMIT 1
  ");
  $st->execute([':uid' => $uid, ':tok' => $tok]);
  $row = $st->fetch(PDO::FETCH_ASSOC);

  return $row ? (int)$row['user_id'] : 0;
}

/* ================= Yemeni Rial detection ================= */
function detect_yer_variants(array $rows): array {
  $codes = [];
  foreach ($rows as $r) $codes[] = strtoupper((string)($r['code'] ?? ''));

  // ✅ بعد التحديث:
  // القديم = YER
  // الجديد = YER_NEW
  // (اختياري) دعم legacy: YER_OLD كقديم
  $old = in_array('YER', $codes, true) ? 'YER' : (in_array('YER_OLD', $codes, true) ? 'YER_OLD' : '');
  $new = in_array('YER_NEW', $codes, true) ? 'YER_NEW' : '';

  // fallback بالاسم العربي
  if ($old === '' || $new === '') {
    foreach ($rows as $r) {
      $name = (string)($r['name_ar'] ?? '');
      $code = strtoupper((string)($r['code'] ?? ''));

      if ($old === '' && mb_strpos($name, 'ريال') !== false &&
          (mb_strpos($name, 'قديم') !== false || mb_strpos($name, 'قدي') !== false)) {
        $old = $code;
      }

      if ($new === '' && mb_strpos($name, 'ريال') !== false &&
          (mb_strpos($name, 'جديد') !== false || mb_strpos($name, 'حديث') !== false)) {
        $new = $code;
      }
    }
  }

  if ($old !== '' && $new !== '' && $old === $new) $new = '';
  return ['old' => $old, 'new' => $new];
}

/* ================= FX helpers (optional: read latest) ================= */
function fx_latest(PDO $conn, string $table, string $quoteCode): ?array {
  try {
    $q = $conn->prepare("
      SELECT buy_rate, sell_rate, updated_at, note
      FROM {$table}
      WHERE quote_code = :q
      ORDER BY updated_at DESC
      LIMIT 1
    ");
    $q->execute([':q' => strtoupper($quoteCode)]);
    $r = $q->fetch(PDO::FETCH_ASSOC);
    if (!$r) return null;

    return [
      'buy_rate'   => (string)($r['buy_rate'] ?? '0'),
      'sell_rate'  => (string)($r['sell_rate'] ?? '0'),
      'updated_at' => (string)($r['updated_at'] ?? ''),
      'note'       => $r['note'] ?? null,
    ];
  } catch (Throwable $e) {
    return null; // لا نكسر API لو الجدول غير موجود
  }
}

/* ================= Pricing (Stable + FX) ================= */
function is_stable_code(string $c): bool {
  $c = strtoupper($c);
  return in_array($c, ['USD','USDT','USDC'], true);
}
function is_quote_fx(string $c): bool {
  $c = strtoupper($c);
  return in_array($c, ['USD','SAR'], true);
}
function fx_market_for(string $code): ?string {
  $c = strtoupper($code);

  // ✅ mapping بعد التحديث:
  // YER_NEW => yer_new
  // YER     => yer_old
  // (اختياري) legacy: YER_OLD => yer_old
  if ($c === 'YER_NEW') return 'yer_new';
  if ($c === 'YER')     return 'yer_old';
  if ($c === 'YER_OLD') return 'yer_old';

  return null;
}
function fx_get_rate(array $fx, string $market, string $quote): ?array {
  if (!isset($fx[$market]) || !is_array($fx[$market])) return null;
  $q = strtoupper($quote);
  if (!isset($fx[$market][$q]) || !is_array($fx[$market][$q])) return null;

  $buy  = safe_float($fx[$market][$q]['buy_rate']  ?? 0);
  $sell = safe_float($fx[$market][$q]['sell_rate'] ?? 0);
  if (!($buy > 0) || !($sell > 0)) return null;
  return ['buy'=>$buy, 'sell'=>$sell];
}
function preferred_fx_market(array $fx): ?string {
  if (!empty($fx['yer_new']['USD']) || !empty($fx['yer_new']['SAR'])) return 'yer_new';
  if (!empty($fx['yer_old']['USD']) || !empty($fx['yer_old']['SAR'])) return 'yer_old';
  return null;
}

/**
 * rate بحيث: to_amount = from_amount * rate (قبل العمولة)
 */
function compute_rate(string $from, string $to, array $fx): ?float {
  $f = strtoupper($from);
  $t = strtoupper($to);
  if ($f === '' || $t === '') return null;
  if ($f === $t) return 1.0;

  // stable 1:1
  if (is_stable_code($f) && is_stable_code($t)) return 1.0;

  // مصارفة: بين (YER/YER_NEW) و (USD/SAR)
  $fMarket = fx_market_for($f);
  $tMarket = fx_market_for($t);

  // ريال -> أجنبي (شراء أجنبي): divide by sell
  if ($fMarket && is_quote_fx($t)) {
    $r = fx_get_rate($fx, $fMarket, $t);
    if (!$r) return null;
    return 1.0 / $r['sell'];
  }

  // أجنبي -> ريال (بيع أجنبي): multiply by buy
  if (is_quote_fx($f) && $tMarket) {
    $r = fx_get_rate($fx, $tMarket, $f);
    if (!$r) return null;
    return $r['buy'];
  }

  // USD <-> SAR عبر تقاطع سوق مفضل (اختياري)
  if (is_quote_fx($f) && is_quote_fx($t) && $f !== $t) {
    $m = preferred_fx_market($fx);
    if (!$m) return null;
    $rf = fx_get_rate($fx, $m, $f);
    $rt = fx_get_rate($fx, $m, $t);
    if (!$rf || !$rt) return null;
    return $rf['buy'] / $rt['sell'];
  }

  return null;
}

function commission_pct(string $from, string $to): float {
  $f = strtoupper($from);
  $t = strtoupper($to);
  if ($f === 'USD'  && $t === 'USDT') return 2.0;
  if ($f === 'USDT' && $t === 'USD')  return 5.0;
  return 0.0;
}

/* ================= Ledger helpers ================= */
function get_available(PDO $conn, int $userId, int $assetId): float {
  $st = $conn->prepare("
    SELECT COALESCE(SUM(
      CASE WHEN balance_type='available' AND status='posted' THEN amount ELSE 0 END
    ),0) AS av
    FROM ledger_entries
    WHERE user_id=:u AND asset_id=:a
  ");
  $st->execute([':u'=>$userId, ':a'=>$assetId]);
  $r = $st->fetch(PDO::FETCH_ASSOC);
  return safe_float($r['av'] ?? 0);
}

function insert_ledger(PDO $conn, array $row): void {
  $sql = "
    INSERT INTO ledger_entries
      (user_id, asset_id, amount, balance_type, ref_type, ref_id, status, note, created_at)
    VALUES
      (:user_id, :asset_id, :amount, :balance_type, :ref_type, :ref_id, :status, :note, NOW())
  ";
  $st = $conn->prepare($sql);
  $st->execute([
    ':user_id'      => (int)$row['user_id'],
    ':asset_id'     => (int)$row['asset_id'],
    ':amount'       => (string)$row['amount'],
    ':balance_type' => (string)$row['balance_type'],
    ':ref_type'     => (string)$row['ref_type'],
    ':ref_id'       => (string)$row['ref_id'],
    ':status'       => (string)$row['status'],
    ':note'         => (string)$row['note'],
  ]);
}

/* ================= Main ================= */
try {
  $in = read_input();

  $userId = resolveUserId($conn, $in);
  if ($userId <= 0) {
    respond(false, 'غير مصرح. الرجاء تسجيل الدخول.', ['unauthorized' => true], 401);
  }

  $action = strtolower(trim((string)($in['action'] ?? 'assets')));
  if (!in_array($action, ['assets','quote','execute'], true)) $action = 'assets';

  /* ============================================================
     ACTION: assets (Picker list)
     ============================================================ */
  if ($action === 'assets') {

    $base    = safe_code($in['base'] ?? ($in['from'] ?? ''));
    $exclude = safe_code($in['exclude'] ?? '');

    $q           = trim((string)($in['q'] ?? ''));
    $includeZero = safe_int($in['include_zero'] ?? 1, 1);
    $hideSmall   = safe_int($in['hide_small'] ?? 0, 0);
    $minUsd      = safe_float($in['min_usd'] ?? 1);

    $sql = "
      SELECT
        a.id         AS asset_id,
        a.code       AS code,
        a.name_ar    AS name_ar,
        a.type       AS type,
        a.decimals   AS decimals,
        a.icon_url   AS icon_url,
        a.sort_order AS sort_order,

        COALESCE(SUM(
          CASE
            WHEN le.balance_type = 'available' AND le.status = 'posted' THEN le.amount
            ELSE 0
          END
        ), 0) AS available,

        COALESCE(SUM(
          CASE
            WHEN le.balance_type = 'locked' AND le.status = 'posted' THEN le.amount
            ELSE 0
          END
        ), 0) AS locked,

        (
          COALESCE(SUM(
            CASE
              WHEN le.balance_type = 'available' AND le.status = 'posted' THEN le.amount
              ELSE 0
            END
          ), 0)
          +
          COALESCE(SUM(
            CASE
              WHEN le.balance_type = 'locked' AND le.status = 'posted' THEN le.amount
              ELSE 0
            END
          ), 0)
        ) AS total_amount

      FROM assets a
      LEFT JOIN ledger_entries le
        ON le.user_id  = :uid
       AND le.asset_id = a.id

      WHERE a.is_active = 1
      GROUP BY a.id, a.code, a.name_ar, a.type, a.decimals, a.icon_url, a.sort_order
      ORDER BY total_amount DESC, a.sort_order DESC, a.code ASC
    ";

    $stmt = $conn->prepare($sql);
    $stmt->execute([':uid' => $userId]);
    $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);

    $yer = detect_yer_variants($rows);
    $YER_OLD_CODE = $yer['old']; // غالباً YER
    $YER_NEW_CODE = $yer['new']; // غالباً YER_NEW

    $byCode = [];
    foreach ($rows as $r) {
      $c = strtoupper((string)($r['code'] ?? ''));
      if ($c !== '') $byCode[$c] = $r;
    }

    $baseRow = null;
    if ($base !== '') {
      $baseRow = $byCode[$base] ?? null;
      if (!$baseRow) {
        respond(false, 'العملة المحددة غير موجودة أو غير مفعلة.', ['base' => $base], 404);
      }
    }

    $fiats = [];
    $cryptos = [];
    foreach ($rows as $r) {
      $code = strtoupper((string)($r['code'] ?? ''));
      if ($code === '') continue;
      if (row_is_fiat($r)) $fiats[] = $code;
      else $cryptos[] = $code;
    }

    $allowed = null;
    $ruleApplied = 'none';

    if ($baseRow) {
      $baseIsFiat = row_is_fiat($baseRow);
      $baseCode   = strtoupper((string)$baseRow['code']);

      if ($baseIsFiat) {
        $allowed = $fiats;

        if ($baseCode === 'USD') {
          if (!in_array('USDT', $allowed, true)) $allowed[] = 'USDT';
          $ruleApplied = 'fiat_usd => fiats + usdt';
        } else {
          $ruleApplied = 'fiat_other => fiats_only';
        }

        // منع التبديل بين الريالين مباشرة
        if ($YER_OLD_CODE !== '' && $YER_NEW_CODE !== '') {
          if ($baseCode === $YER_OLD_CODE) {
            $allowed = array_values(array_filter($allowed, fn($c) => $c !== $YER_NEW_CODE));
            $ruleApplied = 'fiat_yer_old => fiats_except_yer_new' . ($baseCode === 'USD' ? ' + usdt' : '');
          } elseif ($baseCode === $YER_NEW_CODE) {
            $allowed = array_values(array_filter($allowed, fn($c) => $c !== $YER_OLD_CODE));
            $ruleApplied = 'fiat_yer_new => fiats_except_yer_old' . ($baseCode === 'USD' ? ' + usdt' : '');
          }
        }

      } else {
        if ($baseCode === 'USDT') {
          $allowed = $cryptos;
          if (!in_array('USD', $allowed, true)) $allowed[] = 'USD';
          $ruleApplied = 'crypto_usdt => cryptos + usd';
        } else {
          $allowed = ['USDT'];
          $ruleApplied = 'crypto_other => usdt_only';
        }
      }

      // استثناء نفس العملة دائماً
      $allowed = array_values(array_filter($allowed, fn($c) => $c !== $baseCode));

      if ($exclude !== '') {
        $allowed = array_values(array_filter($allowed, fn($c) => $c !== $exclude));
      }
    }

    $fx = [
      'yer_new' => [
        'USD' => fx_latest($conn, 'yer_new_exchange_rates', 'USD'),
        'SAR' => fx_latest($conn, 'yer_new_exchange_rates', 'SAR'),
      ],
      'yer_old' => [
        'USD' => fx_latest($conn, 'yer_old_exchange_rates', 'USD'),
        'SAR' => fx_latest($conn, 'yer_old_exchange_rates', 'SAR'),
      ],
    ];

    $items = [];
    $totalUsd = 0.0;

    foreach ($rows as $r) {
      $code = strtoupper((string)($r['code'] ?? ''));
      if ($code === '') continue;

      if (is_array($allowed) && !in_array($code, $allowed, true)) continue;

      if ($q !== '') {
        $qq = mb_strtolower($q);
        $c1 = mb_strtolower($code);
        $n1 = mb_strtolower((string)($r['name_ar'] ?? ''));
        if (mb_strpos($c1, $qq) === false && mb_strpos($n1, $qq) === false) continue;
      }

      $available = safe_float($r['available'] ?? 0);
      $locked    = safe_float($r['locked'] ?? 0);
      $total     = safe_float($r['total_amount'] ?? ($available + $locked));

      if ((int)$includeZero === 0 && $total == 0.0) continue;

      $usdPrice = null;
      if (in_array($code, ['USD','USDT','USDC'], true)) $usdPrice = 1.0;
      $usdValue = ($usdPrice !== null) ? ($total * $usdPrice) : null;

      if ((int)$hideSmall === 1 && $usdValue !== null && $usdValue < $minUsd) continue;
      if ($usdValue !== null) $totalUsd += $usdValue;

      $items[] = [
        'asset_id'  => (int)($r['asset_id'] ?? 0),
        'code'      => $code,
        'name_ar'   => (string)($r['name_ar'] ?? ''),
        'type'      => (string)($r['type'] ?? ''),
        'decimals'  => (int)($r['decimals'] ?? 2),
        'icon_url'  => $r['icon_url'] ?? null,
        'available' => (string)$available,
        'locked'    => (string)$locked,
        'total'     => (string)$total,
        'usd_value' => $usdValue,
      ];
    }

    respond(true, 'تم جلب عملات التبديل بنجاح.', [
      'user_id' => $userId,
      'base' => $baseRow ? [
        'code' => strtoupper((string)($baseRow['code'] ?? '')),
        'type' => (string)($baseRow['type'] ?? ''),
        'is_fiat' => row_is_fiat($baseRow),
      ] : null,
      'yer_variants' => ['old' => $YER_OLD_CODE, 'new' => $YER_NEW_CODE],
      'rule' => $ruleApplied,
      'fx' => $fx,
      'total_usd' => round($totalUsd, 2),
      'count' => count($items),
      'items' => $items,
    ]);
  }

  /* ============================================================
     ACTION: quote / execute
     ============================================================ */
  if ($action === 'quote' || $action === 'execute') {

    $from = safe_code($in['from'] ?? '');
    $to   = safe_code($in['to'] ?? '');
    $amt  = safe_float($in['amount'] ?? 0);

    if ($from === '' || $to === '') respond(false, 'الرجاء تحديد from و to.', [], 400);
    if ($from === $to) respond(false, 'لا يمكن تبديل نفس العملة.', [], 400);
    if (!($amt > 0)) respond(false, 'الرجاء إدخال كمية صحيحة.', [], 400);

    // جلب rows لتحديد asset_id + تطبيق نفس قواعد السماح
    $stmt = $conn->prepare("
      SELECT
        a.id AS asset_id, a.code, a.name_ar, a.type, a.decimals, a.icon_url, a.sort_order,
        COALESCE(SUM(CASE WHEN le.balance_type='available' AND le.status='posted' THEN le.amount ELSE 0 END),0) AS available,
        COALESCE(SUM(CASE WHEN le.balance_type='locked' AND le.status='posted' THEN le.amount ELSE 0 END),0)    AS locked,
        (
          COALESCE(SUM(CASE WHEN le.balance_type='available' AND le.status='posted' THEN le.amount ELSE 0 END),0) +
          COALESCE(SUM(CASE WHEN le.balance_type='locked' AND le.status='posted' THEN le.amount ELSE 0 END),0)
        ) AS total_amount
      FROM assets a
      LEFT JOIN ledger_entries le
        ON le.user_id=:uid AND le.asset_id=a.id
      WHERE a.is_active=1
      GROUP BY a.id, a.code, a.name_ar, a.type, a.decimals, a.icon_url, a.sort_order
    ");
    $stmt->execute([':uid' => $userId]);
    $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);

    $byCode = [];
    foreach ($rows as $r) {
      $c = strtoupper((string)($r['code'] ?? ''));
      if ($c !== '') $byCode[$c] = $r;
    }

    $fromRow = $byCode[$from] ?? null;
    $toRow   = $byCode[$to] ?? null;
    if (!$fromRow || !$toRow) {
      respond(false, 'العملة غير موجودة أو غير مفعّلة.', ['from'=>$from,'to'=>$to], 404);
    }

    // FX latest
    $fx = [
      'yer_new' => [
        'USD' => fx_latest($conn, 'yer_new_exchange_rates', 'USD'),
        'SAR' => fx_latest($conn, 'yer_new_exchange_rates', 'SAR'),
      ],
      'yer_old' => [
        'USD' => fx_latest($conn, 'yer_old_exchange_rates', 'USD'),
        'SAR' => fx_latest($conn, 'yer_old_exchange_rates', 'SAR'),
      ],
    ];

    // بناء allowed حسب قواعدك (base = from)
    $yer = detect_yer_variants($rows);
    $YER_OLD_CODE = $yer['old'];
    $YER_NEW_CODE = $yer['new'];

    $fiats = [];
    $cryptos = [];
    foreach ($rows as $r) {
      $code = strtoupper((string)($r['code'] ?? ''));
      if ($code === '') continue;
      if (row_is_fiat($r)) $fiats[] = $code; else $cryptos[] = $code;
    }

    $allowed = [];
    $ruleApplied = 'none';

    $baseRow = $fromRow;
    $baseIsFiat = row_is_fiat($baseRow);
    $baseCode = strtoupper((string)$baseRow['code']);

    if ($baseIsFiat) {
      $allowed = $fiats;

      if ($baseCode === 'USD') {
        if (!in_array('USDT', $allowed, true)) $allowed[] = 'USDT';
        $ruleApplied = 'fiat_usd => fiats + usdt';
      } else {
        $ruleApplied = 'fiat_other => fiats_only';
      }

      if ($YER_OLD_CODE !== '' && $YER_NEW_CODE !== '') {
        if ($baseCode === $YER_OLD_CODE) {
          $allowed = array_values(array_filter($allowed, fn($c) => $c !== $YER_NEW_CODE));
          $ruleApplied = 'fiat_yer_old => fiats_except_yer_new' . ($baseCode === 'USD' ? ' + usdt' : '');
        } elseif ($baseCode === $YER_NEW_CODE) {
          $allowed = array_values(array_filter($allowed, fn($c) => $c !== $YER_OLD_CODE));
          $ruleApplied = 'fiat_yer_new => fiats_except_yer_old' . ($baseCode === 'USD' ? ' + usdt' : '');
        }
      }

    } else {
      if ($baseCode === 'USDT') {
        $allowed = $cryptos;
        if (!in_array('USD', $allowed, true)) $allowed[] = 'USD';
        $ruleApplied = 'crypto_usdt => cryptos + usd';
      } else {
        $allowed = ['USDT'];
        $ruleApplied = 'crypto_other => usdt_only';
      }
    }

    // استثناء نفس العملة دائماً
    $allowed = array_values(array_filter($allowed, fn($c) => $c !== $baseCode));

    if (!in_array($to, $allowed, true)) {
      respond(false, 'هذا الزوج غير مسموح حسب قواعد التبديل.', [
        'rule' => $ruleApplied,
        'from' => $from,
        'to'   => $to
      ], 400);
    }

    // التسعير
    $rate = compute_rate($from, $to, $fx);
    if ($rate === null) {
      respond(false, 'لا يوجد سعر صرف متوفر لهذا الزوج حالياً.', [
        'from'=>$from,'to'=>$to,'rule'=>$ruleApplied,'fx'=>$fx
      ], 400);
    }

    $feePct = commission_pct($from, $to);
    $mult   = $rate * (1 - ($feePct/100));
    if (!($mult > 0)) respond(false, 'تعذر حساب السعر.', [], 400);

    $toAmt = $amt * $mult;
    if (!is_finite($toAmt) || $toAmt < 0) respond(false, 'تعذر حساب المبلغ الناتج.', [], 400);

    // تحقق الرصيد
    $fromAssetId = (int)$fromRow['asset_id'];
    $toAssetId   = (int)$toRow['asset_id'];

    $avail = get_available($conn, $userId, $fromAssetId);
    if ($amt > $avail + 1e-12) {
      respond(false, 'لا يوجد رصيد كافي لإتمام العملية', ['available' => (string)$avail], 400);
    }

    // quote فقط
    if ($action === 'quote') {
      respond(true, 'تم حساب السعر بنجاح.', [
        'from' => $from,
        'to' => $to,
        'from_amount' => (string)$amt,
        'to_amount' => (string)$toAmt,
        'rate' => $rate,
        'fee_pct' => $feePct,
        'rule' => $ruleApplied,
        'fx' => $fx
      ]);
    }

    // execute: إنشاء قيدين
    $swapRef = 'SWP_' . date('YmdHis') . '_' . bin2hex(random_bytes(4));

    $lockKey = "swap_u{$userId}";
    $gotLock = 0;

    try {
      $lk = $conn->prepare("SELECT GET_LOCK(:k, 5) AS l");
      $lk->execute([':k'=>$lockKey]);
      $gotLock = (int)($lk->fetch(PDO::FETCH_ASSOC)['l'] ?? 0);
      if ($gotLock !== 1) {
        respond(false, 'الرجاء المحاولة مرة أخرى (تعذر الحصول على قفل).', [], 409);
      }

      $conn->beginTransaction();

      // إعادة تحقق بعد القفل
      $avail2 = get_available($conn, $userId, $fromAssetId);
      if ($amt > $avail2 + 1e-12) {
        $conn->rollBack();
        respond(false, 'لا يوجد رصيد كافي لإتمام العملية', ['available' => (string)$avail2], 400);
      }

      // خصم from
      insert_ledger($conn, [
        'user_id' => $userId,
        'asset_id' => $fromAssetId,
        'amount' => (string)(-$amt),
        'balance_type' => 'available',
        'ref_type' => 'swap',
        'ref_id' => $swapRef,
        'status' => 'posted',
        'note' => "Swap OUT {$from} -> {$to}"
      ]);

      // إضافة to
      insert_ledger($conn, [
        'user_id' => $userId,
        'asset_id' => $toAssetId,
        'amount' => (string)($toAmt),
        'balance_type' => 'available',
        'ref_type' => 'swap',
        'ref_id' => $swapRef,
        'status' => 'posted',
        'note' => "Swap IN {$from} -> {$to}"
      ]);

      $conn->commit();

    } catch (Throwable $e) {
      if ($conn->inTransaction()) $conn->rollBack();
      throw $e;
    } finally {
      if ($gotLock === 1) {
        try {
          $rl = $conn->prepare("SELECT RELEASE_LOCK(:k)");
          $rl->execute([':k'=>$lockKey]);
        } catch (Throwable $e) {}
      }
    }

    $newFromAvail = get_available($conn, $userId, $fromAssetId);
    $newToAvail   = get_available($conn, $userId, $toAssetId);

    respond(true, 'تم تنفيذ عملية التبديل بنجاح.', [
      'ref_id' => $swapRef,
      'from' => $from,
      'to' => $to,
      'from_amount' => (string)$amt,
      'to_amount' => (string)$toAmt,
      'rate' => $rate,
      'fee_pct' => $feePct,
      'rule' => $ruleApplied,
      'balances' => [
        'from_available' => (string)$newFromAvail,
        'to_available'   => (string)$newToAvail,
      ]
    ]);
  }

  respond(false, 'طلب غير صالح.', [], 400);

} catch (Throwable $e) {
  log_error($e);
  $msg = 'خطأ في الخادم';
  if ($DEBUG_MODE) $msg .= ' - ' . $e->getMessage();
  respond(false, $msg, [], 500);
}
