const express = require("express");
const router = express.Router();
const https = require("https");
const jwt = require("jsonwebtoken");
const { queryOne } = require("../db");

const JWT_SECRET = process.env.JWT_SECRET || require("crypto").randomBytes(32).toString("hex");

// 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;
      return next();
    }
    if (header && header.startsWith("Bearer ")) {
      const token = header.split(" ")[1];
      const decoded = jwt.verify(token, JWT_SECRET);
      const user = await queryOne("SELECT id, email, balance FROM users WHERE id = ?", [decoded.id]);
      if (!user) return res.status(401).json({ message: "User not found" });
      req.user = user;
      return next();
    }
    return res.status(401).json({ message: "Unauthorized" });
  } catch (err) {
    return res.status(401).json({ message: "Invalid token" });
  }
}

// Simple HTTP POST helper
function httpsPost(url, data, headers = {}, timeoutMs = 15000) {
  return new Promise((resolve, reject) => {
    const payload = new URLSearchParams(data).toString();
    const parsed = new URL(url);
    const options = {
      hostname: parsed.hostname,
      path: parsed.pathname + parsed.search,
      method: "POST",
      headers: { 
        "Content-Type": "application/x-www-form-urlencoded", 
        "Content-Length": Buffer.byteLength(payload),
        ...headers 
      },
      timeout: timeoutMs,
    };
    const req = https.request(options, (res) => {
      let body = "";
      res.on("data", c => body += c);
      res.on("end", () => {
        try { resolve({ status: res.statusCode, data: JSON.parse(body) }); }
        catch { resolve({ status: res.statusCode, data: body }); }
      });
    });
    req.on("timeout", () => { req.destroy(); reject(new Error("timeout")); });
    req.on("error", reject);
    req.write(payload);
    req.end();
  });
}

// Simple HTTP GET helper
function httpsGet(url, headers = {}, timeoutMs = 15000) {
  return new Promise((resolve, reject) => {
    const parsed = new URL(url);
    const options = {
      hostname: parsed.hostname,
      path: parsed.pathname + parsed.search,
      method: "GET",
      headers,
      timeout: timeoutMs,
    };
    const req = https.request(options, (res) => {
      let body = "";
      res.on("data", c => body += c);
      res.on("end", () => {
        try { resolve({ status: res.statusCode, data: JSON.parse(body) }); }
        catch { resolve({ status: res.statusCode, data: body }); }
      });
    });
    req.on("timeout", () => { req.destroy(); reject(new Error("timeout")); });
    req.on("error", reject);
    req.end();
  });
}

const user_agents = [
  "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36",
  "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36",
  "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:123.0) Gecko/20100101 Firefox/123.0",
  "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36"
];

function getHeaders(email) {
  let hash = 0;
  for (let i = 0; i < email.length; i++) hash = Math.imul(31, hash) + email.charCodeAt(i) | 0;
  const idx = Math.abs(hash) % user_agents.length;
  return {
    "User-Agent": user_agents[idx],
    "Accept": "application/json, text/plain, */*",
    "Accept-Language": "en-US,en;q=0.9"
  };
}

async function getAccessToken(email, refresh_token, client_id) {
  const token_url = "https://login.microsoftonline.com/common/oauth2/v2.0/token";
  const headers = getHeaders(email);
  let lastError = "Unknown error";

  for (let attempt = 1; attempt <= 3; attempt++) {
    try {
      // 1. Request with scope
      let data = {
        client_id,
        grant_type: "refresh_token",
        refresh_token,
        scope: "https://graph.microsoft.com/Mail.Read offline_access"
      };
      let res = await httpsPost(token_url, data, headers);
      if (res.status === 200 && res.data.access_token) {
        return { success: true, token: res.data.access_token, new_refresh: res.data.refresh_token || refresh_token };
      }

      // 2. Fallback without scope
      data = { client_id, grant_type: "refresh_token", refresh_token };
      let fb_res = await httpsPost(token_url, data, headers);
      if (fb_res.status === 200 && fb_res.data.access_token) {
        return { success: true, token: fb_res.data.access_token, new_refresh: fb_res.data.refresh_token || refresh_token };
      } else {
        const error = fb_res.data.error_description || fb_res.data.error || "Unknown error";
        lastError = error;
        if (error.includes("AADSTS50196") || error.includes("request loop") || error.includes("temporarily_unavailable")) {
          if (attempt < 3) {
            await new Promise(r => setTimeout(r, 2000 * attempt + Math.random() * 1000));
            continue;
          }
        }
      }
    } catch (e) {
      lastError = e.message;
    }
    break; // Break if not a retryable error
  }
  return { success: false, error: lastError };
}

async function getMessages(access_token) {
  const url = "https://graph.microsoft.com/v1.0/me/messages?$top=10&$orderby=receivedDateTime%20desc";
  const headers = {
    "Authorization": `Bearer ${access_token}`,
    "Accept": "application/json"
  };
  try {
    const res = await httpsGet(url, headers);
    if (res.status === 200 && res.data.value) return res.data.value;
  } catch (e) {}
  return [];
}

function parseEmailContent(subject, from_addr, bodyPreview) {
  let platform = "Unknown";
  const sender = from_addr.toLowerCase();
  
  if (sender.includes("facebook")) platform = "Facebook";
  else if (sender.includes("instagram")) platform = "Instagram";
  else if (sender.includes("google")) platform = "Google";
  else if (sender.includes("microsoft")) platform = "Microsoft";
  else if (sender.includes("tiktok")) platform = "TikTok";

  const searchArea = `${subject} ${bodyPreview}`;
  const match = searchArea.match(/\b\d{4,8}\b/);
  const code = match ? match[0] : "N/A";
  
  return { platform, code, subject };
}

function extractOTP(messages, submit_time) {
  if (!messages || !Array.isArray(messages)) return { found: false };
  
  for (const mail of messages) {
    if (mail.receivedDateTime) {
      try {
        const receivedTime = new Date(mail.receivedDateTime);
        // Look for messages received within the last 5 minutes from submit_time
        if (receivedTime.getTime() > submit_time - (5 * 60 * 1000)) {
          const subject = mail.subject || "";
          const from_addr = (mail.from && mail.from.emailAddress) ? mail.from.emailAddress.address : "";
          const bodyPreview = mail.bodyPreview || "";
          
          const result = parseEmailContent(subject, from_addr, bodyPreview);
          if (result.code !== "N/A") {
            return { found: true, ...result };
          }
        }
      } catch (e) {}
    }
  }
  return { found: false };
}

/**
 * POST /zapi/otp/check-hotmail
 * Expects { account: "email|pass|refresh_token|client_id" }
 */
router.post("/check-hotmail", auth, async (req, res) => {
  try {
    const { account } = req.body;
    if (!account) return res.status(400).json({ status: "error", message: "Account data missing" });
    
    const parts = account.split("|");
    if (parts.length < 3) return res.status(400).json({ status: "error", message: "Invalid format" });
    
    const email = parts[0].trim();
    const pass = parts[1].trim();
    const refresh_token = parts[2].trim();
    const client_id = (parts[3] ? parts[3].trim() : "") || "9e5f94bc-e8a4-4e73-b8be-63364c29d753";
    
    const submit_time = Date.now();

    // 1. Get Access Token
    const authResult = await getAccessToken(email, refresh_token, client_id);
    if (!authResult.success) {
      return res.json({ status: "error", email, message: "Login Failed" });
    }

    // 2. Get Messages
    const messages = await getMessages(authResult.token);
    
    // 3. Extract OTP
    const otpResult = extractOTP(messages, submit_time);
    if (otpResult.found) {
      return res.json({ status: "success", email, platform: otpResult.platform, code: otpResult.code, subject: otpResult.subject });
    } else {
      return res.json({ status: "not_found", email, message: "No recent OTP found" });
    }
    
  } catch (e) {
    console.error("[OTP Tool]", e.message);
    res.status(500).json({ status: "error", message: "Server error" });
  }
});

module.exports = router;
