const Payroll = require("../../models/accounts/payrollModel");
const { errorResponse } = require("../../utils/errorResponseHandler");
const { logUserAction } = require("../../utils/userActionLogger");
const payrollService = require("../../services/payroll/payrollService");
const generatePayslipPdf = require("../../services/pdf/generatePayslipPdf");


const createPayroll = async (req, res) => {
  try {
    const userId = req.user._id;

    const {
      payDate,
      nextPayDate,
      employees,
      status,
      orgId,
    } = req.body;

    // Validate required fields
    // if (!payDate || !employees) {
    //   return errorResponse(res, "payDate and employees are required", 400);
    // }
    // Convert employees to JSON if frontend sent it as string (FormData case)
    let parsedEmployees = [];
    try {
      parsedEmployees = typeof employees === "string" ? JSON.parse(employees) : employees;
    } catch (err) {
      return errorResponse(res, "Invalid employees format. Must be JSON", 400);
    }

    // to generateUniqueIds
    const uniquePayrollId = "PAY-" + Math.random().toString(36).substring(2, 10).toUpperCase();

    // Create Payroll
    const payroll = await Payroll.create({
      payrollId: uniquePayrollId,
      payDate,
      nextPayDate,
      employees: parsedEmployees,
      orgId,
      status: status || "pending",
      createdBy: userId,
      updatedBy: userId
    });

    // Log action
    await logUserAction({
      userId,
      action: "CREATE_PAYROLL",
      model: "Payroll",
      details: { payrollId: payroll._id },
      req
    });

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

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

// delete payroll
// const deletePayroll = async (req, res) => {
//   try {
//     const payroll = await Payroll.findByIdAndUpdate(
//       req.params.id,
//       { isDeleted: true, updatedBy: req.user?._id },
//       { new: true }
//     );

//     if (!payroll) return errorResponse(res, "Payroll not found", 404);

//     // Log Action
//     await logUserAction({
//       userId: req.user?._id,
//       orgId: payroll.orgId || null,
//       action: "DELETE_PAYROLL",
//       model: "Payroll",
//       details: { payrollId: payroll._id },
//       req
//     });

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

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

const deletePayroll = async (req, res) => {
  try {
    const payrollId = req.params.id;
    console.log(payrollId);
    
    const userId = req.user?._id;

    // Find payroll
    const payroll = await Payroll.findById(payrollId);

    if (!payroll || payroll.isDeleted) {
      return errorResponse(res, "Payroll not found", 404);
    }

    // Prevent deletion if payroll is paid / locked
    if (payroll.status === "paid" || payroll.isLocked) {
      return errorResponse(
        res,
        "Paid payroll cannot be deleted",
        400
      );
    }

    // Soft delete payroll
    payroll.isDeleted = true;
    payroll.updatedBy = userId;

    await payroll.save();

    // Log action
    await logUserAction({
      userId,
      orgId: payroll.orgId,
      action: "VOID_PAYROLL", // better wording than DELETE
      model: "Payroll",
      modelId: payroll._id,
      details: {
        payrollId: payroll.payrollId,
        payrollMonth: payroll.payrollMonth,
        payrollYear: payroll.payrollYear,
      },
      req,
    });

    return res.json({
      success: true,
      message: "Payroll voided successfully",
    });
  } catch (err) {
    return errorResponse(res, "Failed to delete payroll", 500, err);
  }
};


// const updatePayroll = async (req, res) => {
//   try {
//     const updates = { ...req.body, updatedBy: req.user?._id };

//     // If employees is sent as string JSON (from FormData)
//     if (updates.employees && typeof updates.employees === "string") {
//       try {
//         updates.employees = JSON.parse(updates.employees);
//       } catch (err) {
//         return errorResponse(res, "Invalid employees format. Must be JSON", 400);
//       }
//     }

//     const payroll = await Payroll.findByIdAndUpdate(
//       req.params.id,
//       updates,
//       { new: true }
//     );

//     if (!payroll) return errorResponse(res, "Payroll not found", 404);

//     // Log Action
//     await logUserAction({
//       userId: req.user?._id,
//       action: "UPDATE_PAYROLL",
//       model: "Payroll",
//       details: { payrollId: payroll._id, updates },
//       req
//     });

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

//   } catch (err) {
//     return errorResponse(res, "Failed to update payroll", 500, err);
//   }
// };
const updatePayroll = async (req, res) => {
  try {
    const payrollId = req.params.id; // ✅ works now
    console.log(payrollId);
    
    const userId = req.user._id;
    const { employeeId } = req.body;

    const payroll = await Payroll.findOne({
      _id: payrollId,
      isDeleted: false,
    });

    if (!payroll) {
      return errorResponse(res, "Payroll not found", 404);
    }

    if (payroll.status === "paid") {
      return errorResponse(res, "Paid payroll cannot be edited", 400);
    }

    if (employeeId) {
      const mongoose = require("mongoose");
      const employeeObjectId = new mongoose.Types.ObjectId(employeeId);

      const updates = {
        "employees.$.grossEarnings": req.body.grossEarnings,
        "employees.$.totalDeductions": req.body.totalDeductions,
        "employees.$.netPay": req.body.netPay,
        "employees.$.paymentMethod": req.body.paymentMethod,
      };

      const updated = await Payroll.findOneAndUpdate(
        {
          _id: payrollId,
          "employees.employeeId": employeeObjectId,
        },
        {
          $set: updates,
          updatedBy: userId,
        },
        { new: true }
      );

      if (!updated) {
        return errorResponse(res, "Employee payroll not found", 404);
      }

      return res.json({
        success: true,
        message: "Employee payroll updated successfully",
      });
    }

    return errorResponse(res, "No update data provided", 400);
  } catch (err) {
    return errorResponse(res, "Failed to update payroll", 500, err);
  }
};



// const updateEmployeePayroll = async (req, res) => {
//   try {
//     const { payrollId, employeeId } = req.params;
//     const userId = req.user._id;

//     // Block if payroll is paid or locked
//     const payroll = await Payroll.findOne({
//       _id: payrollId,
//       isDeleted: false,
//     });

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

//     if (payroll.status === "paid" || payroll.isLocked) {
//       return errorResponse(
//         res,
//         "Paid or locked payroll cannot be edited",
//         400
//       );
//     }

//     const allowedFields = [
//       "grossEarnings",
//       "totalDeductions",
//       "netPay",
//       "paymentMethod",
//       "currency",
//       "earnings",
//       "deductions",
//     ];

//     const updates = {};
//     for (const key of allowedFields) {
//       if (req.body[key] !== undefined) {
//         updates[`employees.$.${key}`] = req.body[key];
//       }
//     }

//     if (!Object.keys(updates).length) {
//       return errorResponse(res, "No valid employee fields to update", 400);
//     }

//     const updated = await Payroll.findOneAndUpdate(
//       {
//         _id: payrollId,
//         "employees.employeeId": employeeId,
//       },
//       {
//         $set: updates,
//         $setOnInsert: { updatedBy: userId },
//       },
//       { new: true }
//     );

//     if (!updated) {
//       return errorResponse(res, "Employee payroll not found", 404);
//     }

//     await logUserAction({
//       userId,
//       action: "UPDATE_EMPLOYEE_PAYROLL",
//       model: "Payroll",
//       modelId: payrollId,
//       details: { employeeId, updates: req.body },
//       req,
//     });

//     return res.json({
//       success: true,
//       message: "Employee payroll updated successfully",
//     });

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


// fetchAllPayRolls
const fetchAllPayrolls = async (req, res) => {
  try {
    const payrolls = await Payroll.find({ orgId: req.user.orgId, isDeleted: false });
    if (!payrolls) {
      return errorResponse(res, "No payroll records found", 404);

    }
    await logUserAction({
      userId: req.user?._id,
      action: "FETCH PAYROLLS",
      model: Payroll,
      details: { counts: payrolls.length },
      req
    })

    res.status(200).json({
      success: true,
      data: payrolls,
      message: "Fetched all the payrolls successfully.."
    })
  }
  catch (error) {
    return errorResponse(res, "Failed to fetch Payrolls", 500, error)
  }
}


/* ==============================
   GENERATE PAYROLL
================================ */
// const generatePayroll = async (req, res) => {
//   try {
//     const { month, year } = req.body;
//     const orgId = req.user?.orgId;

//     if (!month || !year) {
//       return errorResponse(res, "Month and year are required", 400);
//     }

//     const employeesProcessed =
//       await payrollService.generateMonthlyPayroll({
//         orgId,
//         month,
//         year,
//         createdBy: req.user?._id,
//       });

//     await logUserAction({
//       userId: req.user?._id,
//       action: "GENERATE PAYROLL",
//       model: Payroll,
//       details: { month, year, employeesProcessed },
//       req,
//     });

//     return res.status(201).json({
//       success: true,
//       message: "Payroll generated successfully",
//       data: {
//         employeesProcessed,
//         month,
//         year,
//       },
//     });
//   } catch (error) {
//     return errorResponse(
//       res,
//       error.message || "Failed to generate payroll",
//       500,
//       error
//     );
//   }
// };
const generatePayroll = async (req, res) => {
  try {
    const { month, year } = req.body;
    const orgId = req.user.orgId;

    if (!month || !year) {
      return errorResponse(res, "Month and year are required", 400);
    }

    // 🔥 Service now returns full payroll document
    const payroll = await payrollService.generateMonthlyPayroll({
      orgId,
      month,
      year,
      createdBy: req.user._id,
    });

    await logUserAction({
      userId: req.user._id,
      action: "GENERATE_OR_REPLACE_PAYROLL",
      model: Payroll,
      modelId: payroll._id,
      details: {
        payrollId: payroll.payrollId,
        // month,
        // year,
        payrollMonth: month,
        payrollYear: year,
        employeeCount: payroll.employees.length,
      },
      req,
    });

    return res.status(200).json({
      success: true,
      message: "Payroll generated successfully",
      data: payroll, // ✅ frontend ready
    });
  } catch (error) {
    return errorResponse(
      res,
      error.message || "Failed to generate payroll",
      500,
      error
    );
  }
};

/* ==============================
   FETCH ALL PAYROLLS
================================ */
// const getAllPayrolls = async (req, res) => {
//   try {
//     const payrolls = await Payroll.find({
//       orgId: req.user?.orgId,
//       isDeleted: false,
//     }).sort({ createdAt: -1 });

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

//     await logUserAction({
//       userId: req.user?._id,
//       action: "FETCH PAYROLLS",
//       model: Payroll,
//       details: { count: payrolls.length },
//       req,
//     });

//     return res.status(200).json({
//       success: true,
//       message: "Fetched all payrolls successfully",
//       data: payrolls,
//     });
//   } catch (error) {
//     return errorResponse(res, "Failed to fetch payrolls", 500, error);
//   }
// };
const getAllPayrolls = async (req, res) => {
  try {
    const orgId = req.user.orgId;

    const page = Number(req.query.page) || 1;
    const limit = Number(req.query.limit) || 10;
    const skip = (page - 1) * limit;

    /* ================= FETCH PAYROLLS ================= */
    const payrolls = await Payroll.find({
      orgId,
      isDeleted: false,
    })
      .select(
        "payrollId payPeriodStart payPeriodEnd payDate payrollCycle status employees createdAt"
      )
      .sort({ createdAt: -1 })
      .skip(skip)
      .limit(limit)
      .lean();

    if (!payrolls.length) {
      return res.status(200).json({
        success: true,
        message: "No payroll records found",
        data: [],
        meta: { page, limit, total: 0, totalPages: 0 },
      });
    }

    /* ================= FLATTEN EMPLOYEES ================= */
    const rows = payrolls.flatMap((payroll) => {
      if (!Array.isArray(payroll.employees)) return [];

      return payroll.employees.map((emp) => ({
        payrollDocId: payroll._id, 
        // empId: emp._id, // employee payroll row id
        payrollId: payroll.payrollId,
        payrollStatus: payroll.status,

        payDate: payroll.payDate,
        payrollCycle: payroll.payrollCycle,

        month: payroll.payPeriodStart
          ? new Date(payroll.payPeriodStart).getMonth() + 1
          : null,
        year: payroll.payPeriodStart
          ? new Date(payroll.payPeriodStart).getFullYear()
          : null,

        employeeId: emp.employeeId,
        employeeName: emp.employeeName,
        role: emp.role,
        department: emp.department?.name || "--",

        grossSalary: emp.grossEarnings,
        totalDeductions: emp.totalDeductions,
        netPay: emp.netPay,

        paymentMethod: emp.paymentMethod,
        currency: emp.currency,

        createdAt: payroll.createdAt,
      }));
    });

    /* ================= COUNT (EMPLOYEE LEVEL) ================= */
    const total = rows.length;

    await logUserAction({
      userId: req.user._id,
      action: "FETCH PAYROLL EMPLOYEE LIST",
      model: Payroll,
      details: { page, limit, total },
      req,
    });

    return res.status(200).json({
      success: true,
      message: "Payroll employee records fetched successfully",
      data: rows,
      meta: {
        page,
        limit,
        total,
        totalPages: Math.ceil(total / limit),
      },
    });
  } catch (error) {
    return errorResponse(res, "Failed to fetch payrolls", 500, error);
  }
};


const getEmployeePayslip = async (req, res) => {
  try {
    const { payrollId, employeeId } = req.params;
    const orgId = req.user.orgId;

    const payroll = await Payroll.findOne({
      payrollId,
      orgId,
      isDeleted: false,
      "employees.employeeId": employeeId,
    })
    .sort({ createdAt: -1 }) // ✅ THIS IS THE KEY
    .lean();

    if (!payroll) {
      return res.status(404).json({
        success: false,
        message: "Payslip not found",
      });
    }

    const employee = payroll.employees.find(
      (e) => e.employeeId.toString() === employeeId
    );

    return res.json({
      success: true,
      data: {
        payrollId: payroll.payrollId,
        month: payroll.payPeriodStart.getMonth() + 1,
        year: payroll.payPeriodStart.getFullYear(),
        payDate: payroll.payDate,
        payrollCycle: payroll.payrollCycle,
        payrollStatus: payroll.status,

        employee: {
          employeeId: employee.employeeId,
          name: employee.employeeName,
          role: employee.role,
          department : employee.department?.name || "--",
          workingDays: employee.workingDays,
          payableDays: employee.payableDays,

          earnings: employee.earnings,
          deductions: employee.deductions,

          grossSalary: employee.grossEarnings,
          totalDeductions: employee.totalDeductions,
          netPay: employee.netPay,
          paymentMethod: employee.paymentMethod,
          currency: employee.currency,
        },
      },
    });
  } catch (err) {
    return res.status(500).json({
      success: false,
      message: "Failed to fetch payslip",
    });
  }
};




const downloadPayslipPdf = async (req, res) => {
  const { payrollId, employeeId } = req.params;
  const orgId = req.user.orgId;

  const payroll = await Payroll.findOne({
    payrollId,
    orgId,
    isDeleted: false,
    "employees.employeeId": employeeId,
  })
  .sort({ createdAt: -1 }) // ✅ THIS IS THE KEY
  .lean();

  if (!payroll) {
    return res.status(404).json({ success: false, message: "Payslip not found" });
  }

  const employee = payroll.employees.find(
    (e) => e.employeeId.toString() === employeeId
  );

  return generatePayslipPdf(res, {
    company: {
      name: "Service Nxt Pvt Ltd",
      address: "Plot 45, Madhapur, Hyderabad, Telangana",
      gstin: "--",
    },
    employee: {
      employeeId: employee.employeeId,
      name: employee.employeeName,
      role: employee.role,
      department: employee.department?.name || "--",
      bankName: "--",
      bankAccount: "--",
      pan: "--",
      pfUan: "--",
      earnings: employee.earnings,
      deductions: employee.deductions,
      netPay: employee.netPay,
    },
    month: payroll.payPeriodStart.getMonth() + 1,
    year: payroll.payPeriodStart.getFullYear(),
  });
};


const previewPayroll = async (req, res) => {
  const { month, year } = req.query;
  const orgId = req.user.orgId;

  if (!month || !year) {
    return errorResponse(res, "Month and year are required", 400);
  }

  const payroll = await Payroll.findOne({
    orgId,
    payrollMonth: Number(month),
    payrollYear: Number(year),
    isDeleted: false,
  }).lean();

  if (!payroll) {
    return errorResponse(res, "Payroll not generated", 404);
  }

  const summary = {
    employeeCount: payroll.employees.length,
    totalGross: payroll.employees.reduce(
      (s, e) => s + (e.grossEarnings || 0),
      0
    ),
    totalNetPay: payroll.employees.reduce(
      (s, e) => s + (e.netPay || 0),
      0
    ),
    status: payroll.status,
  };

  return res.json({
    success: true,
    data: {
      payrollId: payroll.payrollId,
      payrollMonth: payroll.payrollMonth,
      payrollYear: payroll.payrollYear,
      summary,
      employees: payroll.employees,
    },
  });
};


const markPayrollAsPaid = async (req, res) => {
  try {
    const payrollId = req.params.id;
    const userId = req.user._id;

    const payroll = await Payroll.findById(payrollId);

    if (!payroll || payroll.isDeleted) {
      return errorResponse(res, "Payroll not found", 404);
    }

    if (payroll.status === "paid") {
      return errorResponse(res, "Payroll already marked as paid", 400);
    }

    payroll.status = "paid";
    // payroll.isLocked = true;
    payroll.paidAt = new Date();
    payroll.paidBy = userId;
    payroll.updatedBy = userId;

    await payroll.save();

    //  Audit log
    await logUserAction({
      userId,
      orgId: payroll.orgId,
      action: "MARK_PAYROLL_PAID",
      model: "Payroll",
      modelId: payroll._id,
      details: {
        payrollId: payroll.payrollId,
        payrollMonth: payroll.payrollMonth,
        payrollYear: payroll.payrollYear,
        employeeCount: payroll.employees.length,
      },
      req,
    });

    return res.json({
      success: true,
      message: "Payroll marked as paid successfully",
    });
  } catch (err) {
    return errorResponse(res, "Failed to mark payroll as paid", 500, err);
  }
};



module.exports = { createPayroll, deletePayroll, updatePayroll, fetchAllPayrolls, generatePayroll, getAllPayrolls, getEmployeePayslip, downloadPayslipPdf, previewPayroll, markPayrollAsPaid };
