const User = require("../../models/userModel");
const Attendance = require("../../models/attendanceModel");
const Payroll = require("../../models/accounts/payrollModel");
const PayrollHistory = require("../../models/accounts/payrollHistoryModel");

// const generateMonthlyPayroll = async ({ orgId, month, year, createdBy }) => {
//   // 1. Get active employees
//   const employees = await User.find({
//     orgId,
//     isDeleted: false,
//     salary: { $ne: null },
//     status: "Approved",
//   });

//   if (!employees.length) {
//     throw new Error("No employees found for payroll generation");
//   }

//   const payrollRecords = [];

//   for (const emp of employees) {
//     // 2. Get attendance for the month
//     const startDate = `${year}-${String(month).padStart(2, "0")}-01`;
//     const endDate = `${year}-${String(month).padStart(2, "0")}-31`;

//     const attendance = await Attendance.find({
//       user: emp._id,
//       orgId,
//       date: { $gte: startDate, $lte: endDate },
//       isDeleted: false,
//     });

//     // 3. Attendance calculation
//     let present = 0;
//     let halfDay = 0;

//     attendance.forEach((a) => {
//       if (a.status === "Present") present += 1;
//       if (a.status === "Half-Day") halfDay += 1;
//     });

//     const payableDays = present + halfDay * 0.5;
//     const perDaySalary = emp.salary / emp.workingDays;
//     const netPay = Math.round(perDaySalary * payableDays);

//     // 4. Prepare payroll record
//     payrollRecords.push({
//       payrollId: `PAY-${Date.now()}-${emp._id.toString().slice(-4)}`,
//       orgId,
//       employeeId: emp._id,
//       employeeName: `${emp.firstName} ${emp.lastName || ""}`,
//       role: emp.role,
//       month,
//       year,
//       workingDays: emp.workingDays,
//       payableDays,
//       grossSalary: emp.salary,
//       netPay,
//       status: "PENDING",
//       createdBy,
//       updatedBy: createdBy,
//     });
//   }

//   // 5. Save payroll
//   await Payroll.insertMany(payrollRecords);

//   return payrollRecords.length;
// };



// const generateMonthlyPayroll = async ({ orgId, month, year, createdBy }) => {
//   const employees = await User.find({
//     orgId,
//     isDeleted: false,
//     salary: { $ne: null },
//     status: "Approved",
//   });

//   if (!employees.length) {
//     throw new Error("No approved employees found");
//   }

//   const payPeriodStart = new Date(year, month - 1, 1);
//   const payPeriodEnd = new Date(year, month, 0);

//   const payrollEmployees = [];

//   for (const emp of employees) {
//     const attendance = await Attendance.find({
//       user: emp._id,
//       orgId,
//       date: {
//         $gte: payPeriodStart.toISOString().slice(0, 10),
//         $lte: payPeriodEnd.toISOString().slice(0, 10),
//       },
//       isDeleted: false,
//     });

//     let present = 0;
//     let halfDay = 0;

//     attendance.forEach((a) => {
//       if (a.status === "Present") present++;
//       if (a.status === "Half-Day") halfDay++;
//     });

//     const payableDays = present + halfDay * 0.5;
//     const perDaySalary = emp.salary / emp.workingDays;
//     const gross = Math.round(perDaySalary * payableDays);

//     payrollEmployees.push({
//       employeeId: emp._id,
//       employeeName: `${emp.firstName} ${emp.lastName || ""}`,
//       role: emp.role,

//       earnings: [
//         { name: "Basic Salary", amount: gross }
//       ],

//       deductions: [],

//       grossEarnings: gross,
//       totalDeductions: 0,
//       netPay: gross,

//       paymentMethod: "bank_transfer",
//       currency: "INR",
//     });
//   }

//   const payroll = await Payroll.create({
//     payrollId: `PAY-${year}${month}-${Date.now()}`,
//     orgId,
//     payPeriodStart,
//     payPeriodEnd,
//     payDate: new Date(),
//     payrollCycle: "monthly",
//     employees: payrollEmployees,
//     status: "processed",
//     createdBy,
//     updatedBy: createdBy,
//   });

//   return payroll;
// };


// const calculateEmployeesPayroll = async (orgId, month, year) => {
//   // 1️⃣ Get employees
//   const employees = await User.find({
//     orgId,
//     isDeleted: false,
//     status: "Active",
//   });

//   const payrollEmployees = [];

//   for (const emp of employees) {
//     // 2️⃣ Fetch attendance for this employee
//     const attendanceRecords = await Attendance.find({
//       employeeId: emp._id,
//       orgId,
//       month,
//       year,
//     });

//     // 3️⃣ Aggregate attendance
//     let present = 0;
//     let absent = 0;
//     let halfDay = 0;

//     attendanceRecords.forEach((a) => {
//       if (a.status === "Present") present++;
//       else if (a.status === "Absent") absent++;
//       else if (a.status === "Half-Day") halfDay++;
//     });

//     // 4️⃣ Salary calculation (example)
//     const perDaySalary = emp.salary / 30;
//     const gross = present * perDaySalary + halfDay * (perDaySalary / 2);

//     const deductions = []; // tax, pf, etc
//     const totalDeductions = deductions.reduce((s, d) => s + d.amount, 0);

//     const netPay = gross - totalDeductions;

//     // 5️⃣ Snapshot history
//     await EmployeePayrollHistory.findOneAndUpdate(
//       { employeeId: emp._id, payrollMonth: month, payrollYear: year },
//       {
//         orgId,
//         employeeId: emp._id,
//         payrollMonth: month,
//         payrollYear: year,
//         salaryBreakup: { gross, netPay },
//         attendanceSummary: { present, absent, halfDay },
//       },
//       { upsert: true, new: true }
//     );

//     payrollEmployees.push({
//       employeeId: emp._id,
//       employeeName: emp.firstName,
//       role: emp.role,
//       grossEarnings: gross,
//       totalDeductions,
//       netPay,
//     });
//   }

//   return payrollEmployees;
// };
// const calculateEmployeesPayroll = async (orgId, month, year) => {
//   const payPeriodStart = new Date(year, month - 1, 1, 0, 0, 0, 0);
//   const payPeriodEnd = new Date(year, month, 0, 23, 59, 59, 999);


//   const employees = await User.find({
//     orgId,
//     isDeleted: false,
//     salary: { $ne: null },
//     status: "Approved",
//   }).populate("department", "deptName");

//   if (!employees.length) {
//     throw new Error("No approved employees found");
//   }

//   const payrollEmployees = [];

//   for (const emp of employees) {
//     const attendance = await Attendance.find({
//       user: emp._id,
//       orgId,
//       date: { $gte: payPeriodStart, $lte: payPeriodEnd },
//       isDeleted: false,
//     });

//     let present = 0;
//     let halfDay = 0;
//     let absent = 0;

//     attendance.forEach((a) => {
//       if (a.status === "Present") present++;
//       else if (a.status === "Half-Day") halfDay++;
//       else if (a.status === "Absent") absent++;
//     });

//     const payableDays = present + halfDay * 0.5;
//     const perDaySalary = emp.salary / emp.workingDays;
//     const gross = Math.round(perDaySalary * payableDays);

//     // 🔥 Snapshot history
//     await PayrollHistory.findOneAndUpdate(
//       {
//         orgId,
//         employeeId: emp._id,
//         payrollMonth: month,
//         payrollYear: year,
//       },
//       {
//         orgId,
//         employeeId: emp._id,
//         payrollMonth: month,
//         payrollYear: year,
//         payrollId: `PAY-${year}-${String(month).padStart(2, "0")}`,
//         salaryBreakup: {
//           gross,
//           netPay: gross,
//         },
//         attendanceSummary: {
//           present,
//           absent,
//           halfDay,
//         },
//       },
//       { upsert: true, new: true }
//     );

//     payrollEmployees.push({
//       employeeId: emp._id,
//       employeeName: `${emp.firstName} ${emp.lastName || ""}`,
//       role: emp.role,
//       department: {
//         id: emp.department?._id,
//         name: emp.department?.deptName || "--",
//       },
//       workingDays: emp.workingDays,
//       payableDays,
//       earnings: [{ name: "Basic Salary", amount: gross }],
//       deductions: [],
//       grossEarnings: gross,
//       totalDeductions: 0,
//       netPay: gross,
//       paymentMethod: "bank_transfer",
//       currency: "INR",
//     });
//   }

//   return payrollEmployees;
// };
// const calculateEmployeesPayroll = async (orgId, month, year) => {
//   const start = `${year}-${String(month).padStart(2, "0")}-01`;
//   const endDate = new Date(year, month, 0).getDate();
//   const end = `${year}-${String(month).padStart(2, "0")}-${endDate}`;

//   const employees = await User.find({
//     orgId,
//     isDeleted: false,
//     salary: { $ne: null },
//     status: "Approved",
//   }).populate("department", "deptName");

//   const payrollEmployees = [];

//   for (const emp of employees) {
//     const attendance = await Attendance.find({
//       user: emp._id,
//       orgId,
//       date: { $gte: start, $lte: end }, // ✅ STRING RANGE
//       isDeleted: false,
//     });

//     let present = 0;
//     let halfDay = 0;
//     let absent = 0;

//     attendance.forEach((a) => {
//       if (a.status === "Present") present++;
//       else if (a.status === "Half-Day") halfDay++;
//       else if (a.status === "Late") present++; // ✅ treat Late as Present
//       else if (a.status === "Absent") absent++;
//     });

//     const payableDays = present + halfDay * 0.5;
//     const perDaySalary = emp.salary / emp.workingDays;
//     const gross = Math.round(perDaySalary * payableDays);

//     payrollEmployees.push({
//       employeeId: emp._id,
//       employeeName: `${emp.firstName} ${emp.lastName || ""}`,
//       role: emp.role,
//       department: {
//         id: emp.department?._id,
//         name: emp.department?.deptName || "--",
//       },
//       workingDays: emp.workingDays,
//       payableDays,
//       earnings: [{ name: "Basic Salary", amount: gross }],
//       deductions: [],
//       grossEarnings: gross,
//       totalDeductions: 0,
//       netPay: gross,
//       paymentMethod: "bank_transfer",
//       currency: "INR",
//     });
//   }

//   return payrollEmployees;
// };

const calculateEmployeesPayroll = async (orgId, month, year) => {
  const start = `${year}-${String(month).padStart(2, "0")}-01`;
  const endDay = new Date(year, month, 0).getDate();
  const end = `${year}-${String(month).padStart(2, "0")}-${endDay}`;

  const employees = await User.find({
    orgId,
    isDeleted: false,
    salary: { $ne: null },
    status: "Approved",
  });

  const payrollEmployees = [];

  for (const emp of employees) {
    const attendance = await Attendance.find({
      user: emp._id,
      orgId,
      date: { $gte: start, $lte: end },
      isDeleted: false,
    }).lean();

    let present = 0;
    let halfDay = 0;
    let absent = 0;

    attendance.forEach(a => {
      if (a.status === "Present" || a.status === "Late") present++;
      else if (a.status === "Half-Day") halfDay++;
      else if (a.status === "Absent") absent++;
    });

    const payableDays = present + halfDay * 0.5;
    const perDaySalary = emp.salary / emp.workingDays;
    const gross = Math.round(perDaySalary * payableDays);

    /* ================= SAVE PAYROLL HISTORY ================= */
    await PayrollHistory.findOneAndUpdate(
      {
        orgId,
        employeeId: emp._id,
        payrollMonth: month,
        payrollYear: year,
      },
      {
        orgId,
        employeeId: emp._id,
        payrollId: `PAY-${year}-${String(month).padStart(2, "0")}`,
        payrollMonth: month,
        payrollYear: year,

        salaryBreakup: {
          earnings: [{ name: "Basic Salary", amount: gross }],
          deductions: [],
          gross,
          netPay: gross,
        },

        attendanceSummary: {
          totalDays: emp.workingDays,
          presentDays: present,
          halfDays: halfDay,
          absentDays: absent,
          leaveDays: 0,
        },

        attendanceDetails: attendance.map(a => ({
          date: new Date(a.date),
          status: a.status,
          workedHours: Math.round((a.totalMinutes || 0) / 60),
        })),
      },
      { upsert: true, new: true }
    );

    payrollEmployees.push({
      employeeId: emp._id,
      employeeName: `${emp.firstName} ${emp.lastName || ""}`,
      role: emp.role,
      workingDays: emp.workingDays,
      payableDays,
      earnings: [{ name: "Basic Salary", amount: gross }],
      deductions: [],
      grossEarnings: gross,
      totalDeductions: 0,
      netPay: gross,
      paymentMethod: "bank_transfer",
      currency: "INR",
    });
  }

  return payrollEmployees;
};




// const generateMonthlyPayroll = async ({ orgId, month, year, createdBy }) => {
//   const payPeriodStart = new Date(year, month - 1, 1);
//   const payPeriodEnd = new Date(year, month, 0);

//   //  Lock payroll month
//   const existingPayroll = await Payroll.findOne({
//     orgId,
//     payPeriodStart,
//     payPeriodEnd,
//     isDeleted: false,
//   });

//   if (existingPayroll) {
//     throw new Error("Payroll already generated for this month");
//   }

//   const employees = await User.find({
//     orgId,
//     isDeleted: false,
//     salary: { $ne: null },
//     status: "Approved",
//   })
//     .populate("department", "deptName");

//   if (!employees.length) {
//     throw new Error("No approved employees found");
//   }

//   const payrollEmployees = [];

//   const start = payPeriodStart.toISOString().split("T")[0];
//   const end = payPeriodEnd.toISOString().split("T")[0];

//   for (const emp of employees) {
//     const attendance = await Attendance.find({
//       user: emp._id,
//       orgId,
//       date: { $gte: start, $lte: end },
//       isDeleted: false,
//     });

//     let present = 0;
//     let halfDay = 0;

//     attendance.forEach((a) => {
//       if (a.status === "Present") present++;
//       if (a.status === "Half-Day") halfDay++;
//     });

//     const payableDays = present + halfDay * 0.5;
//     const perDaySalary = emp.salary / emp.workingDays;
//     const gross = Math.round(perDaySalary * payableDays);

//     payrollEmployees.push({
//       employeeId: emp._id,
//       employeeName: `${emp.firstName} ${emp.lastName || ""}`,
//       role: emp.role,

//       department: {
//         id: emp.department?._id,
//         name: emp.department?.deptName || "--",
//       },
//       workingDays: emp.workingDays,
//       payableDays,
//       earnings: [{ name: "Basic Salary", amount: gross }],
//       deductions: [],
//       grossEarnings: gross,
//       totalDeductions: 0,
//       netPay: gross,
//       paymentMethod: "bank_transfer",
//       currency: "INR",
//     });
//   }

//   const payroll = await Payroll.create({
//     payrollId: `PAY-${year}-${String(month).padStart(2, "0")}`,
//     orgId,
//     payPeriodStart,
//     payPeriodEnd,
//     payDate: new Date(),
//     payrollCycle: "monthly",
//     employees: payrollEmployees,
//     status: "processed",
//     createdBy,
//     updatedBy: createdBy,
//   });

//   return payroll;
// };

const generateMonthlyPayroll = async ({ orgId, month, year, createdBy }) => {
  const payPeriodStart = new Date(year, month - 1, 1, 0, 0, 0, 0);
  const payPeriodEnd = new Date(year, month, 0, 23, 59, 59, 999);
  const payrollId = `PAY-${year}-${String(month).padStart(2, "0")}`;

  /* ===============================
     STEP 1: SOFT DELETE OLD PAYROLL
  ================================ */
  await Payroll.updateMany(
    {
      orgId,

      // payPeriodStart,
      // payPeriodEnd,

      payrollMonth: month,
      payrollYear: year,
      isDeleted: false,
    },
    {
      isDeleted: true,
      updatedBy: createdBy,
    }
  );

  /* ===============================
     STEP 2: CALCULATE PAYROLL
  ================================ */
  const payrollEmployees = await calculateEmployeesPayroll(
    orgId,
    month,
    year
  );

  /* ===============================
     STEP 3: CREATE PAYROLL
  ================================ */
  const payroll = await Payroll.create({
    payrollId,
    orgId,

    payrollMonth: month,
    payrollYear: year,

    payPeriodStart,
    payPeriodEnd,
    payDate: new Date(),
    payrollCycle: "monthly",
    employees: payrollEmployees,
    status: "processed",
    createdBy,
    updatedBy: createdBy,
    isDeleted: false,
  });

  return payroll;
};



module.exports = {
  generateMonthlyPayroll,
  calculateEmployeesPayroll,
};
