import jwt from "jsonwebtoken";
import db from "../models/index.js";
import bcrypt from "bcryptjs";

const { Admin, Merchant } = db;

const normalizeIp = (ip) => {
  if (!ip) return "";
  let clean = ip.trim();
  if (clean.startsWith("::ffff:")) {
    clean = clean.substring(7);
  }
  if (clean === "::1") {
    clean = "127.0.0.1";
  }
  return clean;
};

const ipMatches = (clientIp, allowedIp) => {
  return normalizeIp(clientIp) === normalizeIp(allowedIp);
};

/**
 * SuperAdmin/Admin Dashboard Auth
 */
export const authenticateAdmin = async (req, res, next) => {
  try {
    const authHeader = req.headers.authorization;
    if (!authHeader || !authHeader.startsWith("Bearer ")) {
      return res.status(401).json({ success: false, message: "Unauthorized: No token provided" });
    }

    const token = authHeader.split(" ")[1];
    const decoded = jwt.verify(token, process.env.JWT_SECRET || "airpero_super_secret_key");

    const admin = await Admin.findByPk(decoded.id);
    if (!admin) {
      return res.status(401).json({ success: false, message: "Unauthorized: Invalid admin account" });
    }

    if (admin.status === "suspended") {
      return res.status(403).json({ success: false, message: "Account blocked: Please reach out to support" });
    }

    if (admin.status === "inactive") {
      await admin.update({ status: "active", lastActivityAt: new Date() });
    } else {
      admin.update({ lastActivityAt: new Date() }).catch(() => {});
    }

    req.admin = admin;
    next();
  } catch (error) {
    console.error("❌ Admin Auth Error:", error.message);
    return res.status(401).json({ success: false, message: "Unauthorized: Invalid or expired token" });
  }
};

export const authorizeSuperAdmin = async (req, res, next) => {
  if (req.admin.role !== "superadmin") {
    return res.status(403).json({ success: false, message: "Forbidden: SuperAdmin access required" });
  }

  // --- SuperAdmin IP whitelist check disabled (per request) ---
  // try {
  //   const clientIp = req.ip;
  //
  //   // 1. Check the database for active whitelisted IPs
  //   const dbWhitelists = await db.AdminIpWhitelist.findAll({ where: { status: "active" } });
  //
  //   if (dbWhitelists.length > 0) {
  //     // If there are IPs in the database, ONLY those are allowed
  //     const allowedIps = dbWhitelists.map(entry => entry.ipAddress);
  //     const isAllowed = allowedIps.some(allowedIp => ipMatches(clientIp, allowedIp));
  //
  //     if (!isAllowed) {
  //       console.warn(`[SECURITY] Forbidden SuperAdmin access attempt from IP ${clientIp} (not in DB whitelist)`);
  //       return res.status(403).json({ success: false, message: "Forbidden: IP not authorized for SuperAdmin access" });
  //     }
  //   } else {
  //     // 2. Fallback: If no IPs in DB, use the .env SUPERADMIN_ALLOWED_IPS as a safety net
  //     const allowedIpsEnv = process.env.SUPERADMIN_ALLOWED_IPS || "127.0.0.1,::1";
  //     const allowedIps = allowedIpsEnv.split(",").map(ip => ip.trim());
  //     const isAllowed = allowedIps.some(allowedIp => ipMatches(clientIp, allowedIp));
  //
  //     if (!isAllowed) {
  //       console.warn(`[SECURITY] Forbidden SuperAdmin access attempt from IP ${clientIp} (not in ENV whitelist)`);
  //       return res.status(403).json({ success: false, message: "Forbidden: IP not authorized for SuperAdmin access" });
  //     }
  //   }
  //
  //   next();
  // } catch (error) {
  //   console.error("❌ SuperAdmin IP Check Error:", error.message);
  //   return res.status(500).json({ success: false, message: "Internal server error during IP authorization" });
  // }

  next();
};

/**
 * Merchant API Key Auth (Server-to-Server)
 */
export const authenticateMerchantAPIKey = async (req, res, next) => {
  try {
    const publicKey = req.headers["x-public-key"];
    const privateKey = req.headers["x-private-key"];

    if (!publicKey || !privateKey) {
        return res.status(401).json({ success: false, message: "Unauthorized: Missing API Keys in headers" });
    }

    const merchant = await Merchant.findOne({ where: { publicKey } });
    if (!merchant) {
        return res.status(401).json({ success: false, message: "Invalid Merchant API Keys" });
    }

    if (merchant.status === "suspended") {
        return res.status(403).json({ success: false, message: "Account blocked: Please reach out to support" });
    }

    if (merchant.status === "inactive") {
        await merchant.update({ status: "active", lastActivityAt: new Date() });
    } else {
        merchant.update({ lastActivityAt: new Date() }).catch(() => {});
    }

    // If using live public key, enforce live mode approval
    const isLiveKey = publicKey.startsWith("pk_live_") || publicKey === merchant.livePublicKey;
    if (isLiveKey && (!merchant.isLiveMode || merchant.kybStatus !== "approved")) {
      return res.status(403).json({
        success: false,
        message: "Live Mode access requires an approved KYB application. Please complete KYB verification in your dashboard to unlock live payment processing.",
        kybStatus: merchant.kybStatus || "unsubmitted",
        actionRequired: "COMPLETE_KYB",
        kybUrl: "/dashboard/kyb",
      });
    }

    let isMatch = false;
    if (isLiveKey && merchant.livePrivateKey) {
      isMatch = await bcrypt.compare(privateKey, merchant.livePrivateKey);
    } else if (merchant.privateKey) {
      isMatch = await bcrypt.compare(privateKey, merchant.privateKey);
    }

    if (!isMatch) {
        return res.status(401).json({ success: false, message: "Invalid API Keys" });
    }

    // Check IP Whitelist if configured
    const whitelists = await db.MerchantIpWhitelist.findAll({
      where: { merchantId: merchant.id, status: "active" },
    });
    if (whitelists.length > 0) {
      const allowedIps = whitelists.map((entry) => entry.ipAddress);
      const clientIp = req.ip;
      const isAllowed = allowedIps.some(allowedIp => ipMatches(clientIp, allowedIp));
      if (!isAllowed) {
        console.warn(`[SECURITY] Blocked API Key request from unwhitelisted IP ${clientIp} for merchant ${merchant.id}`);
        return res.status(403).json({ success: false, message: "Forbidden: IP Address not whitelisted" });
      }
    }

    req.merchant = merchant;
    next();
  } catch (error) {
    console.error("❌ API Key Auth Error:", error.message);
    return res.status(401).json({ success: false, message: "Unauthorized: API Key authentication failed" });
  }
};

/**
 * Require Approved Live Mode Middleware
 * Restricts live payment capabilities to merchants with approved KYB.
 */
export const requireLiveMode = async (req, res, next) => {
  if (!req.merchant) {
    return res.status(401).json({ success: false, message: "Unauthorized" });
  }

  if (!req.merchant.isLiveMode || req.merchant.kybStatus !== "approved") {
    return res.status(403).json({
      success: false,
      message: "Live mode access requires an approved KYB application. Please complete KYB verification in your dashboard to unlock live payment processing.",
      kybStatus: req.merchant.kybStatus || "unsubmitted",
      actionRequired: "COMPLETE_KYB",
      kybUrl: "/dashboard/kyb",
    });
  }

  next();
};

/**
 * Merchant Dashboard Auth (JWT)
 */
export const authenticateMerchantJWT = async (req, res, next) => {
  try {
    const authHeader = req.headers.authorization;
    if (!authHeader || !authHeader.startsWith("Bearer ")) {
      return res.status(401).json({ success: false, message: "Unauthorized: No dashboard token provided" });
    }

    const token = authHeader.split(" ")[1];
    const decoded = jwt.verify(token, process.env.JWT_SECRET || "airpero_super_secret_key");

    const merchant = await Merchant.findByPk(decoded.id);
    if (!merchant) {
        return res.status(401).json({ success: false, message: "Invalid merchant session" });
    }

    if (merchant.status === "suspended") {
        return res.status(403).json({ success: false, message: "Account blocked: Please reach out to support" });
    }

    if (merchant.status === "inactive") {
        await merchant.update({ status: "active", lastActivityAt: new Date() });
    } else {
        merchant.update({ lastActivityAt: new Date() }).catch(() => {});
    }

    // Update last activity
    merchant.update({ lastActivityAt: new Date() }).catch(() => {});

    // Check IP Whitelist if configured
    const whitelists = await db.MerchantIpWhitelist.findAll({
      where: { merchantId: merchant.id, status: "active" },
    });
    if (whitelists.length > 0) {
      const allowedIps = whitelists.map((entry) => entry.ipAddress);
      const clientIp = req.ip;
      const isAllowed = allowedIps.some(allowedIp => ipMatches(clientIp, allowedIp));
      if (!isAllowed) {
        console.warn(`[SECURITY] Blocked JWT request from unwhitelisted IP ${clientIp} for merchant ${merchant.id}`);
        return res.status(403).json({ success: false, message: "Forbidden: IP Address not whitelisted" });
      }
    }

    req.merchant = merchant;
    next();
  } catch (error) {
    console.error("❌ Merchant JWT Auth Error:", error.message);
    return res.status(401).json({ success: false, message: "Unauthorized: Session expired or invalid" });
  }
};

/**
 * Unified Merchant Auth (Allows either API Key or JWT)
 * Useful for common resources.
 */
export const authenticateMerchant = async (req, res, next) => {
    const publicKey = req.headers["x-public-key"];
    const authHeader = req.headers.authorization;

    if (publicKey) return authenticateMerchantAPIKey(req, res, next);
    if (authHeader) return authenticateMerchantJWT(req, res, next);

    return res.status(401).json({ success: false, message: "Unauthorized: No valid credentials provided" });
};
