<?php
// create_order.php (PDO) — إنشاء طلب + حجز + تمرير للمزود للتنفيذ فوراً
// ✅ ينشئ طلب في orders (status=pending) لسحب مشفّر خارجي
// ✅ يجلب الرسوم/الحدود من yc_crypto_asset_networks حسب (asset_code + network_id + op=withdraw)
// ✅ يتحقق من الرصيد المتاح من ledger_entries (status=posted + balance_type=available)
// ✅ يعمل قيدين (posted):
//    1) available  -= (amount + fee)
//    2) locked     += (amount + fee)
// ✅ يختار مزود تلقائياً عبر provider_networks (إن وجد) ثم يستدعي ملف المزود binding_file داخل /api/providers
// ✅ المزود يقوم بتحديث orders إلى completed/canceled ويعمل فك الحجز من locked (وعند الإلغاء يرجّع للـ available)
// ✅ حالات الطلب فقط: pending | completed | canceled
// ✅ بدون مفاتيح خارجية مطلوبة

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

function clean_decimal_str($v, bool $allowSign=false): string {
  $s = trim((string)$v);
  if ($s === '') return '0';

  $sign = '';
  if ($allowSign && ($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);
    $b = substr($b, 0, 18);
    $s = $a . ($b !== '' ? '.' . $b : '');
  }

  $s = rtrim(rtrim($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_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 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;
}

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();
}

function safe_binding_file(string $f): string {
  $f = trim($f);
  $f = preg_replace('/[^A-Za-z0-9_.-]/', '', $f);
  if ($f === '' || stripos($f, '.php') === false) return '';
  // اجبار النهاية .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();

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

  /* ================= Params ================= */
  $op = strtolower(trim((string)($in['op'] ?? 'withdraw')));
  if ($op !== 'withdraw') respond(false, 'هذه الواجهة حالياً للسحب فقط.', [], 400);

  $assetCode = clean_code($in['asset_code'] ?? ($in['asset'] ?? ''));
  if ($assetCode === '') $assetCode = 'USDT';

  $networkId = isset($in['network_id']) ? (int)$in['network_id'] : 0;
  $target    = trim((string)($in['target'] ?? ''));
  $amountStr = clean_decimal_str($in['amount'] ?? '0', false);

  if ($networkId <= 0) respond(false, 'network_id مطلوب.', [], 400);
  if ($target === '')  respond(false, 'الوجهة (target) مطلوبة.', [], 400);
  if (dec_cmp($amountStr, '0') <= 0) respond(false, 'المبلغ غير صحيح.', [], 400);

  /* ================= Asset lookup ================= */
  $stA = $conn->prepare("SELECT id, is_active FROM assets WHERE code=:c LIMIT 1");
  $stA->execute([':c'=>$assetCode]);
  $assetRow = $stA->fetch(PDO::FETCH_ASSOC);
  if (!$assetRow) respond(false, 'العملة غير موجودة.', [], 400);
  if ((int)$assetRow['is_active'] !== 1) respond(false, 'العملة غير مفعّلة.', [], 400);
  $assetId = (int)$assetRow['id'];

  /* ================= Network lookup ================= */
  $stN = $conn->prepare("
    SELECT id, network_name, fee_amount, min_amount, max_amount
    FROM yc_crypto_asset_networks
    WHERE id=:nid AND asset_code=:ac AND op='withdraw' AND status='active'
    LIMIT 1
  ");
  $stN->execute([':nid'=>$networkId, ':ac'=>$assetCode]);
  $net = $stN->fetch(PDO::FETCH_ASSOC);
  if (!$net) respond(false, 'الشبكة غير متاحة لهذا الأصل/العملية.', [], 400);

  $networkName = (string)$net['network_name'];
  $feeAmount   = clean_decimal_str($net['fee_amount'] ?? '0', false);
  $minAmount   = clean_decimal_str($net['min_amount'] ?? '0', false);
  $maxRaw      = $net['max_amount'];
  $maxAmount   = ($maxRaw === null) ? '' : clean_decimal_str((string)$maxRaw, false);

  if (dec_cmp($minAmount, '0') > 0 && dec_cmp($amountStr, $minAmount) < 0) {
    respond(false, 'المبلغ أقل من الحد الأدنى.', ['min'=>$minAmount], 400);
  }
  if ($maxAmount !== '' && dec_cmp($maxAmount, '0') > 0 && dec_cmp($amountStr, $maxAmount) > 0) {
    respond(false, 'المبلغ أكبر من الحد الأعلى.', ['max'=>$maxAmount], 400);
  }

  $debitStr = dec_add($amountStr, $feeAmount, 18);

  /* ================= Select Provider (REQUIRED here) ================= */
  $providerId = 0;
  $providerName = '';
  $bindingFile = '';

  $hasProviderNetworks = table_exists($conn, 'provider_networks');
  $hasProviders        = table_exists($conn, 'providers');

  if ($hasProviderNetworks && $hasProviders) {
    $stP = $conn->prepare("
      SELECT p.id, p.name, p.binding_file
      FROM provider_networks pn
      JOIN providers p ON p.id = pn.provider_id
      WHERE pn.network_id=:nid
        AND pn.status='active'
        AND p.is_active=1
      ORDER BY p.id ASC
      LIMIT 1
    ");
    $stP->execute([':nid'=>$networkId]);
    $prow = $stP->fetch(PDO::FETCH_ASSOC);
    if ($prow) {
      $providerId = (int)$prow['id'];
      $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 Order + Hold ================= */
  $conn->beginTransaction();

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

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

  if (dec_cmp($availableStr, $debitStr) < 0) {
    $conn->rollBack();
    respond(false, 'لا يوجد رصيد كافي (يشمل الرسوم).', [
      'available'=>$availableStr, 'required'=>$debitStr, 'fee'=>$feeAmount
    ], 400);
  }

  // create order
  $reference = 'WD' . date('ymdHis') . strtoupper(substr(bin2hex(random_bytes(4)), 0, 8));

  $hasStatusReason = column_exists($conn, 'orders', 'status_reason');
  $hasTxHash       = column_exists($conn, 'orders', 'tx_hash');
  $hasCreatedAt    = column_exists($conn, 'orders', 'created_at');
  $hasUpdatedAt    = column_exists($conn, 'orders', 'updated_at');
  $hasProviderCol  = column_exists($conn, 'orders', 'provider_id'); // إن كان موجوداً عندك

  $cols = ['user_id','op','channel','asset_code','route_name','target','amount','fee_amount','status','reference'];
  $vals = [':uid', ':op', ':ch', ':ac', ':rn', ':tg', ':am', ':fee', ':st', ':ref'];
  $params = [
    ':uid'=>$userId,
    ':op'=>'withdraw',
    ':ch'=>'crypto',
    ':ac'=>$assetCode,
    ':rn'=>$networkName,
    ':tg'=>$target,
    ':am'=>$amountStr,
    ':fee'=>$feeAmount,
    ':st'=>'pending',
    ':ref'=>$reference,
  ];

  if ($hasStatusReason) { $cols[]='status_reason'; $vals[]=':sr'; $params[':sr']=null; }
  if ($hasTxHash)       { $cols[]='tx_hash';       $vals[]=':tx'; $params[':tx']=null; }
  if ($hasProviderCol)  { $cols[]='provider_id';   $vals[]=':pid'; $params[':pid']=$providerId; }
  if ($hasCreatedAt)    { $cols[]='created_at';    $vals[]='NOW()'; }
  if ($hasUpdatedAt)    { $cols[]='updated_at';    $vals[]='NOW()'; }

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

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

  // ledger hold
  $hasLedgerCreated = column_exists($conn, 'ledger_entries', 'created_at');

  $noteHold = "Withdraw hold {$assetCode} via {$networkName} (order #{$orderId})";
  $negDebit = dec_sub('0', $debitStr, 18);

  $colsL = ['user_id','asset_id','amount','balance_type','ref_type','ref_id','status','note'];
  $valsL = [':uid',':aid',':amt',':bt',':rt',':rid',':st',':note'];
  if ($hasLedgerCreated) { $colsL[]='created_at'; $valsL[]='NOW()'; }

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

  // available -= debit
  $stL->execute([
    ':uid'=>$userId, ':aid'=>$assetId, ':amt'=>$negDebit,
    ':bt'=>'available', ':rt'=>'withdraw', ':rid'=>$orderId, ':st'=>'posted', ':note'=>$noteHold
  ]);

  // locked += debit
  $stL->execute([
    ':uid'=>$userId, ':aid'=>$assetId, ':amt'=>$debitStr,
    ':bt'=>'locked', ':rt'=>'withdraw', ':rid'=>$orderId, ':st'=>'posted', ':note'=>$noteHold
  ]);

  $conn->commit();

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

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

  $result = provider_execute($conn, ['order_id'=>$orderId, 'provider_id'=>$providerId]);

  // جلب الطلب بعد التنفيذ
  $stOF = $conn->prepare("SELECT * FROM orders WHERE id=:id LIMIT 1");
  $stOF->execute([':id'=>$orderId]);
  $orderFinal = $stOF->fetch(PDO::FETCH_ASSOC) ?: null;

  // نجاح/فشل حسب نتيجة المزود
  if (!empty($result['success'])) {
    respond(true, 'تم إنشاء الطلب وتنفيذه بنجاح.', [
      'order'=>$orderFinal,
      'provider'=>['id'=>$providerId,'name'=>$providerName,'binding_file'=>$bindingFile],
      'execution'=>$result
    ], 200);
  } else {
    respond(false, (string)($result['message'] ?? 'فشل تنفيذ الطلب.'), [
      'order'=>$orderFinal,
      'provider'=>['id'=>$providerId,'name'=>$providerName,'binding_file'=>$bindingFile],
      'execution'=>$result
    ], 400);
  }

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