const express = require("express");
const jwt = require("jsonwebtoken");
const { query, queryOne, insert, transaction } = require("../db");
const { notifyNewOrder } = require("../telegram");
const { v4: uuidv4 } = require("uuid");

const router = express.Router();
const JWT_SECRET = process.env.JWT_SECRET || require("crypto").randomBytes(32).toString("hex");
const UPSTREAM_API_KEY = process.env.UPSTREAM_API_KEY || "";
const UPSTREAM_BASE_URL = "https://shopmailmmo.store/v1";
const PHONE_API_KEY = process.env.PHONE_API_KEY || "e2d13a0a094869a09cea53ad3c36110459aabc5c261e5ca5";

// Auth middleware
async function auth(req, res, next) {
  const header = req.headers.authorization;
  const apiKey = req.headers["x-api-key"];

  try {
    if (apiKey) {
      const user = await queryOne("SELECT * FROM users WHERE apiKey = ?", [apiKey]);
      if (!user) return res.status(401).json({ message: "Invalid API key" });
      req.user = user;
      req.user.balance = parseFloat(user.balance);
      return next();
    }

    if (!header) return res.status(401).json({ message: "No token provided" });
    const token = header.replace("Bearer ", "");
    const decoded = jwt.verify(token, JWT_SECRET);
    const user = await queryOne("SELECT * FROM users WHERE id = ?", [decoded.id]);
    if (!user) return res.status(401).json({ message: "User not found" });
    req.user = user;
    req.user.balance = parseFloat(user.balance);
    next();
  } catch {
    res.status(401).json({ message: "Invalid token" });
  }
}

function delay(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

/**
 * ទិញ Gmail ពី shopmailmmo.store
 */
async function getMailFromUpstream() {
  if (!UPSTREAM_API_KEY) return null;

  for (let i = 0; i < 3; i++) {
    try {
      const response = await fetch(`${UPSTREAM_BASE_URL}/orders?service=facebook`, {
        method: "POST",
        headers: { "api_key": UPSTREAM_API_KEY },
      });

      if (response.ok) {
        const data = await response.json();
        if (data.error) {
          console.log("[Upstream] get_mail:", data.error);
          return { error: data.error };
        }
        if (data.mail && data.order_id) {
          return { mail: data.mail, orderId: data.order_id };
        }
      }
      await delay(1000);
    } catch (err) {
      console.error("[Upstream] get_mail:", err.message);
      await delay(1000);
    }
  }
  return { error: "Cannot connect to provider" };
}

/**
 * យក OTP ពី shopmailmmo.store — poll រៀងរាល់ 5 វិ រហូតដល់ 6 នាទី
 */
async function getOtpFromUpstream(upstreamOrderId) {
  if (!UPSTREAM_API_KEY || !upstreamOrderId) return null;

  const timeout = 360;
  const start = Date.now();
  let attempt = 0;

  while ((Date.now() - start) / 1000 < timeout) {
    attempt++;
    try {
      const response = await fetch(`${UPSTREAM_BASE_URL}/otp?id=${upstreamOrderId}`, {
        method: "POST",
        headers: { "api_key": UPSTREAM_API_KEY },
      });

      if (response.ok) {
        const data = await response.json();
        console.log(`[OTP] attempt ${attempt} id=${upstreamOrderId}:`, JSON.stringify(data));
        if (data.error) { await delay(5000); continue; }
        if (data.otp && data.otp !== "") return data.otp;
      } else {
        console.log(`[OTP] HTTP ${response.status} attempt ${attempt}`);
      }
      await delay(5000);
    } catch (err) {
      console.error("[OTP] get_otp error:", err.message);
      await delay(5000);
    }
  }
  return null;
}

/**
 * យកលេខទូរសព្ទពី angkorphonesms.shop
 */
async function getPhoneFromUpstream(countryCode = 'us') {
  for (let i = 0; i < 3; i++) {
    try {
      const response = await fetch(`https://angkorphonesms.shop/v1/api/create-order.php?key=${PHONE_API_KEY}&category=fb&country=${countryCode}`);
      if (response.ok) {
        const data = await response.json();
        if (data.error) {
          console.log("[Upstream Phone] get_phone:", data.error);
          return { error: data.error };
        }
        if (data.phone && data.order_id) {
          return { phone: data.phone, orderId: data.order_id };
        }
      }
      await delay(1000);
    } catch (err) {
      console.error("[Upstream Phone] get_phone:", err.message);
      await delay(1000);
    }
  }
  return { error: "Cannot connect to provider" };
}

/**
 * ឆែកលេខកូដ SMS ម្តង
 */
async function checkPhoneOtpOnce(orderId) {
  if (!orderId) return null;
  try {
    const response = await fetch(`https://angkorphonesms.shop/v1/api/check-otp.php?id=${orderId}&key=${PHONE_API_KEY}`);
    if (response.ok) {
      const data = await response.json();
      if (data.otp && data.otp !== "") return data.otp;
    }
  } catch (err) {
    console.error("[Phone OTP Check]", err.message);
  }
  return null;
}

// POST /zapi/orders — ទិញ Gmail OTP / ទិញលេខទូរសព្ទ
router.post("/", auth, async (req, res) => {
  try {
    const { service: serviceId, quantity = 1 } = req.body;
    let parsedQty = parseInt(quantity, 10);
    if (isNaN(parsedQty) || parsedQty < 1) parsedQty = 1;
    if (parsedQty > 50) {
      return res.status(400).json({ message: "ចំនួនអតិបរមាគឺ 50 ក្នុងមួយ order" });
    }
    const qty = Math.max(1, parsedQty);

    let service = await queryOne(
      "SELECT * FROM services WHERE id = ?",
      [serviceId]
    );
    // Fallbacks if not explicitly found
    if (!service) {
      if (serviceId === 'gmail_otp') service = { id: 'gmail_otp', price: 0.055 };
      else if (serviceId === 'phone_sms_us') service = { id: 'phone_sms_us', price: 0.032 };
      else if (serviceId === 'phone_sms_kh') service = { id: 'phone_sms_kh', price: 0.032 };
      else return res.status(404).json({ message: "Service not found" });
    }

    // Price calculation
    let price = parseFloat(service.price) || 0.055;
    if ((service.id === 'gmail_otp' || serviceId === 'gmail_otp') && price < 0.055) {
      price = 0.055;
    } else if (serviceId.startsWith('phone_sms') && price < 0.032) {
      price = 0.032;
    }
    const total = parseFloat((qty * price).toFixed(3));

    // Use transaction for balance deduction (prevents race conditions!)
    let newBalance;
    try {
      newBalance = await transaction(async (conn) => {
        // Lock the user row for update
        const [rows] = await conn.execute(
          "SELECT balance FROM users WHERE id = ? FOR UPDATE",
          [req.user.id]
        );
        const currentBalance = parseFloat(rows[0].balance);

        if (currentBalance < total) {
          throw new Error(`INSUFFICIENT_BALANCE:${total}:${currentBalance}`);
        }

        const updatedBalance = parseFloat((currentBalance - total).toFixed(3));
        await conn.execute("UPDATE users SET balance = ? WHERE id = ?", [updatedBalance, req.user.id]);
        return updatedBalance;
      });
    } catch (err) {
      if (err.message.startsWith("INSUFFICIENT_BALANCE:")) {
        const [, needed, have] = err.message.split(":");
        return res.status(400).json({
          message: `Balance មិនគ្រប់គ្រាន់ — ត្រូវការ $${parseFloat(needed).toFixed(3)} មាន $${parseFloat(have).toFixed(3)}`
        });
      }
      throw err;
    }

    // Buy from upstream
    let items = [];
    let boughtQty = 0;
    
    if (serviceId.startsWith('phone_sms')) {
      const countryCode = serviceId.endsWith('_kh') ? 'kh' : 'us';
      for (let i = 0; i < qty; i++) {
        const result = await getPhoneFromUpstream(countryCode);
        if (!result || result.error) break;
        items.push({ mail: result.phone, upstreamOrderId: result.orderId, otp: "" });
        boughtQty++;
      }
    } else {
      if (!UPSTREAM_API_KEY) {
        await query("UPDATE users SET balance = balance + ? WHERE id = ?", [total, req.user.id]);
        return res.status(500).json({ message: "System error — សូមទាក់ទង Admin" });
      }
      for (let i = 0; i < qty; i++) {
        const result = await getMailFromUpstream();
        if (!result || result.error) break;
        items.push({ mail: result.mail, upstreamOrderId: result.orderId, otp: "" });
        boughtQty++;
      }
    }

    if (boughtQty === 0) {
      await query("UPDATE users SET balance = balance + ? WHERE id = ?", [total, req.user.id]);
      const refundedUser = await queryOne("SELECT balance FROM users WHERE id = ?", [req.user.id]);
      return res.status(400).json({
        message: "Stock អស់ហើយ ឬ មិនអាចទាក់ទង provider បាន",
        newBalance: parseFloat(refundedUser.balance),
      });
    }

    let actualTotal = total;
    if (boughtQty < qty) {
      const refundAmt = parseFloat(((qty - boughtQty) * price).toFixed(3));
      actualTotal = parseFloat((boughtQty * price).toFixed(3));
      await query("UPDATE users SET balance = balance + ? WHERE id = ?", [refundAmt, req.user.id]);
    }

    // Save order to MySQL
    const orderId = uuidv4();
    await insert(
      `INSERT INTO orders (id, userId, username, service, qty, total, status, createdAt)
       VALUES (?, ?, ?, ?, ?, ?, 'pending', ?)`,
      [orderId, req.user.id, req.user.username, service.id, boughtQty, actualTotal, new Date()]
    );

    // Save order items
    for (const item of items) {
      await insert(
        `INSERT INTO order_items (orderId, mail, upstreamOrderId, otp) VALUES (?, ?, ?, ?)`,
        [orderId, item.mail, item.upstreamOrderId, item.otp]
      );
    }

    // Notify Telegram
    const order = {
      id: orderId,
      userId: req.user.id,
      username: req.user.username,
      service: service.id,
      qty: boughtQty,
      total: actualTotal,
      items,
      status: "pending",
      createdAt: new Date().toISOString(),
    };
    notifyNewOrder(order);

    // Response
    res.json({
      message: "សូមចុចប៊ូតុង ឆែក OTP ដើម្បីយកកូដ...",
      order: {
        id: orderId,
        service: service.id,
        qty, total,
        items: items.map(it => ({ mail: it.mail, otp: it.otp || "រង់ចាំ..." })),
        status: "pending",
        createdAt: order.createdAt,
      },
      newBalance,
    });

    // We no longer auto fetch OTP in the background. User must manually click Check OTP.
  } catch (err) {
    console.error("[Orders] Error:", err.message);
    res.status(500).json({ message: "Server error — សូមព្យាយាមម្ដងទៀត" });
  }
});

// Background OTP fetch (Disabled)
// Auto-fetching OTP in background is disabled by user request.
// User must manually check OTP.
async function fetchOtpBackground(orderId, items) {
  // Function intentionally disabled.
}

/**
 * Quick OTP check (1 attempt)
 */
async function checkOtpOnce(orderId) {
  if (!UPSTREAM_API_KEY || !orderId) return null;
  try {
    const response = await fetch(`${UPSTREAM_BASE_URL}/otp?id=${orderId}`, {
      method: "POST",
      headers: { "api_key": UPSTREAM_API_KEY },
    });
    if (response.ok) {
      const data = await response.json();
      if (data.otp && data.otp !== "") return data.otp;
    }
  } catch (err) {
    console.error("[OTP Check]", err.message);
  }
  return null;
}

/**
 * POST /zapi/orders/:id/fetch-otp
 */
router.post("/:id/fetch-otp", auth, async (req, res) => {
  try {
    const order = await queryOne(
      "SELECT * FROM orders WHERE id = ? AND userId = ?",
      [req.params.id, req.user.id]
    );
    if (!order) return res.status(404).json({ message: "Order not found" });

    const items = await query("SELECT * FROM order_items WHERE orderId = ?", [order.id]);
    const isRecheck = order.status === "success";

    let anyFound = false;
    for (let i = 0; i < items.length; i++) {
      const item = items[i];
      if (!item.upstreamOrderId) continue;
      if (!isRecheck && item.otp && item.otp !== "" && item.otp !== "expired") continue;

      let otp;
      if (order.service.startsWith('phone_sms')) {
        otp = await checkPhoneOtpOnce(item.upstreamOrderId);
      } else {
        otp = await checkOtpOnce(item.upstreamOrderId);
      }
      
      if (otp) {
        items[i].otp = otp;
        anyFound = true;
        await query(
          "UPDATE order_items SET otp = ? WHERE id = ?",
          [otp, item.id]
        );
        console.log(`[OTP] ${isRecheck ? "re-check" : "check"} ${item.upstreamOrderId} → ${otp}`);
      }
    }

    // Update order status
    if (anyFound) {
      const allDone = items.every(it => it.otp && it.otp !== "" && it.otp !== "expired");
      const newStatus = allDone ? "success" : "pending";
      await query("UPDATE orders SET status = ? WHERE id = ?", [newStatus, order.id]);
      order.status = newStatus;
    }

    // Expiry check
    if (!isRecheck && !anyFound) {
      const age = (Date.now() - new Date(order.createdAt).getTime()) / 1000;
      const maxAge = order.service.startsWith('phone_sms') ? 1200 : 360; // 20 mins vs 6 mins
      const durationText = order.service.startsWith('phone_sms') ? "20 នាទី" : "6 នាទី";
      
      if (age > maxAge) {
        const updateResult = await query("UPDATE orders SET status = 'failed' WHERE id = ? AND status = 'pending'", [order.id]);
        if (updateResult.affectedRows > 0) {
          await query("UPDATE order_items SET otp = 'expired' WHERE orderId = ? AND (otp = '' OR otp IS NULL)", [order.id]);
          await query("UPDATE users SET balance = balance + ? WHERE id = ?", [parseFloat(order.total) || 0, order.userId]);
          items.forEach(it => { if (!it.otp || it.otp === "") it.otp = 'expired'; });
          return res.json({ status: "failed", items, message: `OTP ផុតកំណត់ (${durationText}) — ប្រាក់ត្រូវបានបង្វិលចូលគណនីវិញ!` });
        } else {
          return res.json({ status: "failed", items, message: `OTP ផុតកំណត់ (${durationText})` });
        }
      }
    }

    res.json({
      status: order.status,
      items,
      message: anyFound
        ? (isRecheck ? "✅ Re-check OTP: " + (items[0]?.otp || "") : "✅ OTP បានទទួល!")
        : (isRecheck ? "OTP ផ្លាស់ប្ដូររួចហើយ ឬ ផុតកំណត់" : "OTP នៅមិនទាន់មក — ចុចឆែកម្ដងទៀត"),
    });
  } catch (err) {
    console.error("[fetch-otp]", err.message);
    res.status(500).json({ message: "Server error — សូមព្យាយាមម្ដងទៀត" });
  }
});

// GET /zapi/orders — order history
router.get("/", auth, async (req, res) => {
  try {
    const orders = await query(
      "SELECT * FROM orders WHERE userId = ? ORDER BY createdAt DESC LIMIT 100",
      [req.user.id]
    );

    // Attach items to each order
    for (const order of orders) {
      order.items = await query("SELECT * FROM order_items WHERE orderId = ?", [order.id]);
      order.total = parseFloat(order.total);
    }

    res.json(orders);
  } catch (err) {
    console.error("[Orders GET]", err.message);
    res.status(500).json({ message: "Server error" });
  }
});

// GET /zapi/orders/:id — single order
router.get("/:id", auth, async (req, res) => {
  try {
    const order = await queryOne(
      "SELECT * FROM orders WHERE id = ? AND userId = ?",
      [req.params.id, req.user.id]
    );
    if (!order) return res.status(404).json({ message: "Order not found" });

    order.items = await query("SELECT * FROM order_items WHERE orderId = ?", [order.id]);
    order.total = parseFloat(order.total);
    res.json(order);
  } catch (err) {
    res.status(500).json({ message: "Server error" });
  }
});

/**
 * ⚡ STARTUP RECOVERY — resume pending OTP fetches
 */
async function recoverPendingOrders() {
  if (!UPSTREAM_API_KEY) return;
  await delay(2000);

  try {
    const pending = await query(
      `SELECT o.* FROM orders o
       INNER JOIN order_items oi ON oi.orderId = o.id
       WHERE o.status = 'pending' AND (oi.otp = '' OR oi.otp IS NULL)
       GROUP BY o.id`
    );

    if (pending.length === 0) {
      console.log("[OTP Recovery] No pending orders to recover.");
      return;
    }

    console.log(`[OTP Recovery] Resuming ${pending.length} pending order(s)...`);
    for (const order of pending) {
      const age = (Date.now() - new Date(order.createdAt).getTime()) / 1000;
      const maxAge = order.service.startsWith('phone_sms') ? 1200 : 360;

      if (age > maxAge) {
        const updateResult = await query("UPDATE orders SET status = 'failed' WHERE id = ? AND status = 'pending'", [order.id]);
        if (updateResult.affectedRows > 0) {
          await query("UPDATE order_items SET otp = 'expired' WHERE orderId = ? AND (otp = '' OR otp IS NULL)", [order.id]);
          await query("UPDATE users SET balance = balance + ? WHERE id = ?", [parseFloat(order.total) || 0, order.userId]);
          console.log(`[OTP Recovery] Order ${order.id} → expired (age ${Math.floor(age)}s) - Refunded ${order.total}`);
        }
      } else {
        console.log(`[OTP Recovery] Order ${order.id} is pending (age ${Math.floor(age)}s). Waiting for manual check.`);
      }
    }
  } catch (err) {
    console.error("[OTP Recovery] Error:", err.message);
  }
}

// Run recovery on startup and periodically (every 1 min) to cleanup and refund expired orders
recoverPendingOrders();
setInterval(recoverPendingOrders, 60 * 1000);

module.exports = router;
