<?php
/**
 * /api/create_trade_order.php (PDO) — FINAL (LAST)
 * ✅ إنشاء طلب تداول في trade_orders + حجز ledger (available->locked)
 * ✅ يعتمد على asset_pairs.id كـ pair_id
 * ✅ يدعم ui_order_mode من الواجهة:
 *    - BUY:  market | limit
 *    - SELL: market | take_profit | stop_loss  (حالياً تُعامل كـ LIMIT + تخزين ui_order_mode)
 * ✅ بعد commit يمرّر التنفيذ للمزوّد binding_file داخل /api/providers
 * ✅ FIX نهائي مهم: clean_decimal_str لا يحوّل 830 -> 83 (يحذف أصفار الكسور فقط)
 */

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");
if (($_SERVER['REQUEST_METHOD'] ?? '') === 'OPTIONS') { http_response_code(204); exit; }

/* ================= DEBUG ================= */
$DEBUG_MODE = false; // اجعلها true مؤقتاً عند الاختبار فقط
if ($DEBUG_MODE) { ini_set('display_errors', '1'); error_reporting(E_ALL); }
else { ini_set('display_errors', '0'); error_reporting(0); }

/* ================= 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 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 safe_upper($s): string {
  return strtoupper(preg_replace('/[^A-Z0-9_]/', '', (string)$s));
}

function safe_lower_token($s): string {
  $s = strtolower(trim((string)$s));
  $s = preg_replace('/[^a-z0-9_]/', '', $s);
  return $s;
}

/**
 * ✅ تنظيف آمن للأرقام:
 * - يحافظ على أصفار الأعداد الصحيحة (830 تبقى 830)
 * - يحذف أصفار الكسور فقط (830.00 -> 830 ، 12.3400 -> 12.34)
 * - يدعم الأرقام العربية والفاصلة العربية
 */
function clean_decimal_str($v, bool $allowSign=false): string {
  $s = trim((string)$v);
  if ($s === '') return '0';

  // أرقام عربية + فواصل عربية
  $s = strtr($s, [
    '٠'=>'0','١'=>'1','٢'=>'2','٣'=>'3','٤'=>'4','٥'=>'5','٦'=>'6','٧'=>'7','٨'=>'8','٩'=>'9',
    '٫'=>'.','٬'=>'', // آلاف عربية
  ]);

  // إذا لا يوجد نقطة ويوجد فاصلة، اعتبرها فاصلة عشرية
  if (strpos($s, '.') === false && strpos($s, ',') !== false) {
    $s = str_replace(',', '.', $s);
  } else {
    // غير ذلك: اعتبر الفاصلة فاصل آلاف واحذفها
    $s = str_replace(',', '', $s);
  }

  $sign = '';
  if ($allowSign && $s !== '' && ($s[0] === '-' || $s[0] === '+')) {
    $sign = ($s[0] === '-') ? '-' : '';
    $s = substr($s, 1);
  }

  $s = preg_replace('/[^0-9.]/', '', $s);

  // توحيد تعدد النقاط
  if (substr_count($s, '.') > 1) {
    $parts = explode('.', $s);
    $s = array_shift($parts) . '.' . implode('', $parts);
  }

  if ($s === '' || $s === '.') $s = '0';

  if (strpos($s, '.') !== false) {
    [$a,$b] = explode('.', $s, 2);
    $a = ltrim($a, '0'); if ($a === '') $a = '0';
    $b = substr($b, 0, 18);
    $b = rtrim($b, '0');              // ✅ فقط الكسور
    $s = $a . ($b !== '' ? '.' . $b : '');
  } else {
    // ✅ عدد صحيح: لا تحذف أصفار النهاية
    $s = ltrim($s, '0');
    if ($s === '') $s = '0';
  }

  if ($allowSign && $sign === '-' && $s !== '0') $s = '-' . $s;
  return $s;
}

function dec_add(string $a, string $b, int $scale=18): string {
  if (function_exists('bcadd')) return bcadd($a, $b, $scale);
  $x = (float)$a + (float)$b;
  $s = number_format($x, $scale, '.', '');
  return rtrim(rtrim($s,'0'),'.') ?: '0';
}
function dec_sub(string $a, string $b, int $scale=18): string {
  if (function_exists('bcsub')) return bcsub($a, $b, $scale);
  $x = (float)$a - (float)$b;
  $s = number_format($x, $scale, '.', '');
  return rtrim(rtrim($s,'0'),'.') ?: '0';
}
function dec_mul(string $a, string $b, int $scale=18): string {
  if (function_exists('bcmul')) return bcmul($a, $b, $scale);
  $x = (float)$a * (float)$b;
  $s = number_format($x, $scale, '.', '');
  return rtrim(rtrim($s,'0'),'.') ?: '0';
}
function dec_div(string $a, string $b, int $scale=18): string {
  $b = clean_decimal_str($b, false);
  if ($b === '0') return '0';
  if (function_exists('bcdiv')) return bcdiv($a, $b, $scale);
  $x = (float)$a / (float)$b;
  $s = number_format($x, $scale, '.', '');
  return rtrim(rtrim($s,'0'),'.') ?: '0';
}
function dec_cmp(string $a, string $b, int $scale=18): int {
  if (function_exists('bccomp')) return bccomp($a, $b, $scale);
  $x = (float)$a; $y = (float)$b;
  if (abs($x - $y) < 1e-12) return 0;
  return ($x < $y) ? -1 : 1;
}

function table_exists(PDO $conn, string $table): bool {
  $st = $conn->prepare("SELECT 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME=:t LIMIT 1");
  $st->execute([':t'=>$table]);
  return (bool)$st->fetchColumn();
}

function column_exists(PDO $conn, string $table, string $col): bool {
  $st = $conn->prepare("SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME=:t AND COLUMN_NAME=:c LIMIT 1");
  $st->execute([':t'=>$table, ':c'=>$col]);
  return (bool)$st->fetchColumn();
}

/**
 * ✅ يدعم:
 * - session user_id
 * - (user_id + user_token)
 * - user_token فقط (مهم للواجهة trade.php)
 */
function resolveUserId(PDO $conn, array $in): int {
  $sid = isset($_SESSION['user_id']) ? (int)$_SESSION['user_id'] : 0;
  if ($sid > 0) return $sid;

  $tok = trim((string)($in['user_token'] ?? ''));
  if ($tok === '') return 0;

  $uid = isset($in['user_id']) ? (int)$in['user_id'] : 0;

  if ($uid > 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;
  }

  // ✅ token فقط
  $st = $conn->prepare("
    SELECT user_id
    FROM user_sessions
    WHERE user_token=:tok AND is_online=1
    ORDER BY id DESC
    LIMIT 1
  ");
  $st->execute([':tok'=>$tok]);
  $row = $st->fetch(PDO::FETCH_ASSOC);
  return $row ? (int)$row['user_id'] : 0;
}

function safe_binding_file(string $f): string {
  $f = trim($f);
  $f = preg_replace('/[^A-Za-z0-9_.-]/', '', $f);
  if ($f === '') return '';
  if (stripos($f, '.php') === false) $f .= '.php';
  if (substr($f, -4) !== '.php') $f .= '.php';
  return $f;
}

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

try {
  $in = read_input();

  foreach (['users','assets','asset_pairs','ledger_entries','trade_orders','user_sessions','providers'] as $t) {
    if (!table_exists($conn, $t)) respond(false, "جدول {$t} غير موجود.", [], 500);
  }

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

  /* ================= Params ================= */
  $symbol = safe_upper($in['symbol'] ?? '');
  if ($symbol === '') respond(false, 'symbol مطلوب.', [], 400);

  $side = strtolower(trim((string)($in['side'] ?? 'buy')));
  if (!in_array($side, ['buy','sell'], true)) $side = 'buy';

  $orderType = strtolower(trim((string)($in['order_type'] ?? 'market')));
  if (!in_array($orderType, ['market','limit'], true)) $orderType = 'market';

  // ✅ ui_order_mode من الواجهة
  $uiOrderMode = safe_lower_token($in['ui_order_mode'] ?? '');
  $allowedUiModes = ['market','limit','take_profit','stop_loss'];
  if ($uiOrderMode !== '' && !in_array($uiOrderMode, $allowedUiModes, true)) $uiOrderMode = '';

  // ✅ تطبيق قواعد الواجهة:
  // BUY: market/limit
  // SELL: market/take_profit/stop_loss  (حالياً تُعامل كـ LIMIT)
  if ($uiOrderMode !== '') {
    if (in_array($uiOrderMode, ['limit','take_profit','stop_loss'], true)) {
      $orderType = 'limit';
    } else {
      $orderType = 'market';
    }

    if (in_array($uiOrderMode, ['take_profit','stop_loss'], true)) {
      $side = 'sell';
    }

    if ($side === 'buy' && !in_array($uiOrderMode, ['market','limit'], true)) {
      $uiOrderMode = 'market';
      $orderType = 'market';
    }
    if ($side === 'sell' && !in_array($uiOrderMode, ['market','take_profit','stop_loss'], true)) {
      $uiOrderMode = 'market';
      $orderType = 'market';
    }
  }

  // ✅ السعر:
  // - LIMIT: price (أو client_price كاحتياط)
  // - MARKET: client_price (أو last_price كاحتياط)
  $clientPrice = clean_decimal_str($in['client_price'] ?? ($in['last_price'] ?? '0'), false);
  $priceIn     = clean_decimal_str($in['price'] ?? '0', false);

  $price = ($orderType === 'limit')
    ? (dec_cmp($priceIn,'0') > 0 ? $priceIn : $clientPrice)
    : $clientPrice;

  $qtyBase  = clean_decimal_str($in['qty_base']  ?? '0', false);
  $qtyQuote = clean_decimal_str($in['qty_quote'] ?? '0', false);

  if (dec_cmp($qtyBase,'0') <= 0 && dec_cmp($qtyQuote,'0') <= 0) {
    respond(false, 'أدخل qty_base أو qty_quote.', [], 400);
  }

  if ($orderType === 'limit' && dec_cmp($price,'0') <= 0) {
    respond(false, 'price مطلوب لأوامر LIMIT (سعر محدد/أخذ الأرباح/وقف الخسارة).', [], 400);
  }

  /* ================= Pair lookup (IMPORTANT: uses id as pair_id) ================= */
  $stP = $conn->prepare("
    SELECT id, base_asset_id, quote_asset_id,
           COALESCE(taker_fee_pct,0) AS taker_fee_pct,
           COALESCE(maker_fee_pct,0) AS maker_fee_pct,
           COALESCE(provider_id,0)   AS provider_id
    FROM asset_pairs
    WHERE tv_symbol=:sym AND (is_active=1 OR is_active IS NULL)
    LIMIT 1
  ");
  $stP->execute([':sym'=>$symbol]);
  $pair = $stP->fetch(PDO::FETCH_ASSOC);
  if (!$pair) respond(false, 'الزوج غير موجود في asset_pairs (tv_symbol).', ['symbol'=>$symbol], 400);

  $pairId       = (int)$pair['id'];
  $baseAssetId  = (int)$pair['base_asset_id'];
  $quoteAssetId = (int)$pair['quote_asset_id'];
  $providerId   = (int)$pair['provider_id'];

  if ($pairId <= 0) respond(false, 'pair_id غير صالح داخل asset_pairs.', [], 500);

  // أكواد الأصول
  $stC = $conn->prepare("SELECT code FROM assets WHERE id=:id LIMIT 1");
  $stC->execute([':id'=>$baseAssetId]);
  $baseCode = strtoupper((string)($stC->fetchColumn() ?: ''));
  $stC->execute([':id'=>$quoteAssetId]);
  $quoteCode = strtoupper((string)($stC->fetchColumn() ?: ''));

  if ($baseCode === '' || $quoteCode === '') respond(false, 'تعذر قراءة أكواد الأصول من assets.', [], 500);

  /* ================= Normalize qty_base/qty_quote ================= */
  if ($side === 'buy') {
    if (dec_cmp($qtyQuote,'0') <= 0) {
      if (dec_cmp($price,'0') <= 0) respond(false, 'client_price/price مطلوب لحساب تكلفة الشراء.', [], 400);
      $qtyQuote = dec_mul($qtyBase, $price, 18);
    } else {
      if (dec_cmp($qtyBase,'0') <= 0 && dec_cmp($price,'0') > 0) {
        $qtyBase = dec_div($qtyQuote, $price, 18);
      }
    }
  } else {
    if (dec_cmp($qtyBase,'0') <= 0) {
      if (dec_cmp($price,'0') <= 0) respond(false, 'client_price/price مطلوب لحساب كمية البيع.', [], 400);
      $qtyBase = dec_div($qtyQuote, $price, 18);
    } else {
      if (dec_cmp($qtyQuote,'0') <= 0 && dec_cmp($price,'0') > 0) {
        $qtyQuote = dec_mul($qtyBase, $price, 18);
      }
    }
  }

  if (dec_cmp($qtyBase,'0') <= 0)  respond(false, 'qty_base غير صالح.', [], 400);
  if (dec_cmp($qtyQuote,'0') <= 0) respond(false, 'qty_quote غير صالح.', [], 400);

  /* ================= Fee ================= */
  $feeRate = ($orderType === 'market')
    ? clean_decimal_str($pair['taker_fee_pct'] ?? '0', false)
    : clean_decimal_str($pair['maker_fee_pct'] ?? '0', false);

  if ($feeRate === '0') $feeRate = '0.001'; // احترازي
  $feeAmount = dec_mul($qtyQuote, $feeRate, 18);
  $feeAssetCode = $quoteCode;

  /* ================= Hold rule ================= */
  if ($side === 'buy') {
    $holdAssetId = $quoteAssetId;
    $holdAmount  = dec_add($qtyQuote, $feeAmount, 18);
  } else {
    $holdAssetId = $baseAssetId;
    $holdAmount  = $qtyBase;
  }

  if (dec_cmp($holdAmount,'0') <= 0) respond(false, 'hold_amount غير صالح.', [], 400);

  /* ================= Provider binding_file ================= */
  if ($providerId <= 0) {
    $stPr0 = $conn->query("SELECT id FROM providers WHERE is_active=1 AND binding_file IS NOT NULL AND binding_file<>'' ORDER BY id ASC LIMIT 1");
    $providerId = (int)($stPr0 ? $stPr0->fetchColumn() : 0);
  }

  $providerName = '';
  $bindingFile  = '';
  if ($providerId > 0) {
    $stPr = $conn->prepare("SELECT id,name,binding_file FROM providers WHERE id=:id AND is_active=1 LIMIT 1");
    $stPr->execute([':id'=>$providerId]);
    $prow = $stPr->fetch(PDO::FETCH_ASSOC);
    if ($prow) {
      $providerName = (string)$prow['name'];
      $bindingFile  = safe_binding_file((string)($prow['binding_file'] ?? ''));
    }
  }

  if ($providerId <= 0 || $bindingFile === '') {
    respond(false, 'لا يوجد مزود تداول متاح حالياً.', [
      'provider'=>['id'=>$providerId,'name'=>$providerName,'binding_file'=>$bindingFile]
    ], 400);
  }

  $providerPath = __DIR__ . '/providers/' . $bindingFile;
  if (!is_file($providerPath)) respond(false, "ملف المزود غير موجود: {$bindingFile}", [], 500);

  /* ================= Transaction: Create + Hold ================= */
  $conn->beginTransaction();

  // lock user row
  $lock = $conn->prepare("SELECT id FROM users WHERE id=:uid FOR UPDATE");
  $lock->execute([':uid'=>$userId]);

  // check available
  $hasLedgerStatus = column_exists($conn, 'ledger_entries', 'status');
  $sqlBal = "
    SELECT COALESCE(SUM(
      CASE WHEN balance_type='available' ".($hasLedgerStatus ? "AND status='posted'" : "")." THEN amount ELSE 0 END
    ), 0) AS available
    FROM ledger_entries
    WHERE user_id=:uid AND asset_id=:aid
  ";
  $stBal = $conn->prepare($sqlBal);
  $stBal->execute([':uid'=>$userId, ':aid'=>$holdAssetId]);
  $availableStr = clean_decimal_str($stBal->fetchColumn() ?? '0', true);

  if (dec_cmp($availableStr, $holdAmount) < 0) {
    $conn->rollBack();
    respond(false, 'لا يوجد رصيد كافي للحجز.', [
      'available'=>$availableStr,
      'required'=>$holdAmount,
      'asset'=>($holdAssetId===$baseAssetId ? $baseCode : $quoteCode)
    ], 400);
  }

  // insert trade order (dynamic columns)
  $cols = [];
  $vals = [];
  $params = [];

  $map = [
    'user_id' => $userId,
    'pair_id' => $pairId,
    'symbol' => $symbol,
    'side' => $side,
    'order_type' => $orderType,

    // LIMIT فقط نخزن price
    'price' => ($orderType === 'limit' && dec_cmp($price,'0')>0 ? $price : null),

    // client_price مفيد للماركت/الواجهة
    'client_price' => (dec_cmp($clientPrice,'0')>0 ? $clientPrice : null),

    // ui_order_mode (إن كان العمود موجود)
    'ui_order_mode' => ($uiOrderMode !== '' ? $uiOrderMode : null),

    'qty_base' => $qtyBase,
    'qty_quote' => $qtyQuote,
    'fee_rate' => $feeRate,
    'fee_amount' => $feeAmount,
    'fee_asset_code' => $feeAssetCode,
    'hold_asset_id' => $holdAssetId,
    'hold_amount' => $holdAmount,
    'provider_id' => $providerId,
    'status' => 'pending',
    'status_reason' => null,
  ];

  foreach ($map as $c=>$v) {
    if (column_exists($conn,'trade_orders',$c)) {
      $cols[] = $c;
      $ph = ':'.$c;
      $vals[] = $ph;
      $params[$ph] = $v;
    }
  }

  if (column_exists($conn,'trade_orders','created_at')) { $cols[]='created_at'; $vals[]='NOW()'; }
  if (column_exists($conn,'trade_orders','updated_at')) { $cols[]='updated_at'; $vals[]='NOW()'; }

  if (empty($cols)) {
    $conn->rollBack();
    respond(false, 'هيكل trade_orders لا يحتوي أعمدة كافية.', [], 500);
  }

  $sqlO = "INSERT INTO trade_orders (".implode(',',$cols).") VALUES (".implode(',',$vals).")";
  $stO = $conn->prepare($sqlO);
  $stO->execute($params);

  $tradeOrderId = (int)$conn->lastInsertId();
  if ($tradeOrderId <= 0) {
    $conn->rollBack();
    respond(false, 'تعذر إنشاء طلب التداول.', [], 500);
  }

  // ledger hold (available -= hold, locked += hold)
  $hasLedgerCreated = column_exists($conn, 'ledger_entries', 'created_at');

  $noteHold = "Trade hold {$symbol} ({$side}) (trade_order #{$tradeOrderId})";
  $negHold  = dec_sub('0', $holdAmount, 18);

  $lcols = ['user_id','asset_id','amount','balance_type','ref_type','ref_id','note'];
  $lvals = [':uid',':aid',':amt',':bt',':rt',':rid',':note'];
  $lparBase = [
    ':uid'=>$userId, ':aid'=>$holdAssetId,
    ':rt'=>'trade', ':rid'=>$tradeOrderId, ':note'=>$noteHold
  ];

  if ($hasLedgerStatus) { $lcols[]='status'; $lvals[]=':st'; $lparBase[':st']='posted'; }
  if ($hasLedgerCreated) { $lcols[]='created_at'; $lvals[]='NOW()'; }

  $sqlL = "INSERT INTO ledger_entries (".implode(',',$lcols).") VALUES (".implode(',',$lvals).")";
  $stL = $conn->prepare($sqlL);

  // available -= hold
  $p1 = $lparBase + [':amt'=>$negHold, ':bt'=>'available'];
  $stL->execute($p1);

  // locked += hold
  $p2 = $lparBase + [':amt'=>$holdAmount, ':bt'=>'locked'];
  $stL->execute($p2);

  $conn->commit();

  /* ================= Dispatch to Provider (AFTER COMMIT) ================= */
  define('EAZZYBIT_INTERNAL_CALL', 1);
  require_once $providerPath;

  if (!function_exists('provider_execute')) {
    respond(false, 'ملف المزود لا يحتوي الدالة provider_execute().', ['binding_file'=>$bindingFile], 500);
  }

  $exec = provider_execute($conn, [
    'trade_order_id'=>$tradeOrderId,
    'provider_id'=>$providerId,
    'ui_order_mode'=>$uiOrderMode
  ]);

  // fetch final order
  $stF = $conn->prepare("SELECT * FROM trade_orders WHERE id=:id LIMIT 1");
  $stF->execute([':id'=>$tradeOrderId]);
  $final = $stF->fetch(PDO::FETCH_ASSOC) ?: null;

  $ok = !empty($exec['success']);
  respond($ok, (string)($exec['message'] ?? 'تمت معالجة الطلب.'), [
    'trade_order_id' => $tradeOrderId,
    'order'=>$final,
    'provider'=>['id'=>$providerId,'name'=>$providerName,'binding_file'=>$bindingFile],
    'execution'=>$exec,
    'ui_order_mode'=>$uiOrderMode
  ], $ok ? 200 : 400);

} catch (Throwable $e) {
  if (isset($conn) && ($conn instanceof PDO) && $conn->inTransaction()) $conn->rollBack();
  $msg = 'خطأ في الخادم';
  if (!empty($GLOBALS['DEBUG_MODE'])) $msg .= ' - ' . $e->getMessage();
  respond(false, $msg, [], 500);
}
