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


// // create Invoice
// const createInvoice = async (req, res) => {
//   try {
//     const userId = req.user?._id;
//     // 🔹 REQUIRED: link invoice to task
//     // Reason: Invoice must be fetched using taskId from task-based UI
//     const { taskId } = req.body;

//     if (!taskId) {
//       return errorResponse(res, "Task ID is required to create invoice", 400);
//     }


//     if (!userId) {
//       return errorResponse(res, "Unauthorized user", 401);
//     }

//     const {
//       invoiceNumber,
//       // taskId,
//       customerName,
//       category,
//       service,
//       amount,
//       orgId,
//       generatedDate,
//       dueDate,
//       status,
//       transactionId,
//       notes
//     } = req.body;
//     if (!customerName || !category || !service || !amount || !orgId || !generatedDate || !dueDate) {
//       return errorResponse(res, "Missing required fields", 400);
//     }

//     const uniqueInvoiceId = "INV-" + Math.floor(100000 + Math.random() * 900000);
//     const invoice = await Invoice.create({
//       invoiceNumber: uniqueInvoiceId,
//       taskId,
//       customerName,
//       category,
//       service,
//       amount,
//       orgId,
//       generatedDate,
//       dueDate,
//       status: status || "pending",
//       transactionId,
//       notes: notes || "",
//       createdBy: userId,
//       updatedBy: userId
//     });
//     await logUserAction({
//       userId,
//       orgId,
//       action: "CREATE_INVOICE",
//       model: "Invoice",
//       details: { invoiceId: invoice._id },
//       req
//     });

//     return res.status(201).json({
//       success: true,
//       message: "Invoice created successfully",
//       data: invoice
//     });

//   } catch (err) {
//     return errorResponse(res, "Failed to create invoice", 500, err);
//   }
// };

// // getAllInvoices
// const fetchAllInvoices = async (req, res) => {
//   try {
//     const invoices = await Invoice.find({ isDeleted: false });

//     if (!invoices || invoices.length === 0) {
//       return errorResponse(res, "No invoice records found", 404);
//     }

//     await logUserAction({
//       userId: req.user?._id,
//       action: "FETCH_INVOICES",
//       model: "Invoice",
//       details: { count: invoices.length },
//       req,
//     });

//     return res.status(200).json({
//       success: true,
//       data: invoices,
//       message: "Fetched all invoices successfully",
//     });

//   } catch (error) {
//     return errorResponse(res, "Failed to fetch invoices", 500, error);
//   }
// };

// // Update invoice
// const updateInvoiceById = async (req, res) => {
//   try {
//     const updates = { ...req.body, updatedBy: req.user?._id };
//     // If incoming data has nested fields as JSON strings (optional)
//     // if (updates.items && typeof updates.items === "string") {
//     //   try {
//     //     updates.items = JSON.parse(updates.items);
//     //   } catch (err) {
//     //     return errorResponse(res, "Invalid items format. Must be JSON", 400);
//     //   }
//     // }
//     const invoice = await Invoice.findByIdAndUpdate(
//       req.params.id,
//       updates,
//       { new: true }
//     );

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

//     await logUserAction({
//       userId: req.user?._id,
//       orgId: invoice.orgId || null,
//       action: "UPDATE_INVOICE",
//       model: "Invoice",
//       details: { invoiceId: invoice._id, updates },
//       req
//     });

//     return res.json({
//       success: true,
//       message: "Invoice updated successfully",
//       data: invoice,
//     });

//   } catch (err) {
//     return errorResponse(res, "Failed to update invoice", 500, err);
//   }
// };


// // Delete invoice
// const deleteInvoiceById = async (req, res) => {
//   try {
//     const invoice = await Invoice.findByIdAndUpdate(
//       req.params.id,
//       { isDeleted: true, updatedBy: req.user?._id },
//       { new: true }
//     );

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

//     // Log Action
//     await logUserAction({
//       userId: req.user?._id,
//       orgId: invoice.orgId || null,
//       action: "DELETE_INVOICE",
//       model: "Invoice",
//       details: { invoiceId: invoice._id },
//       req,
//     });

//     return res.json({
//       success: true,
//       message: "Invoice deleted successfully",
//     });

//   } catch (err) {
//     return errorResponse(res, "Failed to delete invoice", 500, err);
//   }
// };


// // 🔹 GET invoice by Task ID
// // Reason: Frontend navigates using taskId, not invoiceId
// const getInvoiceByTaskId = async (req, res) => {
//   try {
//     const { taskId } = req.params;

//     const invoice = await Invoice.findOne({
//       taskId,
//       isDeleted: false
//     });

//     if (!invoice) {
//       return errorResponse(
//         res,
//         "Invoice not created for this task yet",
//         404
//       );
//     }

//     return res.status(200).json({
//       success: true,
//       data: invoice
//     });

//   } catch (err) {
//     return errorResponse(
//       res,
//       "Failed to fetch invoice for task",
//       500,
//       err
//     );
//   }
// };

// // controllers/accounts/invoiceController.js

// const getInvoiceViewDetails = async (req, res) => {
//   try {
//     const { taskId } = req.params;

//     const invoice = await Invoice.findOne({ taskId, isDeleted: false })
//       .populate({
//         path: "taskId",
//         populate: [
//           { path: "assignedTo", select: "name email phone" },
//           { path: "assignedBy", select: "name" }
//         ]
//       });

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

//     return res.status(200).json({
//       success: true,
//       data: invoice,
//     });

//   } catch (err) {
//     return errorResponse(res, "Failed to fetch invoice view data", 500, err);
//   }
// };




// module.exports = { createInvoice, fetchAllInvoices, deleteInvoiceById, updateInvoiceById, getInvoiceByTaskId, getInvoiceViewDetails };
const Invoice = require("../../models/accounts/invoiceModel");
const Task = require("../../models/taskModel"); //  REQUIRED
const { errorResponse } = require("../../utils/errorResponseHandler");
const { logUserAction } = require("../../utils/userActionLogger");

const generateInvoicePdf = require("../../services/pdf/generateInvoicePdf");
const generateStatementPdf = require("../../services/pdf/generateStatementPdf");
const Organization = require("../../models/admin/orgModal");
const Tax = require("../../models/admin/taxModel")
const Discount = require("../../models/admin/discountModel")
const Payment = require("../../models/accounts/paymentModel");
const calculateInvoiceTotals = require("../../utils/calculateInvoiceTotals");
const buildLedger = require("../../services/ledger.service");
const generateCustomerStatementPdf = require("../../services/pdf/generateCustomerStatementPdf");




/* ===========================
   CREATE INVOICE (MANUAL)
   =========================== */


/* ===========================
   GET OR CREATE INVOICE (CORE)
   =========================== */
// const getOrCreateInvoiceByTask = async (req, res) => {

//   console.log("TASK MODEL:", Task);
//   try {
//     const { taskId } = req.params;
//     const userId = req.user._id;

//     // 1️⃣ Check existing invoice
//     let invoice = await Invoice.findOne({ taskId, isDeleted: false })
//       .populate({
//         path: "taskId",
//         populate: [
//           { path: "assignedTo", select: "name email phone" },
//           { path: "assignedBy", select: "name" },
//         ],
//       });

//     if (invoice) {
//       return res.status(200).json({ success: true, data: invoice });
//     }

//     // 2️⃣ Fetch task
//     const task = await Task.findById(taskId)
//       .populate("assignedTo", "name email phone")
//       .populate("assignedBy", "name");

//     if (!task) {
//       return errorResponse(res, "Task not found", 404);
//     }

//     // 3️⃣ Create invoice automatically
//     invoice = await Invoice.create({
//       invoiceNumber: `INV-${Date.now()}`,
//       taskId,
//       customerName: task.customerName,
//       category: task.category || "Service",
//       service: task.service?.serviceName || "Service",
//       amount: task.amount || 0,
//       orgId: task.orgId,
//       generatedDate: new Date(),
//       dueDate: task.dueDate,
//       status: "pending",
//       createdBy: userId,
//       updatedBy: userId,
//     });

//     res.status(201).json({ success: true, data: invoice });
//   } catch (err) {
//     return errorResponse(res, "Failed to load invoice", 500, err);
//   }
// };
// const getOrCreateInvoiceByTask = async (req, res) => {
//   try {
//     const { taskId } = req.params;
//     const userId = req.user?._id;

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

//     /* ---------------------------------
//        1️⃣ CHECK EXISTING INVOICE
//     ---------------------------------- */
//     const existingInvoice = await Invoice.findOne({
//       taskId,
//       isDeleted: false,
//     }).populate({
//       path: "taskId",
//       populate: [
//         { path: "assignedTo", select: "name email phone" },
//         { path: "assignedBy", select: "name" },
//       ],
//     });

//     if (existingInvoice) {
//       return res.status(200).json({
//         success: true,
//         data: existingInvoice,
//         created: false,
//       });
//     }

//     /* ---------------------------------
//        2️⃣ FETCH TASK
//     ---------------------------------- */
//     const task = await Task.findById(taskId)
//       .populate("assignedTo", "name email phone")
//       .populate("assignedBy", "name");

//     if (!task) {
//       return errorResponse(res, "Task not found", 404);
//     }

//     /* ---------------------------------
//        3️⃣ REQUIRED VALIDATIONS (CRITICAL)
//     ---------------------------------- */

//     if (!task.orgId) {
//       return errorResponse(res, "Task orgId missing", 400);
//     }

//     if (!task.dueDate) {
//       return errorResponse(res, "Task due date missing", 400);
//     }

//     if (!task.amount || Number(task.amount) < 1) {
//       return errorResponse(
//         res,
//         "Task amount must be defined before creating invoice",
//         400
//       );
//     }

//     /* ---------------------------------
//        4️⃣ SAFE DATA NORMALIZATION
//     ---------------------------------- */

//     const serviceName =
//       typeof task.service === "object"
//         ? task.service.serviceName
//         : task.service || "Service";

//     const categoryName = task.category || "Service";

//     /* ---------------------------------
//        5️⃣ CREATE INVOICE (SAFE)
//     ---------------------------------- */
//     const invoice = await Invoice.create({
//       invoiceNumber: `INV-${Date.now()}`,
//       taskId,
//       customerName: task.customerName,
//       category: categoryName,
//       service: serviceName,
//       amount: Number(task.amount),
//       orgId: task.orgId,
//       generatedDate: new Date(),
//       dueDate: task.dueDate,
//       status: "pending",
//       createdBy: userId,
//       updatedBy: userId,
//     });

//     return res.status(201).json({
//       success: true,
//       data: invoice,
//       created: true,
//     });
//   } catch (err) {
//     console.error("GET/CREATE INVOICE ERROR:", err);
//     return errorResponse(res, "Failed to load invoice", 500, err);
//   }
// };
// controllers/accounts/invoiceController.js

// const getOrCreateInvoiceByTask = async (req, res) => {
//   try {
//     const { taskId } = req.params;
//     const userId = req.user._id;

//     // 1️⃣ Check if invoice already exists
//     let invoice = await Invoice.findOne({
//       taskId,
//       isDeleted: false,
//     }).populate({
//       path: "taskId",
//       populate: [
//         { path: "assignedTo", select: "name email phone" },
//         { path: "assignedBy", select: "name" },
//       ],
//     });

//     if (invoice) {
//       return res.status(200).json({
//         success: true,
//         data: invoice,
//       });
//     }

//     // 2️⃣ Fetch task
//     const task = await Task.findById(taskId)
//       .populate("assignedTo", "name email phone")
//       .populate("assignedBy", "name");

//     if (!task) {
//       return errorResponse(res, "Task not found", 404);
//     }

//     /**
//      * 🔴 TEMPORARY FALLBACK
//      * Reason:
//      * Task model currently does NOT have amount.
//      * This will be removed once `task.amount` is added.
//      */
//     const TEMP_DEFAULT_AMOUNT = 500;

//     const invoiceAmount =
//       task.amount && Number(task.amount) > 0
//         ? Number(task.amount)
//         : TEMP_DEFAULT_AMOUNT;

//     // 3️⃣ Auto-create invoice
//     invoice = await Invoice.create({
//       invoiceNumber: `INV-${Date.now()}`,
//       taskId: task._id,
//       customerName: task.customerName,
//       category: task.category || "Service",
//       service: task.service?.serviceName || "Service",
//       amount: invoiceAmount, // ✅ TEMP STATIC VALUE
//       orgId: task.orgId,
//       generatedDate: new Date(),
//       dueDate: task.dueDate,
//       status: "pending",
//       createdBy: userId,
//       updatedBy: userId,
//     });

//     return res.status(201).json({
//       success: true,
//       data: invoice,
//     });
//   } catch (err) {
//     console.error("Invoice create/view error:", err);
//     return errorResponse(res, "Failed to load invoice", 500, err);
//   }
// };
// const getOrCreateInvoiceByTask = async (req, res) => {
//   try {
//     const { taskId } = req.params;
//     const userId = req.user?._id;

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

//     // 1️⃣ Check existing invoice
//     let invoice = await Invoice.findOne({
//       taskId,
//       isDeleted: false,
//     }).populate({
//       path: "taskId",
//       populate: [
//         { path: "assignedTo", select: "name email phone" },
//         { path: "assignedBy", select: "name" },
//       ],
//     })
//       .populate({
//         path: "taskId",
//         populate: {
//           path: "service",
//           select: "serviceName"
//         }
//       });
//     ;

//     if (invoice) {
//       return res.status(200).json({ success: true, data: invoice });
//     }

//     // 2️⃣ Fetch task
//     const task = await Task.findById(taskId)
//       .populate("assignedTo", "name email phone")
//       .populate("assignedBy", "name");

//     if (!task) {
//       return errorResponse(res, "Task not found", 404);
//     }

//     // 🔴 TEMP FALLBACK AMOUNT
//     const TEMP_DEFAULT_AMOUNT = 500;

//     // 🔴 SAFE CUSTOMER NAME FALLBACK
//     const customerName =
//       task.customerName ||
//       task.customer?.name ||
//       "Customer";

//     // 3️⃣ Auto-create invoice
//     invoice = await Invoice.create({
//       invoiceNumber: `INV-${Date.now()}`,
//       taskId: task._id,
//       customerName,
//       category: task.category || "Service",
//       service: task.service?.serviceName || "Service",
//       amount: task.amount || TEMP_DEFAULT_AMOUNT,
//       orgId: task.orgId,
//       generatedDate: new Date(),
//       dueDate: task.dueDate,
//       status: "pending",
//       createdBy: userId,
//       updatedBy: userId,
//     });

//     return res.status(201).json({ success: true, data: invoice });

//   } catch (err) {
//     console.error("Invoice error:", err);
//     return errorResponse(res, "Failed to load invoice", 500, err);
//   }
// };

// const getOrCreateInvoiceByTask = async (req, res) => {
//   try {
//     const { taskId } = req.params;
//     const userId = req.user._id;

//     // 1️ Check existing invoice
//     let invoice = await Invoice.findOne({ taskId, isDeleted: false });
//     if (invoice) {
//       return res.status(200).json({ success: true, data: invoice });
//     }

//     const organization = await Organization.findOne().lean();

//     if (!organization) {
//       return errorResponse(res, "Organization not found", 404);
//     }

//     // 2 Fetch task
//     const task = await Task.findById(taskId)
//       .populate("service", "serviceName")
//       .populate("customer", "name phone email");

//     if (!task) return errorResponse(res, "Task not found", 404);

//     //  TEMP fallback until task.amount exists
//     const rate = task.amount || 500;

//     // 3️ Create SNAPSHOT invoice
//     invoice = await Invoice.create({
//       invoiceNumber: `INV-${Date.now()}`,
//       taskId,
//       orgId: task.orgId,

//       // company: {
//       //   name: req.user.org?.orgName || "Company",
//       //   address: req.user.org?.address || "--",
//       //   gstin: req.user.org?.gstin || null,
//       // },
//       company: {
//         name: organization.orgName,
//         address: organization.address || "--",
//         gstin: organization.gstin || null,
//       },

//       customer: {
//         name: task.customer?.name || "--",
//         phone: task.customer?.phone || "--",
//         email: task.customer?.email || null,
//       },

//       items: [
//         {
//           description: task.service?.serviceName || "Service",
//           quantity: 1,
//           rate,
//           amount: rate,
//         },
//       ],

//       subTotal: rate,
//       tax: { percentage: 0, amount: 0 },
//       grandTotal: rate,

//       status: "pending",
//       createdBy: userId,
//       updatedBy: userId,
//     });

//     return res.status(201).json({ success: true, data: invoice });
//   } catch (err) {
//     console.error("Invoice create error:", err);
//     return errorResponse(res, "Failed to load invoice", 500, err);
//   }
// };




// just now made commented below ///02-01-26
const createInvoice = async (req, res) => {
  try {
    const userId = req.user?._id;
    const { taskId } = req.body;

    if (!userId) return errorResponse(res, "Unauthorized user", 401);
    if (!taskId) return errorResponse(res, "Task ID is required", 400);

    const existing = await Invoice.findOne({ taskId, isDeleted: false });
    if (existing) {
      return errorResponse(res, "Invoice already exists for this task", 409);
    }

    const {
      customerName,
      category,
      service,
      amount,
      orgId,
      generatedDate,
      dueDate,
      status,
      transactionId,
    } = req.body;

    if (!customerName || !category || !service || !amount || !orgId || !generatedDate || !dueDate) {
      return errorResponse(res, "Missing required fields", 400);
    }

    const invoice = await Invoice.create({
      invoiceNumber: `INV-${Date.now()}`,
      taskId,
      customerName,
      category,
      service,
      amount,
      orgId,
      generatedDate,
      dueDate,
      status: status || "pending",
      transactionId,
      createdBy: userId,
      updatedBy: userId,
    });

    await logUserAction({
      userId,
      orgId,
      action: "CREATE_INVOICE",
      model: "Invoice",
      details: { invoiceId: invoice._id },
      req,
    });

    res.status(201).json({ success: true, data: invoice });
  } catch (err) {
    return errorResponse(res, "Failed to create invoice", 500, err);
  }
};


// just for time being commented 02-01-26
// const getOrCreateInvoiceByTask = async (req, res) => {
//   try {
//     const { taskId } = req.params;
//     const userId = req.user._id;

//     // 1️⃣ Fetch task FIRST
//     const task = await Task.findById(taskId)
//       .populate("service", "serviceName")
//       .populate("customer", "name phone email");

//     if (!task) {
//       return errorResponse(res, "Task not found", 404);
//     }

//     // 2️⃣ Fetch organization (CORRECT WAY)
//     // const organization = await Organization.findById(task.orgId).lean();
//     const organization = await Organization.findOne().lean();

//     if (!organization) {
//       return errorResponse(res, "Organization not found", 404);
//     }

//     // 3️⃣ Check existing invoice
//     let invoice = await Invoice.findOne({ taskId, isDeleted: false });

//     // If invoice already has proper snapshot → return it
//     if (
//       invoice &&
//       invoice.company?.name &&
//       invoice.items?.length &&
//       invoice.customer?.name
//     ) {
//       return res.status(200).json({ success: true, data: invoice });
//     }

//     // 4️⃣ TEMP fallback until task.amount exists
//     const rate = Number(task.amount) > 0 ? Number(task.amount) : 500;

//     // 5️⃣ Create / REPLACE invoice snapshot
//     invoice = await Invoice.findOneAndUpdate(
//       { taskId },
//       {
//         invoiceNumber: invoice?.invoiceNumber || `INV-${Date.now()}`,
//         taskId,
//         orgId: task.orgId,

//         // 🏢 COMPANY SNAPSHOT
//         company: {
//           name: organization.orgName,
//           address: organization.address || "--",
//           gstin: organization.gstin || null,
//         },

//         // 👤 CUSTOMER SNAPSHOT
//         customer: {
//           name: task.customer?.name || task.customerName || "--",
//           phone: task.customer?.phone || "--",
//           email: task.customer?.email || null,
//         },

//         // 🧾 ITEMS
//         items: [
//           {
//             description: task.service?.serviceName || "Service",
//             quantity: 1,
//             rate,
//             amount: rate,
//           },
//         ],

//         subTotal: rate,
//         tax: { percentage: 0, amount: 0 },
//         grandTotal: rate,

//         status: "pending",
//         createdBy: invoice?.createdBy || userId,
//         updatedBy: userId,
//       },
//       { upsert: true, new: true }
//     );

//     return res.status(200).json({ success: true, data: invoice });

//   } catch (err) {
//     console.error("Invoice create error:", err);
//     return errorResponse(res, "Failed to load invoice", 500, err);
//   }
// };
// replace above function with below function

const getInvoiceByTaskId = async (req, res) => {
  try {
    const { taskId } = req.params;

    const invoice = await Invoice.findOne({
      taskId,
      isDeleted: false,
    })
      .populate({
        path: "taskId",
        populate: [
          { path: "assignedTo", select: "name email phone" },
          { path: "assignedBy", select: "name" },
        ],
      })
    // .populate("service", "serviceName serviceCost");

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

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

// const createInvoiceByTask = async (req, res) => {
//   try {
//     const { taskId } = req.params;
//     const userId = req.user._id;

//     const exists = await Invoice.findOne({ taskId, isDeleted: false });
//     if (exists) {
//       return errorResponse(res, "Invoice already exists", 409);
//     }

//     const task = await Task.findById(taskId)
//       .populate("service", "serviceName")
//       .populate("customer", "name phone email");

//     if (!task) {
//       return errorResponse(res, "Task not found", 404);
//     }

//     const org = await Organization.findById(task.orgId).lean();
//     if (!org) {
//       return errorResponse(res, "Organization not found", 404);
//     }

//     const rate = Number(task.amount) > 0 ? Number(task.amount) : 500;

//     const invoice = await Invoice.create({
//       invoiceNumber: `INV-${Date.now()}`,
//       taskId,
//       orgId: task.orgId,

//       company: {
//         name: org.orgName,
//         address: org.address || "--",
//         gstin: org.gstin || null,
//       },

//       customer: {
//         name: task.customer?.name || "--",
//         phone: task.customer?.phone || "--",
//         email: task.customer?.email || null,
//       },

//       items: [
//         {
//           description: task.service?.serviceName || "Service",
//           quantity: 1,
//           rate,
//           amount: rate,
//         },
//       ],

//       subTotal: rate,
//       tax: { percentage: 0, amount: 0 },
//       grandTotal: rate,

//       status: "DRAFT",
//       createdBy: userId,
//       updatedBy: userId,
//     });

//     return res.status(201).json({
//       success: true,
//       data: invoice,
//     });
//   } catch (err) {
//     return errorResponse(res, "Failed to create invoice", 500, err);
//   }
// };
// const createInvoiceByTask = async (req, res) => {
//   try {
//     const { taskId } = req.params;
//     const userId = req.user?._id;
//     const orgId = req.user?.orgId;

//     if (!userId) return errorResponse(res, "Unauthorized", 401);
//     if (!taskId) return errorResponse(res, "Task ID required", 400);

//     // 1️⃣ Prevent duplicate invoice
//     const existing = await Invoice.findOne({ taskId, isDeleted: false });
//     if (existing) {
//       return res.status(200).json({ success: true, data: existing });
//     }

//     // 2️⃣ Fetch task
//     const task = await Task.findById(taskId)
//       .populate("service", "serviceName serviceCost")
//       .populate("customer", "name phone email");

//     if (!task) return errorResponse(res, "Task not found", 404);

//     // 3️⃣ Fetch organization from logged-in user
//     // const organization = await Organization.findById(orgId).lean();
//     const organization = await Organization.findOne().lean();
//     if (!organization) {
//       return errorResponse(res, "Organization not found", 404);
//     }

//     // 4️⃣ Amount fallback (until task.amount exists)
//     if (!task.service || typeof task.service.serviceCost !== "number") {
//       return errorResponse(res, "Service cost not configured", 400);
//     }

//     const rate = task.service.serviceCost;


//     const generatedDate = new Date();

//     const dueDate =
//       task.dueDate
//         ? new Date(task.dueDate)
//         : new Date(Date.now() + 7 * 24 * 60 * 60 * 1000); // +7 days

//     // 5️⃣ Create invoice
//     const invoice = await Invoice.create({
//       invoiceNumber: `INV-${Date.now()}`,
//       taskId,
//       orgId,
//       generatedDate,
//       dueDate,

//       company: {
//         name: organization.orgName,
//         address: organization.address || "--",
//         gstin: organization.gstin || null,
//       },

//       customer: {
//         name: task.customer?.name || task.customerName || "--",
//         phone: task.customer?.phone || "--",
//         email: task.customer?.email || null,
//       },

//       items: [
//         {
//           description: task.service?.serviceName || "Service",
//           quantity: 1,
//           rate,
//           amount: rate,
//         },
//       ],

//       subTotal: rate,
//       tax: { percentage: 0, amount: 0 },
//       grandTotal: rate,

//       status: "DRAFT",
//       createdBy: userId,
//       updatedBy: userId,
//     });

//     return res.status(201).json({
//       success: true,
//       data: invoice,
//     });
//   } catch (err) {
//     console.error("CREATE INVOICE ERROR:", err);
//     return errorResponse(res, "Failed to create invoice", 500, err);
//   }
// };
// const createInvoiceByTask = async (req, res) => {
//   try {
//     const { taskId } = req.params;
//     const userId = req.user?._id;
//     const orgId = req.user?.orgId;

//     if (!userId) return errorResponse(res, "Unauthorized", 401);
//     if (!taskId) return errorResponse(res, "Task ID required", 400);

//     // 1️⃣ Prevent duplicate invoice
//     const existing = await Invoice.findOne({ taskId, isDeleted: false });
//     if (existing) {
//       return res.status(200).json({ success: true, data: existing });
//     }

//     // 2️⃣ Fetch task (NO service populate needed)
//     const task = await Task.findById(taskId);

//     if (!task) return errorResponse(res, "Task not found", 404);

//     // 3️⃣ Validate service snapshot
//     if (typeof task.serviceCost !== "number") {
//       return errorResponse(res, "Service cost snapshot missing on task", 400);
//     }

//     const rate = task.serviceCost;

//     // 4️⃣ Fetch organization
//     const organization = await Organization.findOne().lean();
//     if (!organization) {
//       return errorResponse(res, "Organization not found", 404);
//     }

//     const generatedDate = new Date();
//     const dueDate = task.dueDate
//       ? new Date(task.dueDate)
//       : new Date(Date.now() + 7 * 24 * 60 * 60 * 1000);

//     // 5️⃣ Create invoice (snapshot-only)
//     const invoice = await Invoice.create({
//       invoiceNumber: `INV-${Date.now()}`,
//       taskId,
//       orgId,
//       generatedDate,
//       dueDate,

//       company: {
//         name: organization.orgName,
//         address: organization.address || "--",
//         gstin: organization.gstin || null,
//       },

//       customer: {
//         name: task.customer?.name || "--",
//         phone: task.customer?.phone || "--",
//         email: task.customer?.email || null,
//       },

//       items: [
//         {
//           description: task.serviceName || "Service",
//           quantity: 1,
//           rate,
//           amount: rate,
//         },
//       ],

//       subTotal: rate,
//       tax: { percentage: 0, amount: 0 },
//       grandTotal: rate,

//       status: "DRAFT",
//       createdBy: userId,
//       updatedBy: userId,
//     });

//     return res.status(201).json({
//       success: true,
//       data: invoice,
//     });
//   } catch (err) {
//     console.error("CREATE INVOICE ERROR:", err);
//     return errorResponse(res, "Failed to create invoice", 500, err);
//   }
// };


const createInvoiceByTask = async (req, res) => {
  try {
    const { taskId } = req.params;
    const { discountId } = req.body;

    const userId = req.user?._id;
    const orgId = req.user?.orgId;

    if (!userId) return errorResponse(res, "Unauthorized", 401);
    if (!taskId) return errorResponse(res, "Task ID required", 400);

    /* 1️⃣ Prevent duplicate invoice */
    const existing = await Invoice.findOne({ taskId, isDeleted: false });
    if (existing) {
      return res.status(200).json({ success: true, data: existing });
    }

    /* 2️⃣ Fetch task */
    const task = await Task.findById(taskId);
    if (!task) return errorResponse(res, "Task not found", 404);

    if (typeof task.serviceCost !== "number") {
      return errorResponse(res, "Service cost snapshot missing on task", 400);
    }

    const baseAmount = task.serviceCost;

    /* 3️⃣ Fetch organization */
    // below line modified beacause orgId is coming from req.user in db we have different orgId
    const organization = await Organization.findOne().lean();
    if (!organization) {
      return errorResponse(res, "Organization not found", 404);
    }

    /* 4️⃣ Fetch active tax (STATE / INTRA) */
    const tax = await Tax.findOne({
      orgId,
      isActive: true,
      isDeleted: false,
    });

    /* 5️⃣ Fetch discount (optional) */
    let discount = null;
    let discountAmount = 0;

    if (discountId) {
      discount = await Discount.findOne({
        _id: discountId,
        orgId,
        isActive: true,
        isDeleted: false,
      });

      if (!discount) {
        return errorResponse(res, "Invalid discount", 400);
      }

      if (discount.type === "PERCENTAGE") {
        discountAmount = (baseAmount * discount.value) / 100;
        if (
          discount.maxDiscountAmount &&
          discountAmount > discount.maxDiscountAmount
        ) {
          discountAmount = discount.maxDiscountAmount;
        }
      } else {
        discountAmount = discount.value;
      }
    }

    const taxableAmount = baseAmount - discountAmount;

    /* 6️⃣ Calculate GST (INTRA-STATE) */
    let cgstAmount = 0;
    let sgstAmount = 0;
    let totalTax = 0;

    if (tax) {
      cgstAmount = (taxableAmount * tax.rates.cgst) / 100;
      sgstAmount = (taxableAmount * tax.rates.sgst) / 100;
      totalTax = cgstAmount + sgstAmount;
    }

    const grandTotal = taxableAmount + totalTax;

    /* 7️⃣ Create invoice */
    const invoice = await Invoice.create({
      invoiceNumber: `INV-${Date.now()}`,
      taskId,
      orgId,
      generatedDate: new Date(),
      dueDate: task.dueDate || new Date(Date.now() + 7 * 86400000),

      company: {
        name: organization.orgName,
        address: organization.address || "--",
        gstin: organization.gstin || null,
      },

      customer: {
        name: task.customer?.name || "--",
        phone: task.customer?.phone || "--",
        email: task.customer?.email || null,
      },

      items: [
        {
          description: task.serviceName || "Service",
          quantity: 1,
          rate: baseAmount,
          amount: baseAmount,

          discount: discount
            ? {
              name: discount.name,
              type: discount.type,
              value: discount.value,
              amount: discountAmount,
            }
            : null,

          tax: tax
            ? {
              name: tax.name,
              cgstPercent: tax.rates.cgst,
              sgstPercent: tax.rates.sgst,
              cgstAmount,
              sgstAmount,
              totalTax,
            }
            : null,

          total: grandTotal,
        },
      ],

      subTotal: baseAmount,
      totalDiscount: discountAmount,
      totalTax,
      grandTotal,

      status: "DRAFT",
      createdBy: userId,
      updatedBy: userId,
    });

    return res.status(201).json({ success: true, data: invoice });
  } catch (err) {
    console.error("CREATE INVOICE ERROR:", err);
    return errorResponse(res, "Failed to create invoice", 500, err);
  }
};



const updateInvoiceStatus = async (req, res) => {
  try {
    const { status } = req.body;

    const allowedTransitions = {
      DRAFT: ["ISSUED", "CANCELLED"],
      ISSUED: ["PAID", "CANCELLED"],
      PAID: [],
      CANCELLED: [],
    };

    const invoice = await Invoice.findById(req.params.id);
    if (!invoice) {
      return errorResponse(res, "Invoice not found", 404);
    }

    if (!allowedTransitions[invoice.status]?.includes(status)) {
      return errorResponse(
        res,
        `Invalid status change from ${invoice.status} to ${status}`,
        400
      );
    }

    invoice.status = status;
    invoice.updatedBy = req.user._id;
    await invoice.save();

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

const issueInvoice = async (req, res) => {
  try {
    const { id: invoiceId } = req.params;
    const userId = req.user?._id;
    const orgId = req.user?.orgId;

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

    if (!invoiceId) {
      return errorResponse(res, "Invoice ID is required", 400);
    }

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

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

    /* ---------------- ORG-LEVEL SECURITY ---------------- */
    if (String(invoice.orgId) !== String(orgId)) {
      return errorResponse(res, "Access denied", 403);
    }

    /* ---------------- WORKFLOW VALIDATION ---------------- */
    if (invoice.status === "ISSUED") {
      // Idempotent response (safe retry)
      return res.status(200).json({
        success: true,
        message: "Invoice already issued",
        data: invoice,
      });
    }

    if (invoice.status !== "DRAFT") {
      return errorResponse(
        res,
        `Invoice cannot be issued from status '${invoice.status}'`,
        400
      );
    }

    /* ---------------- REQUIRED DATA CHECKS ---------------- */
    if (!invoice.items || invoice.items.length === 0) {
      return errorResponse(res, "Invoice has no items", 400);
    }

    if (!invoice.subTotal || invoice.subTotal <= 0) {
      return errorResponse(res, "Invalid invoice total", 400);
    }

    /* ---------------- ISSUE INVOICE ---------------- */
    invoice.status = "ISSUED";
    invoice.updatedBy = userId;
    invoice.issuedAt = new Date(); // optional audit field

    await invoice.save();

    /* ---------------- AUDIT LOG ---------------- */
    await logUserAction({
      userId,
      orgId,
      action: "ISSUE_INVOICE",
      model: "Invoice",
      details: {
        invoiceId: invoice._id,
        previousStatus: "DRAFT",
        newStatus: "ISSUED",
      },
      req,
    });

    return res.status(200).json({
      success: true,
      message: "Invoice issued successfully",
      data: invoice,
    });

  } catch (err) {
    console.error("ISSUE INVOICE ERROR:", err);
    return errorResponse(res, "Failed to issue invoice", 500, err);
  }
};





/* ===========================
   OTHER EXISTING APIs (UNCHANGED)
   =========================== */
const fetchAllInvoices = async (req, res) => {
  const invoices = await Invoice.find({ isDeleted: false });
  res.json({ success: true, data: invoices });
};

const updateInvoiceById = async (req, res) => {
  const invoice = await Invoice.findByIdAndUpdate(
    req.params.id,
    { ...req.body, updatedBy: req.user._id },
    { new: true }
  );
  if (!invoice) return errorResponse(res, "Invoice not found", 404);
  res.json({ success: true, data: invoice });
};

const deleteInvoiceById = async (req, res) => {
  const invoice = await Invoice.findByIdAndUpdate(
    req.params.id,
    { isDeleted: true, updatedBy: req.user._id },
    { new: true }
  );
  if (!invoice) return errorResponse(res, "Invoice not found", 404);
  res.json({ success: true });
};


// const downloadInvoicePdf = async (req, res) => {
//   try {
//     const { invoiceId } = req.params;
//     console.log("PDF INVOICE DATA:", {
//       generatedDate: invoice.generatedDate,
//       dueDate: invoice.dueDate,
//     });

//     // const invoice = await Invoice.findOne({
//     //   _id: invoiceId,
//     //   isDeleted: false,
//     // });
//     const invoice = await Invoice.findOne({
//       _id: invoiceId,
//       isDeleted: false,
//     })
//       .populate({
//         path: "taskId",
//         populate: [
//           {
//             path: "service",
//             select: "serviceName",
//           },
//           {
//             path: "customer",
//             select: "name phone email",
//           },
//         ],
//       });


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

//     // SECURITY: org-level check
//     if (String(invoice.orgId) !== String(req.user.orgId)) {
//       return errorResponse(res, "Access denied", 403);
//     }

//     // Generate PDF
//     generateInvoicePdf(invoice, res);
//   } catch (err) {
//     return errorResponse(res, "Failed to download invoice", 500, err);
//   }
// };
// const downloadInvoicePdf = async (req, res) => {
//   try {
//     const { invoiceId } = req.params;

//     const invoice = await Invoice.findOne({
//       _id: invoiceId,
//       isDeleted: false,
//     }).populate({
//       path: "taskId",
//       populate: [
//         { path: "service", select: "serviceName" },
//         { path: "customer", select: "name phone email" },
//       ],
//     });

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

//     //  Org security check
//     if (String(invoice.orgId) !== String(req.user.orgId)) {
//       return errorResponse(res, "Access denied", 403);
//     }

//     //  FIX OLD INVOICES (important)
//     if (!invoice.generatedDate) {
//       invoice.generatedDate = invoice.createdAt || new Date();
//     }

//     if (!invoice.dueDate) {
//       invoice.dueDate = invoice.createdAt || new Date();
//     }

//     await invoice.save(); // safe & idempotent

//     //  DEBUG LOG (NOW CORRECT)
//     console.log("PDF INVOICE DATA:", {
//       generatedDate: invoice.generatedDate,
//       dueDate: invoice.dueDate,
//     });

//     generateInvoicePdf(invoice, res);
//   } catch (err) {
//     console.error("PDF DOWNLOAD ERROR:", err);
//     return errorResponse(res, "Failed to download invoice", 500, err);
//   }
// };
const downloadInvoicePdf = async (req, res) => {
  try {
    const { invoiceId } = req.params;

    const invoice = await Invoice.findOne({
      _id: invoiceId,
      isDeleted: false,
    })
      .populate({
        path: "taskId",
        populate: [
          { path: "service", select: "serviceName" },
          { path: "customer", select: "name phone email" },
        ],
      })
      .lean(); // 🔴 IMPORTANT

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

    // 🔐 Org-level security
    if (String(invoice.orgId) !== String(req.user.orgId)) {
      return errorResponse(res, "Access denied", 403);
    }

    /* ================= NORMALIZE DATES ================= */
    invoice.generatedDate =
      invoice.generatedDate ||
      invoice.createdAt ||
      new Date();

    invoice.dueDate =
      invoice.dueDate ||
      invoice.generatedDate;

    /* ================= DEBUG (FINAL CONFIRM) ================= */
    console.log("PDF INVOICE DATA:", {
      generatedDate: invoice.generatedDate,
      dueDate: invoice.dueDate,
    });

    generateInvoicePdf(invoice, res);
  } catch (err) {
    console.error("PDF DOWNLOAD ERROR:", err);
    return errorResponse(res, "Failed to download invoice", 500, err);
  }
};


const updateInvoiceDiscount = async (req, res) => {
  const { id } = req.params;
  const { discountId } = req.body;

  const invoice = await Invoice.findById(id);
  if (!invoice) {
    return res.status(404).json({ message: "Invoice not found" });
  }

  if (invoice.status !== "DRAFT") {
    return res
      .status(400)
      .json({ message: "Cannot modify issued invoice" });
  }

  let discount = null;
  if (discountId) {
    discount = await Discount.findById(discountId);
    if (!discount || !discount.isActive) {
      return res.status(400).json({ message: "Invalid discount" });
    }
  }

  // 🔁 Recalculate totals here
  const totals = calculateInvoiceTotals(invoice.items, discount);

  invoice.discount = discount;
  invoice.totalDiscount = totals.totalDiscount;
  invoice.subTotal = totals.subTotal;
  invoice.totalTax = totals.totalTax;
  invoice.grandTotal = totals.grandTotal;

  await invoice.save();

  res.json({ data: invoice });
};



const downloadInvoiceStatementPdf = async (req, res) => {
  try {
    const { invoiceId } = req.params;
    const orgId = req.user.orgId;

    const invoice = await Invoice.findOne({
      _id: invoiceId,
      orgId,
      isDeleted: false,
    }).lean();

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

    // later we need to work on this 
    // const payments = await Payment.find({
    //   invoiceId,
    //   orgId,
    //   isDeleted: false,
    // }).sort({ paymentDate: 1 });
    let payments = [];
    try {
      payments = await Payment.find({
        invoiceId,
        orgId,
        isDeleted: false,
      })
        .sort({ paymentDate: 1 })
        .lean();
    } catch (err) {
      // Payment module not ready yet – ignore
      payments = [];
    }


    /* Build rows (same logic as ViewStatement) */
    let balance = 0;
    const rows = [];

    rows.push({
      date: null,
      type: "Opening",
      reference: "-",
      description: "Opening Balance",
      debit: 0,
      credit: 0,
      balance,
    });

    balance += invoice.grandTotal;
    rows.push({
      date: invoice.generatedDate,
      type: "Invoice",
      reference: invoice.invoiceNumber,
      description: "Invoice Raised",
      debit: invoice.grandTotal,
      credit: 0,
      balance,
    });

    payments.forEach((p) => {
      balance -= p.amount;
      rows.push({
        date: p.paymentDate,
        type: "Payment",
        reference: p.paymentNumber,
        description: "Payment Received",
        debit: 0,
        credit: p.amount,
        balance,
      });
    });

    generateStatementPdf(res, {
      invoice,
      rows,
      closingBalance: balance,
    });
  } catch (err) {
    return errorResponse(res, "Failed to download statement", 500, err);
  }
};

const getInvoiceReminders = async (req, res) => {
  try {
    const orgId = req.user.orgId;
    const today = new Date();

    const invoices = await Invoice.find({
      orgId,
      isDeleted: false,
      status: "ISSUED", // unpaid only
    }).lean();

    const reminders = invoices.map((inv) => {
      let status = "Pending";

      if (inv.dueDate) {
        if (new Date(inv.dueDate) < today) {
          status = "Overdue";
        } else {
          status = "Pending";
        }
      }

      return {
        invoiceId: inv._id,
        invoiceNumber: inv.invoiceNumber,
        customer: inv.customer?.name,
        service: inv.items?.[0]?.description || "-",
        dueDate: inv.dueDate,
        amount: inv.grandTotal,
        status,

        // Reminder info (Phase-1)
        lastReminder: "Not Sent",
        nextReminder: "-",
      };
    });

    res.json({ success: true, data: reminders });
  } catch (err) {
    res.status(500).json({
      success: false,
      message: "Failed to fetch payment reminders",
    });
  }
};


const downloadCustomerStatementPdf = async (req, res) => {
  try {
    const { customerKey } = req.query;
    const orgId = req.user.orgId;

    if (!customerKey) {
      return errorResponse(res, "Customer key required", 400);
    }

    /* 1️⃣ Fetch invoices */
    const invoices = await Invoice.find({
      orgId,
      isDeleted: false,
      $or: [
        { "customer.email": customerKey },
        { "customer.phone": customerKey },
        { "customer.name": customerKey },
      ],
    }).lean();

    if (!invoices.length) {
      return errorResponse(res, "No invoices found", 404);
    }

    /* 2️⃣ Fetch payments (safe if module exists) */
    let payments = [];
    try {
      payments = await Payment.find({
        orgId,
        isDeleted: false,
        invoiceId: { $in: invoices.map((i) => i._id) },
      }).lean();
    } catch {
      payments = [];
    }

    /* 3️⃣ Build ledger */
    const { rows, closingBalance } = buildLedger(invoices, payments);

    /* 4️⃣ Generate PDF */
    generateCustomerStatementPdf(res, {
      // company: invoices.company,
      company: invoices[0].company,
      customer: invoices[0].customer,
      rows,
      closingBalance,
    });
  } catch (err) {
    console.error("CUSTOMER STATEMENT PDF ERROR:", err);
    return errorResponse(res, "Failed to download statement", 500, err);
  }
};





module.exports = {
  createInvoice,
  fetchAllInvoices,
  updateInvoiceById,
  deleteInvoiceById,
  // 🔹 MAIN PRODUCTION API
  downloadInvoicePdf,
  // getOrCreateInvoiceByTask,
  getInvoiceByTaskId,
  createInvoiceByTask,
  updateInvoiceStatus,
  issueInvoice,
  updateInvoiceDiscount,
  downloadInvoiceStatementPdf,
  getInvoiceReminders,
  downloadCustomerStatementPdf,
};
