import db from "../models/index.js";
import PsbService from "../thirdParties/psbService.js";
import { v4 as uuidv4 } from "uuid";
import { Op } from "sequelize";
import YouverifyService from "../thirdParties/youVerifyService.js";
import PayscribeService from "../thirdParties/payscribeService.js";
import { calculateSaaSFee } from "../utils/feeCalculator.js";

const { Customer, Transaction, Merchant, PayscribePerson, sequelize } = db;

class CustomerController {
  /**
   * Create a new customer under a merchant and assign a virtual 9PSB account.
   */
  static async createCustomer(req, res) {
    try {
      const { fullName, email, phoneNumber } = req.body;
      const merchantId = req.merchant.id;

      if (!fullName || !email) {
        return res.status(400).json({ success: false, message: "Missing required fields" });
      }

      const existingCustomer = await Customer.findOne({ where: { email, merchantId } });
      if (existingCustomer) {
        return res.status(400).json({ success: false, message: "Customer with this email already exists" });
      }

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

      const customer = await Customer.create({
        merchantId,
        fullName,
        email,
        phoneNumber,
      });

      const reference = `CUST-VA-${uuidv4().slice(0, 8)}`;
      let accountNumber = null;

      if (req.isLiveMode) {
        // Provision live 9PSB virtual account number
        const psbAccount = await PsbService.createStaticAccount({
          reference,
          amount: 0,
          description: `Virtual account for ${fullName}`,
          name: `${req.merchant.preview || req.merchant.businessName} / ${fullName}`,
        });

        if (psbAccount && psbAccount.customer?.account?.number) {
          accountNumber = psbAccount.customer.account.number;
        }
      } else {
        // Sandbox Mode: Generate test mock account number
        accountNumber = `99${Math.floor(10000000 + Math.random() * 90000000)}`;
      }

      if (accountNumber) {
        await customer.update({ accountNumber });
      }

      return res.status(201).json({
        success: true,
        message: "Customer created successfully",
        data: customer,
      });
    } catch (error) {
      console.error("❌ createCustomer error:", error);
      return res.status(500).json({
        success: false,
        message: "Failed to create customer",
        error: error.message,
      });
    }
  }

  /**
   * Get customer transaction summary (Reporting)
   */
  static async getCustomerReport(req, res) {
    try {
      const { customerId } = req.params;
      const merchantId = req.merchant.id;
      const { startDate, endDate, period } = req.query;

      // Verify customer belongs to merchant
      const customer = await Customer.findOne({ where: { id: customerId, merchantId } });
      if (!customer) {
        return res.status(404).json({ success: false, message: "Customer not found or not owned by you" });
      }

      let whereClause = { customerId, merchantId };

      if (startDate && endDate) {
        whereClause.createdAt = {
          [Op.between]: [new Date(startDate), new Date(endDate)],
        };
      } else if (period) {
        const now = new Date();
        if (period === "daily") {
          now.setHours(0, 0, 0, 0);
          whereClause.createdAt = { [Op.gte]: now };
        } else if (period === "monthly") {
          now.setDate(1);
          now.setHours(0, 0, 0, 0);
          whereClause.createdAt = { [Op.gte]: now };
        } else if (period === "yearly") {
          now.setMonth(0, 1);
          now.setHours(0, 0, 0, 0);
          whereClause.createdAt = { [Op.gte]: now };
        }
      }

      const transactions = await Transaction.findAll({ where: whereClause });

      let totalVolume = 0;
      let totalCredit = 0;
      let totalDebit = 0;

      transactions.forEach((tx) => {
        const amount = parseFloat(tx.amount);
        totalVolume += amount;
        if (tx.type === "credit") {
          totalCredit += amount;
        } else if (tx.type === "debit") {
          totalDebit += amount;
        }
      });

      return res.status(200).json({
        success: true,
        data: {
          totalVolume,
          totalCredit,
          totalDebit,
          transactionCount: transactions.length,
          transactions: transactions,
        },
      });
    } catch (error) {
      return res.status(500).json({ success: false, message: error.message });
    }
  }

  /**
   * Get a single customer's balance and basic info.
   */
  static async getCustomerBalance(req, res) {
    try {
      const { customerId } = req.params;
      const merchantId = req.merchant.id;
      const customer = await Customer.findOne({
        where: { id: customerId, merchantId },
        attributes: ["id", "fullName", "accountNumber", "balance"]
      });

      if (!customer) {
        return res.status(404).json({ success: false, message: "Customer not found or not owned by you" });
      }

      return res.status(200).json({
        success: true,
        data: customer,
      });
    } catch (error) {
       return res.status(500).json({ success: false, message: error.message });
    }
  }

  /**
   * Get full details of a single customer.
   */
  static async getCustomerDetails(req, res) {
    try {
      const { customerId } = req.params;
      const merchantId = req.merchant.id;

      const customer = await Customer.findOne({
        where: { id: customerId, merchantId }
      });

      if (!customer) {
        return res.status(404).json({ success: false, message: "Customer not found or not owned by you" });
      }

      return res.status(200).json({
        success: true,
        data: customer,
      });
    } catch (error) {
       return res.status(500).json({ success: false, message: error.message });
    }
  }

  /**
   * Merchant manually debits a customer (moves funds to merchant wallet)
   */
  static async debitCustomer(req, res) {
    const t = await sequelize.transaction();
    try {
      const { customerId } = req.params;
      const { amount, reason } = req.body;
      const merchantId = req.merchant.id;
      const numAmount = parseFloat(amount);

      if (!numAmount || numAmount <= 0) {
        throw new Error("Invalid amount");
      }

      // 1. Find Customer & verify ownership
      const customer = await Customer.findOne({
        where: { id: customerId, merchantId },
        transaction: t,
        lock: true
      });

      if (!customer) {
        throw new Error("Customer not found or not owned by you");
      }

      // 2. Check Balance
      if (parseFloat(customer.balance) < numAmount) {
        throw new Error("Insufficient customer balance");
      }

      // 3. Find Merchant
      const merchant = await Merchant.findByPk(merchantId, {
        transaction: t,
        lock: true
      });

      // 4. Update Balances
      const { fee } = await calculateSaaSFee("merchant_debit", numAmount, merchantId);

      const customerOldBalance = parseFloat(customer.balance);
      const customerNewBalance = customerOldBalance - numAmount;

      await customer.decrement("balance", { by: numAmount, transaction: t });
      await merchant.increment("balance", { by: numAmount, transaction: t });

      // --- DEDUCT FEE FROM MERCHANT IF ANY ---
      if (fee > 0) {
        if (parseFloat(merchant.balance) < fee) {
          throw new Error("Insufficient merchant balance for debit fee");
        }
        await merchant.decrement("balance", { by: fee, transaction: t });
      }

      // 5. Create Transaction Record
      const txRef = `MCH-DR-${uuidv4().slice(0, 8)}`;
      const savedTx = await Transaction.create({
        merchantId,
        customerId,
        transaction_id: txRef,
        type: "debit",
        class: "transfer",
        amount: numAmount,
        fee: fee,
        total_amount: numAmount,
        status: "success",
        old_balance: customerOldBalance,
        new_balance: customerNewBalance,
        info: reason || `Merchant direct debit${fee > 0 ? ` (Fee of ${fee} charged to Merchant)` : ""}`,
      }, { transaction: t });

      await t.commit();

      return res.status(200).json({
        success: true,
        message: `Successfully debited customer ${customer.fullName}`,
        data: savedTx
      });
    } catch (error) {
      await t.rollback();
      console.error("❌ debitCustomer error:", error);
      return res.status(error.message.includes("not found") ? 404 : 400).json({
        success: false,
        message: error.message
      });
    }
  }

  /**
   * Merchant manually credits a customer (moves funds from merchant wallet to customer)
   */
  static async creditCustomer(req, res) {
    const t = await sequelize.transaction();
    try {
      const { customerId } = req.params;
      const { amount, narration, description } = req.body;
      const merchantId = req.merchant.id;
      const numAmount = parseFloat(amount);
      const reason = narration || description;

      if (!numAmount || numAmount <= 0) {
        throw new Error("Invalid amount");
      }

      if (!reason) {
        throw new Error("Narration or description is required for this credit");
      }

      // 1. Find Merchant & Check Balance
      const merchant = await Merchant.findByPk(merchantId, {
        transaction: t,
        lock: true
      });

      if (parseFloat(merchant.balance) < numAmount) {
        throw new Error("Insufficient merchant wallet balance to perform this credit");
      }

      // 2. Find Customer & verify ownership
      const customer = await Customer.findOne({
        where: { id: customerId, merchantId },
        transaction: t,
        lock: true
      });

      if (!customer) {
        throw new Error("Customer not found or not owned by you");
      }

      // 3. Update Balances (Internal transfer)
      const customerOldBalance = parseFloat(customer.balance);
      const customerNewBalance = customerOldBalance + numAmount;

      await merchant.decrement("balance", { by: numAmount, transaction: t });
      await customer.increment("balance", { by: numAmount, transaction: t });

      // 4. Create Transaction Record
      const txRef = `MCH-CR-${uuidv4().slice(0, 8)}`;
      const savedTx = await Transaction.create({
        merchantId,
        customerId,
        transaction_id: txRef,
        type: "credit",
        class: "transfer",
        amount: numAmount,
        fee: 0,
        old_balance: customerOldBalance,
        new_balance: customerNewBalance,
        total_amount: numAmount,
        status: "success",
        info: reason,
      }, { transaction: t });

      await t.commit();

      return res.status(200).json({
        success: true,
        message: `Successfully credited customer ${customer.fullName}`,
        data: savedTx
      });
    } catch (error) {
      await t.rollback();
      console.error("❌ creditCustomer error:", error);
      return res.status(error.message.includes("not found") ? 404 : 400).json({
        success: false,
        message: error.message
      });
    }
  }

  /**
   * Get all transactions for a specific customer
   */
  static async getCustomerTransactions(req, res) {
    try {
      const { customerId } = req.params;
      const merchantId = req.merchant.id;

      // Verify customer belongs to merchant
      const customer = await Customer.findOne({ where: { id: customerId, merchantId } });
      if (!customer) {
        return res.status(404).json({ success: false, message: "Customer not found or not owned by you" });
      }

      const transactions = await Transaction.findAll({
        where: { customerId, merchantId },
        order: [["createdAt", "DESC"]],
      });

      return res.status(200).json({
        success: true,
        count: transactions.length,
        data: transactions,
      });
    } catch (error) {
      return res.status(500).json({ success: false, message: error.message });
    }
  }

  /**
   * Stage 1 KYC: Verify Customer BVN
   */
  static async verifyCustomerBvn(req, res) {
    try {
      const { customerId } = req.params;
      const { bvn } = req.body;
      const merchantId = req.merchant.id;

      const customer = await Customer.findOne({
        where: { id: customerId, merchantId }
      });

      if (!customer) {
        return res.status(404).json({ success: false, message: "Customer not found or not owned by you" });
      }

      if (customer.bvnStatus === "verified") {
        return res.status(400).json({ success: false, message: "Customer BVN has already been verified" });
      }

      // Update status to pending
      await customer.update({ bvnStatus: "pending" });

      let result;
      try {
        result = await YouverifyService.verifyBvn({ id: bvn });
      } catch (apiError) {
        console.error("❌ Customer BVN API Error:", apiError.response?.data || apiError.message);
        await customer.update({ bvnStatus: "failed" });
        return res.status(apiError.response?.status || 500).json({
          success: false,
          message: "Failed to verify BVN with provider",
          error: apiError.response?.data || apiError.message
        });
      }

      const isSuccess = result?.success === true || result?.status === "success";
      if (!isSuccess) {
        await customer.update({ bvnStatus: "failed" });
        return res.status(400).json({
          success: false,
          message: "BVN verification failed with provider",
          data: result
        });
      }

      // Match names
      const bvnFirstName = (result.data?.firstName || "").trim().toLowerCase();
      const bvnLastName = (result.data?.lastName || "").trim().toLowerCase();
      const customerNameParts = customer.fullName.toLowerCase().split(/\s+/);
      
      const firstNameMatched = customerNameParts.includes(bvnFirstName);
      const lastNameMatched = customerNameParts.includes(bvnLastName);
      
      if (!firstNameMatched && !lastNameMatched) {
        await customer.update({ bvnStatus: "failed" });
        return res.status(400).json({
          success: false,
          message: "BVN verification failed: Name mismatch",
          details: {
            providedName: customer.fullName,
            foundName: `${result.data?.firstName || ""} ${result.data?.lastName || ""}`.trim()
          }
        });
      }

      // Success
      await customer.update({
        bvn: bvn,
        bvnStatus: "verified",
        kycStatus: customer.idStatus === "verified" ? "verified" : customer.kycStatus
      });

      return res.status(200).json({
        success: true,
        message: "Customer BVN verified successfully",
        data: {
          customerId: customer.id,
          bvnStatus: "verified",
          kycStatus: customer.kycStatus
        }
      });
    } catch (error) {
      console.error("❌ verifyCustomerBvn error:", error);
      return res.status(500).json({ success: false, message: error.message });
    }
  }

  /**
   * Stage 2 KYC: Verify Customer ID (NIN)
   */
  static async verifyCustomerId(req, res) {
    try {
      const { customerId } = req.params;
      const { idType, idValue } = req.body;
      const merchantId = req.merchant.id;

      const customer = await Customer.findOne({
        where: { id: customerId, merchantId }
      });

      if (!customer) {
        return res.status(404).json({ success: false, message: "Customer not found or not owned by you" });
      }

      // Must complete BVN first
      if (customer.bvnStatus !== "verified") {
        return res.status(400).json({
          success: false,
          message: "Please complete Stage 1 (BVN verification) first before ID verification"
        });
      }

      if (customer.idStatus === "verified") {
        return res.status(400).json({ success: false, message: "Customer ID has already been verified" });
      }

      // Update status to pending
      await customer.update({ idStatus: "pending" });

      let result;
      try {
        result = await YouverifyService.verifyNin({ id: idValue });
      } catch (apiError) {
        console.error("❌ Customer NIN API Error:", apiError.response?.data || apiError.message);
        await customer.update({ idStatus: "failed" });
        return res.status(apiError.response?.status || 500).json({
          success: false,
          message: "Failed to verify NIN with provider",
          error: apiError.response?.data || apiError.message
        });
      }

      const isSuccess = result?.success === true || result?.status === "success";
      if (!isSuccess) {
        await customer.update({ idStatus: "failed" });
        return res.status(400).json({
          success: false,
          message: "NIN verification failed with provider",
          data: result
        });
      }

      // Match names
      const ninFirstName = (result.data?.firstName || "").trim().toLowerCase();
      const ninLastName = (result.data?.lastName || "").trim().toLowerCase();
      const customerNameParts = customer.fullName.toLowerCase().split(/\s+/);
      
      const firstNameMatched = customerNameParts.includes(ninFirstName);
      const lastNameMatched = customerNameParts.includes(ninLastName);
      
      if (!firstNameMatched && !lastNameMatched) {
        await customer.update({ idStatus: "failed" });
        return res.status(400).json({
          success: false,
          message: "NIN verification failed: Name mismatch",
          details: {
            providedName: customer.fullName,
            foundName: `${result.data?.firstName || ""} ${result.data?.lastName || ""}`.trim()
          }
        });
      }

      // Success
      await customer.update({
        idType: idType.toLowerCase(),
        idValue: idValue,
        idStatus: "verified",
        kycStatus: "verified" // Since both BVN and NIN are now verified
      });

      // ─────────────────────────────────────────────────────────────────
      // AUTO-CREATE PAYSCRIBE PROFILE
      // ─────────────────────────────────────────────────────────────────
      try {
        const existingProfile = await PayscribePerson.findOne({ where: { customerId: customer.id } });
        if (!existingProfile) {
          const nameParts = customer.fullName.trim().split(" ");
          const firstName = nameParts[0] || "";
          const lastName = nameParts.slice(1).join(" ") || firstName;

          const psResponse = await PayscribeService.registerCustomerProfile({
            firstName,
            lastName,
            phone: customer.phoneNumber || "08000000000",
            email: customer.email,
            dob: result.data?.dateOfBirth || "1990-01-01",
            address: result.data?.address || "Nigeria",
            bvn: customer.bvn,
          });

          const payscribePersonId = psResponse?.data?.customer_id || psResponse?.customer_id;
          if (payscribePersonId) {
            await PayscribePerson.create({ customerId: customer.id, payscribePersonId });
            console.log(`✅ Automatically created PayScribe profile for customer ${customer.id}`);
          }
        }
      } catch (psbErr) {
        console.error("⚠️ Failed to auto-create PayScribe profile:", psbErr.response?.data || psbErr.message);
        // We don't fail the KYC request if PayScribe profile creation fails.
      }

      return res.status(200).json({
        success: true,
        message: "Customer ID verified successfully. KYC verification complete.",
        data: {
          customerId: customer.id,
          idStatus: "verified",
          kycStatus: "verified"
        }
      });
    } catch (error) {
      console.error("❌ verifyCustomerId error:", error);
      return res.status(500).json({ success: false, message: error.message });
    }
  }
}

export default CustomerController;
