import db from "../models/index.js";
import { logAudit } from "../utils/auditLogger.js";
import { sendEmail, renderTemplate } from "../utils/emailService.js";
import { baseEmailLayout } from "../utils/emailTemplates/baseLayout.js";
import DiditService from "../thirdParties/diditService.js";

const { KybApplication, KybDocument, KybDirector, KybHistory, sequelize } = db;

class KybController {
  /**
   * Get the merchant's current KYB application
   * @route GET /merchants/kyb
   */
  static async getKybApplication(req, res) {
    try {
      const merchantId = req.merchant.id;

      let application = await KybApplication.findOne({
        where: { merchantId },
        include: [
          { model: KybDocument, as: "documents" },
          { model: KybDirector, as: "directors" },
          { model: KybHistory, as: "historyLogs", order: [["createdAt", "DESC"]] },
        ],
      });

      // Auto-create a Draft if it doesn't exist
      if (!application) {
        application = await KybApplication.create({ merchantId, status: "Draft" });
        // Fetch again to get the included empty arrays
        application = await KybApplication.findByPk(application.id, {
          include: [
            { model: KybDocument, as: "documents" },
            { model: KybDirector, as: "directors" },
            { model: KybHistory, as: "historyLogs" },
          ],
        });
      }

      return res.status(200).json({ success: true, data: application });
    } catch (error) {
      console.error("Error fetching KYB application:", error);
      return res.status(500).json({ success: false, message: "Internal server error" });
    }
  }

  /**
   * Upsert KYB application details (saves as Draft)
   * @route PUT /merchants/kyb
   */
  static async upsertKybApplication(req, res) {
    const t = await sequelize.transaction();
    try {
      const merchantId = req.merchant.id;
      const {
        companyName,
        registrationNumber,
        companyAddress,
        companyType,
        businessDescription,
        website,
        incorporationDate,
        taxId,
        contactPersonName,
        companyPhone,
        companyEmail,
        natureOfBusiness,
        isLicensed,
        licenseDocumentUrl,
        expectedMonthlyVolume,
        documents, // Array of { documentType, documentUrl }
        directors, // Array of { firstName, lastName, email, phoneNumber, role, ownershipPercentage, idType, idNumber, idDocumentUrl, bvn, gender, dateOfBirth, residentialAddress, proofOfAddressUrl, isBeneficialOwner, isDirector }
        beneficialOwners, // Array of { firstName, lastName, email, phoneNumber, bvn, gender, dateOfBirth, residentialAddress, proofOfAddressUrl }
      } = req.body;

      let application = await KybApplication.findOne({
        where: { merchantId },
        transaction: t,
      });

      if (!application) {
        application = await KybApplication.create({ merchantId, status: "Draft" }, { transaction: t });
      }

      // If already under review or approved, prevent edits unless additional documents are required
      if (["Under Review", "Approved"].includes(application.status)) {
        await t.rollback();
        return res.status(400).json({
          success: false,
          message: `Cannot edit application while status is ${application.status}`,
        });
      }

      // Update core details
      await application.update({
        companyName: companyName || application.companyName,
        registrationNumber: registrationNumber || application.registrationNumber,
        companyAddress: companyAddress || application.companyAddress,
        companyType: companyType || application.companyType,
        businessDescription: businessDescription || application.businessDescription,
        website: website || application.website,
        incorporationDate: incorporationDate || application.incorporationDate,
        taxId: taxId || application.taxId,
        contactPersonName: contactPersonName || application.contactPersonName,
        companyPhone: companyPhone || application.companyPhone,
        companyEmail: companyEmail || application.companyEmail,
        natureOfBusiness: natureOfBusiness || application.natureOfBusiness,
        isLicensed: isLicensed !== undefined ? isLicensed : application.isLicensed,
        licenseDocumentUrl: licenseDocumentUrl || application.licenseDocumentUrl,
        expectedMonthlyVolume: expectedMonthlyVolume || application.expectedMonthlyVolume,
      }, { transaction: t });

      // Update documents (replace all for simplicity in draft stage, or just add new ones)
      if (documents && Array.isArray(documents)) {
        await KybDocument.destroy({ where: { applicationId: application.id }, transaction: t });
        const docRecords = documents.map((doc) => ({
          applicationId: application.id,
          documentType: doc.documentType,
          documentUrl: doc.documentUrl,
          status: "Pending",
        }));

        // If license document URL provided separately, add it as business_license doc type
        if (licenseDocumentUrl) {
          docRecords.push({
            applicationId: application.id,
            documentType: "business_license",
            documentUrl: licenseDocumentUrl,
            status: "Pending",
          });
        }
        await KybDocument.bulkCreate(docRecords, { transaction: t });
      }

      // Combine Directors and Beneficial Owners into KybDirector table
      const combinedPeople = [];

      if (directors && Array.isArray(directors)) {
        directors.forEach((dir) => {
          if (dir.firstName || dir.lastName) {
            combinedPeople.push({
              applicationId: application.id,
              isDirector: true,
              isBeneficialOwner: false,
              role: dir.role || "Director",
              firstName: dir.firstName || "",
              lastName: dir.lastName || "",
              email: dir.email || null,
              phoneNumber: dir.phoneNumber || null,
              bvn: dir.bvn || null,
              gender: dir.gender || null,
              dateOfBirth: dir.dateOfBirth || null,
              residentialAddress: dir.residentialAddress || null,
              proofOfAddressUrl: dir.proofOfAddressUrl || null,
            });
          }
        });
      }

      if (beneficialOwners && Array.isArray(beneficialOwners)) {
        beneficialOwners.forEach((owner) => {
          if (owner.firstName || owner.lastName) {
            combinedPeople.push({
              applicationId: application.id,
              isDirector: false,
              isBeneficialOwner: true,
              role: owner.role || "Beneficial Owner",
              firstName: owner.firstName || "",
              lastName: owner.lastName || "",
              email: owner.email || null,
              phoneNumber: owner.phoneNumber || null,
              ownershipPercentage: owner.ownershipPercentage || 0,
              bvn: owner.bvn || null,
              gender: owner.gender || null,
              dateOfBirth: owner.dateOfBirth || null,
              residentialAddress: owner.residentialAddress || null,
              proofOfAddressUrl: owner.proofOfAddressUrl || null,
            });
          }
        });
      }

      if (combinedPeople.length > 0) {
        await KybDirector.destroy({ where: { applicationId: application.id }, transaction: t });
        await KybDirector.bulkCreate(combinedPeople, { transaction: t });
      }

      await t.commit();

      // Refetch to return full updated model
      application = await KybApplication.findByPk(application.id, {
        include: [
          { model: KybDocument, as: "documents" },
          { model: KybDirector, as: "directors" },
        ],
      });

      return res.status(200).json({
        success: true,
        message: "KYB application drafted successfully.",
        data: application,
      });
    } catch (error) {
      if (t && !t.finished) {
        await t.rollback().catch(() => {});
      }
      console.error("❌ Error upserting KYB application:", error);
      return res.status(500).json({
        success: false,
        message: error.message || "Failed to save KYB application draft",
        error: error.message,
      });
    }
  }

  /**
   * Submit KYB application
   * @route POST /merchants/kyb/submit
   */
  static async submitKybApplication(req, res) {
    const t = await sequelize.transaction();
    try {
      const merchantId = req.merchant.id;

      let application = await KybApplication.findOne({
        where: { merchantId },
        transaction: t,
      });

      if (!application) {
        await t.rollback();
        return res.status(400).json({
          success: false,
          message: "No KYB draft application found. Please save your company details first before submitting.",
        });
      }

      if (
        !application.companyName ||
        !application.registrationNumber ||
        !application.contactPersonName ||
        !application.companyPhone ||
        !application.companyEmail
      ) {
        await t.rollback();
        return res.status(400).json({
          success: false,
          message: "Please complete all required company details (Company Name, Registration Number, Contact Person Name, Phone Number, and Compliance Email) before proceeding.",
        });
      }

      // Verify at least one Director and at least one Beneficial Owner exist
      const directorCount = await KybDirector.count({
        where: { applicationId: application.id, isDirector: true },
        transaction: t,
      });

      const ownerCount = await KybDirector.count({
        where: { applicationId: application.id, isBeneficialOwner: true },
        transaction: t,
      });

      if (directorCount === 0 || ownerCount === 0) {
        await t.rollback();
        return res.status(400).json({
          success: false,
          message: "Please add at least one Company Director and at least one Beneficial Owner before proceeding to verification.",
        });
      }

      if (application.status === "Submitted" && application.diditSessionId) {
        await t.rollback();
        let outcomeObj = application.verificationOutcome;
        if (typeof outcomeObj === "string") {
          try { outcomeObj = JSON.parse(outcomeObj); } catch (e) {}
        }
        const existingUrl = outcomeObj?.session_url || outcomeObj?.url || null;
        return res.status(400).json({
          success: false,
          message: "Application is already Submitted and Didit session is active.",
          data: {
            application,
            verificationUrl: existingUrl
          }
        });
      }

      // 1. Try Didit KYB session creation if configured
      let diditSession = null;
      try {
        diditSession = await DiditService.createSession(merchantId);
      } catch (err) {
        console.warn("⚠️ Didit session creation warning (proceeding with manual review submission):", err.message);
      }

      // 2. Update application status to Submitted & Merchant kybStatus to pending
      const previousStatus = application.status;
      application.status = "Submitted";
      if (diditSession?.sessionId) {
        application.diditSessionId = diditSession.sessionId;
        application.verificationOutcome = {
          sessionId: diditSession.sessionId,
          url: diditSession.url,
          session_url: diditSession.url,
          token: diditSession.token
        };
      }
      await application.save({ transaction: t });

      await db.Merchant.update({ kybStatus: "pending" }, { where: { id: merchantId }, transaction: t });

      await KybHistory.create({
        applicationId: application.id,
        action: "KYB Application Submitted",
        previousStatus,
        newStatus: "Submitted",
        comment: diditSession?.sessionId ? `Started Didit KYB session: ${diditSession.sessionId}` : "Submitted for SuperAdmin manual review",
      }, { transaction: t });

      logAudit({
        userId: merchantId,
        userType: "merchant",
        action: "KYB_SUBMITTED",
        details: { applicationId: application.id, diditSessionId: diditSession?.sessionId },
        req,
      });

      await t.commit();

      // Send email notification to Merchant (non-blocking)
      try {
        const emailParams = await renderTemplate("kyb_submitted", {
          merchantName: req.merchant.businessName,
        });

        if (emailParams) {
          sendEmail(req.merchant.email, emailParams.subject, emailParams.html).catch(() => { });
        }
      } catch (emailErr) {
        console.warn("⚠️ Email notification error (non-fatal):", emailErr.message);
      }

      return res.status(200).json({
        success: true,
        message: "Your KYB application has been submitted successfully and is now under manual review. We will notify you if any additional information or documents are required. You will also receive an update once your application has been approved or rejected.",
        data: {
          application,
          verificationUrl: diditSession?.url || null,
          sessionToken: diditSession?.token || null
        },
      });
    } catch (error) {
      if (t && !t.finished) {
        await t.rollback().catch(() => {});
      }
      console.error("❌ Error submitting KYB application:", error);
      return res.status(500).json({
        success: false,
        message: error.message || "Failed to submit KYB application",
        error: error.message,
      });
    }
  }
}

export default KybController;
