const Payment = require("../../models/accounts/paymentModel");
const Invoice = require("../../models/accounts/invoiceModel");
const { errorResponse } = require("../../utils/errorResponseHandler");
const { logUserAction } = require("../../utils/userActionLogger");

/* ================= HELPERS ================= */
const generatePaymentNumber = () =>
  `PAY-${Date.now()}-${Math.floor(100 + Math.random() * 900)}`;

/* =====================================================
   CREATE PAYMENT
===================================================== */
const createPayment = async (req, res) => {
  try {
    const userId = req.user?._id;
    const orgId = req.user?.orgId;

    if (!userId) return errorResponse(res, "Unauthorized", 401);

    const {
      customer,
      invoiceId,
      amount,
      paymentDate,
      mode,
      reference,
      notes,
    } = req.body;

    /* ---------- VALIDATIONS ---------- */
    if (!customer?.name) {
      return errorResponse(res, "Customer details are required", 400);
    }

    if (!amount || amount <= 0) {
      return errorResponse(res, "Invalid payment amount", 400);
    }

    if (!paymentDate || !mode) {
      return errorResponse(res, "Payment date and mode are required", 400);
    }

    let invoice = null;
    let remainingBeforePayment = null;

    /* ---------- FETCH INVOICE (OPTIONAL) ---------- */
    if (invoiceId) {
      invoice = await Invoice.findOne({
        _id: invoiceId,
        orgId,
        isDeleted: false,
      });

      if (!invoice) {
        return errorResponse(res, "Invoice not found", 404);
      }

      if (invoice.status === "CANCELLED") {
        return errorResponse(res, "Cannot pay a cancelled invoice", 400);
      }

      if (invoice.status === "PAID") {
        return errorResponse(res, "Invoice already fully paid", 400);
      }

      const paidSoFar = invoice.payment?.paidAmount || 0;
      remainingBeforePayment = invoice.grandTotal - paidSoFar;

      if (amount > remainingBeforePayment) {
        return errorResponse(
          res,
          `Payment exceeds remaining invoice balance (${remainingBeforePayment})`,
          400
        );
      }
    }

    /* ---------- CREATE PAYMENT ---------- */
    const payment = await Payment.create({
      paymentNumber: generatePaymentNumber(),
      orgId,

      customer: {
        name: customer.name,
        phone: customer.phone || null,
        email: customer.email || null,
      },

      invoiceId: invoice ? invoice._id : null,
      invoiceNumber: invoice ? invoice.invoiceNumber : null,

      amount,
      paymentDate,
      mode: mode.toUpperCase(),
      reference,
      notes,

      createdBy: userId,
      updatedBy: userId,
    });

    /* ---------- SYNC INVOICE TOTALS ---------- */
    if (invoice) {
      const paidSoFar = invoice.payment?.paidAmount || 0;
      const newPaidAmount = paidSoFar + amount;

      invoice.payment = {
        paidAmount: newPaidAmount,
        lastPaymentMode: mode,
        lastTransactionId: reference || null,
        lastPaidAt: paymentDate,
      };

      // Status transitions
      if (newPaidAmount === invoice.grandTotal) {
        invoice.status = "PAID";
      } else {
        invoice.status = "ISSUED"; // still partially pending
      }

      invoice.updatedBy = userId;
      await invoice.save();
    }

    /* ---------- AUDIT LOG ---------- */
    await logUserAction({
      userId,
      orgId,
      action: "CREATE_PAYMENT",
      model: "Payment",
      details: {
        paymentId: payment._id,
        invoiceId: invoice?._id || null,
        amount,
      },
      req,
    });

    return res.status(201).json({
      success: true,
      message: "Payment recorded successfully",
      data: payment,
    });
  } catch (err) {
    console.error("CREATE PAYMENT ERROR:", err);
    return errorResponse(res, "Failed to record payment", 500, err);
  }
};

/* =====================================================
   GET PAYMENTS BY CUSTOMER (LEDGER)
===================================================== */
const getPaymentsByCustomer = async (req, res) => {
  try {
    const orgId = req.user?.orgId;
    const { name, phone, email } = req.query;

    if (!name && !phone && !email) {
      return errorResponse(res, "Customer identifier required", 400);
    }

    const payments = await Payment.find({
      orgId,
      isDeleted: false,
      $or: [
        name ? { "customer.name": name } : null,
        phone ? { "customer.phone": phone } : null,
        email ? { "customer.email": email } : null,
      ].filter(Boolean),
    }).sort({ paymentDate: 1 });

    return res.json({
      success: true,
      data: payments,
    });
  } catch (err) {
    return errorResponse(res, "Failed to fetch payments", 500, err);
  }
};

/* =====================================================
   GET PAYMENT BY ID
===================================================== */
const getPaymentById = async (req, res) => {
  try {
    const orgId = req.user?.orgId;

    const payment = await Payment.findOne({
      _id: req.params.id,
      orgId,
      isDeleted: false,
    });

    if (!payment) {
      return errorResponse(res, "Payment not found", 404);
    }

    return res.json({
      success: true,
      data: payment,
    });
  } catch (err) {
    return errorResponse(res, "Failed to fetch payment", 500, err);
  }
};

module.exports = {
  createPayment,
  getPaymentsByCustomer,
  getPaymentById,
};
