using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using ClosedXML.Excel;
using ClosedXML.Excel.Drawings;
using Microsoft.AspNetCore.Hosting;

using PSTW_CentralSystem.Areas.OTcalculate.Models;
using PSTW_CentralSystem.Models;
using PSTW_CentralSystem.DBContext;


namespace PSTW_CentralSystem.Areas.OTcalculate.Services
{
    public class OvertimeExcel
    {
        private readonly CentralSystemContext _centralDbContext;
        private readonly IWebHostEnvironment _env;

        public OvertimeExcel(CentralSystemContext centralDbContext, IWebHostEnvironment env)
        {
            _centralDbContext = centralDbContext;
            _env = env;
        }

        public MemoryStream GenerateOvertimeExcel(
            List<OtRegisterModel> records,
            UserModel user,
            decimal userRate,
            DateTime? selectedMonth = null,
            bool isHoU = false,
            bool isHoD = false, 
            bool isManager = false, 
            string? flexiHour = null,
            byte[]? logoImage = null,
            bool isSimplifiedExport = false,
            OtStatusModel? otStatus = null)
        {
            bool isAdminUser = IsAdmin(user.Id);
            bool showStationColumn = user.Department?.DepartmentId == 3 || user.Department?.DepartmentId == 2 || isAdminUser;

            var stream = new MemoryStream();

            using (var workbook = new XLWorkbook())
            {
                var worksheet = workbook.Worksheets.Add("Overtime Report");
                worksheet.ShowGridLines = true;

                int currentRow = 1;
                int logoBottomRow = 0;

                if (logoImage != null)
                {
                    using (var ms = new MemoryStream(logoImage))
                    {
                        var picture = worksheet.AddPicture(ms)
                            .MoveTo(worksheet.Cell(currentRow, 1))
                            .WithPlacement(XLPicturePlacement.FreeFloating);

                        picture.Name = "Company Logo";
                        picture.Scale(0.3);
                        logoBottomRow = currentRow + 2;
                    }
                }

                currentRow = logoBottomRow + 1;

                DateTime displayMonth = selectedMonth ??
                    (records.Any() ? records.First().OtDate : DateTime.Now);

                var allDatesInMonth = GetAllDatesInMonth(displayMonth);
                records = records.OrderBy(r => r.OtDate).ToList();

                worksheet.Cell(currentRow, 1).Value = $"Name: {user.FullName}";
                worksheet.Cell(currentRow, 1).Style.Font.SetBold();
                currentRow++;

                worksheet.Cell(currentRow, 1).Value = $"Department: {user.Department?.DepartmentName ?? "N/A"}";
                worksheet.Cell(currentRow, 1).Style.Font.SetBold();
                currentRow++;

                if (!string.IsNullOrEmpty(flexiHour))
                {
                    worksheet.Cell(currentRow, 1).Value = $"Flexi Hour: {flexiHour}";
                    worksheet.Cell(currentRow, 1).Style.Font.SetBold();
                    currentRow++;
                }

                worksheet.Cell(currentRow, 1).Value = $"Overtime Report: {displayMonth:MMMM yyyy}";
                worksheet.Cell(currentRow, 1).Style.Font.SetBold();
                currentRow++;

                currentRow++;

                if (isSimplifiedExport)
                {
                    AddSimplifiedHeaders(worksheet, ref currentRow, showStationColumn);
                }
                else
                {
                    if (isHoU || isHoD || isManager) // If HoU, HoD, or Manager, hide salary details
                    {
                        if (showStationColumn)
                        {
                            AddHoUPSTWAirHeaders(worksheet, ref currentRow); // This already excludes salary info
                        }
                        else
                        {
                            AddHoUNonPSTWAirHeaders(worksheet, ref currentRow); // This already excludes salary info
                        }
                    }
                    else // For other users (who are not HoU, HoD, or Manager)
                    {
                        if (showStationColumn)
                        {
                            AddNonHoUPSTWAirHeaders(worksheet, ref currentRow);
                        }
                        else
                        {
                            AddNonHoUNonPSTWAirHeaders(worksheet, ref currentRow);
                        }
                    }
                }


                var userSetting = _centralDbContext.Hrusersetting
                    .Include(us => us.State)
                    .FirstOrDefault(us => us.UserId == user.Id);

                var publicHolidays = _centralDbContext.Holidays
                    .Where(h => userSetting != null && h.StateId == userSetting.State.StateId)
                    .ToList();

                var publicHolidayDates = publicHolidays.Select(h => h.HolidayDate.Date).ToList();


                var recordsGroupedByDate = records
                    .GroupBy(r => r.OtDate.Date)
                    .ToDictionary(g => g.Key, g => g.ToList());

                decimal totalAllBreaksMinutes = 0;
                decimal totalAllOtMinutes = 0;

                decimal totalOfficeBreak = 0;
                decimal totalAfterBreak = 0;
                decimal totalOtHrsOffice = 0;
                decimal totalOtHrsAfterOffice = 0;
                decimal totalNdOt = 0;
                decimal totalOdUnder4 = 0;
                decimal totalOd4to8 = 0;
                decimal totalOdAfter = 0;
                decimal totalRdUnder4 = 0;
                decimal totalRd4to8 = 0;
                decimal totalRdAfter = 0;
                decimal totalPhUnder8 = 0;
                decimal totalPhAfter = 0;
                decimal grandTotalOt = 0;
                decimal grandTotalNdOd = 0;
                decimal grandTotalRd = 0;
                decimal grandTotalPh = 0;
                decimal grandTotalOtAmount = 0;

                // UserRate is now interpreted as Basic Salary
                var basicSalary = userRate;
                var orp = CalculateOrp(basicSalary); // ORP = Basic Salary / 26
                var hrp = CalculateHrp(orp); // HRP = ORP / 8
                bool hasPrintedSalaryDetails = false;

                DateTime? previousDate = null;

                foreach (var date in allDatesInMonth)
                {
                    recordsGroupedByDate.TryGetValue(date, out var dateRecords);
                    var recordsToShow = dateRecords ?? new List<OtRegisterModel> { new OtRegisterModel { OtDate = date } };
                    recordsToShow = recordsToShow.OrderBy(r => r.OfficeFrom ?? r.AfterFrom).ToList();

                    foreach (var record in recordsToShow)
                    {
                        int col = 1;

                        if (isSimplifiedExport)
                        {
                            var dayCell = worksheet.Cell(currentRow, col);
                            var dateCell = worksheet.Cell(currentRow, col + 1);

                            if (record.OtDate.Date != previousDate?.Date)
                            {
                                dayCell.Value = record.OtDate.ToString("ddd");
                                dateCell.Value = record.OtDate.ToString("dd-MM-yyyy");
                            }
                            else
                            {
                                dayCell.Value = "";
                                dateCell.Value = "";
                            }
                            ApplyDayTypeStyle(dayCell, record.OtDate, userSetting?.State?.WeekendId, publicHolidayDates);
                            ApplyDayTypeStyle(dateCell, record.OtDate, userSetting?.State?.WeekendId, publicHolidayDates);
                            col += 2;

                            worksheet.Cell(currentRow, col++).Value = record.OfficeFrom?.ToString(@"hh\:mm") ?? "";
                            worksheet.Cell(currentRow, col++).Value = record.OfficeTo?.ToString(@"hh\:mm") ?? "";
                            worksheet.Cell(currentRow, col++).Value = FormatAsHourMinute(record.OfficeBreak, isMinutes: true);

                            worksheet.Cell(currentRow, col++).Value = record.AfterFrom?.ToString(@"hh\:mm") ?? "";
                            worksheet.Cell(currentRow, col++).Value = record.AfterTo?.ToString(@"hh\:mm") ?? "";
                            worksheet.Cell(currentRow, col++).Value = FormatAsHourMinute(record.AfterBreak, isMinutes: true);

                            var currentRecordTotalOtMinutes = (CalculateTimeDifferenceInMinutes(record.OfficeFrom, record.OfficeTo) - record.OfficeBreak.GetValueOrDefault(0)) +
                                                              (CalculateTimeDifferenceInMinutes(record.AfterFrom, record.AfterTo) - record.AfterBreak.GetValueOrDefault(0));
                            currentRecordTotalOtMinutes = Math.Max(0, currentRecordTotalOtMinutes);
                            worksheet.Cell(currentRow, col++).Value = FormatAsHourMinute(currentRecordTotalOtMinutes, isMinutes: true);
                            totalAllOtMinutes += currentRecordTotalOtMinutes;

                            var currentRecordTotalBreakMinutes = record.OfficeBreak.GetValueOrDefault(0) + record.AfterBreak.GetValueOrDefault(0);
                            worksheet.Cell(currentRow, col++).Value = FormatAsHourMinute(currentRecordTotalBreakMinutes, isMinutes: true);
                            totalAllBreaksMinutes += currentRecordTotalBreakMinutes;

                            if (showStationColumn)
                            {
                                worksheet.Cell(currentRow, col++).Value = record.Stations?.StationName ?? "";
                            }

                            var descriptionCell = worksheet.Cell(currentRow, col);
                            descriptionCell.Value = record.OtDescription ?? "";
                            descriptionCell.Style.Alignment.WrapText = true;
                            descriptionCell.Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Left;
                            descriptionCell.Style.Alignment.Vertical = XLAlignmentVerticalValues.Top;
                            col++;

                            var rowRange = worksheet.Range(currentRow, 1, currentRow, col - 1);
                            rowRange.Style.Border.SetOutsideBorder(XLBorderStyleValues.Thin);
                            rowRange.Style.Border.InsideBorder = XLBorderStyleValues.Thin;
                            rowRange.Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Center;
                            rowRange.Style.Alignment.Vertical = XLAlignmentVerticalValues.Center;
                            descriptionCell.Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Left;

                        }
                        else // Not simplified export
                        {
                            var dayType = GetDayType(date, userSetting?.State?.WeekendId, publicHolidayDates);
                            var classified = ClassifyOt(record, hrp, publicHolidayDates, userSetting?.State?.WeekendId);

                            decimal currentNdOt = decimal.TryParse(classified["ndAfter"], out decimal ndOtVal) ? ndOtVal : 0;
                            decimal currentOdUnder4 = decimal.TryParse(classified["odUnder4"], out decimal odUnder4Val) ? odUnder4Val : 0;
                            decimal currentOd4to8 = decimal.TryParse(classified["odBetween4And8"], out decimal od4to8Val) ? od4to8Val : 0;
                            decimal currentOdAfter = decimal.TryParse(classified["odAfter"], out decimal odAfterVal) ? odAfterVal : 0;
                            decimal currentRdUnder4 = decimal.TryParse(classified["rdUnder4"], out decimal rdUnder4Val) ? rdUnder4Val : 0;
                            decimal currentRd4to8 = decimal.TryParse(classified["rdBetween4And8"], out decimal rd4to8Val) ? rd4to8Val : 0;
                            decimal currentRdAfter = decimal.TryParse(classified["rdAfter"], out decimal rdAfterVal) ? rdAfterVal : 0;
                            decimal currentPhUnder8 = decimal.TryParse(classified["phUnder8"], out decimal phUnder8Val) ? phUnder8Val : 0;
                            decimal currentPhAfter = decimal.TryParse(classified["phAfter"], out decimal phAfterVal) ? phAfterVal : 0;

                            decimal currentRowTotalOt = currentNdOt + currentOdUnder4 + currentOd4to8 + currentOdAfter +
                                                        currentRdUnder4 + currentRd4to8 + currentRdAfter +
                                                        currentPhUnder8 + currentPhAfter;

                            decimal currentRowTotalNdOd = currentNdOt + currentOdUnder4 + currentOd4to8 + currentOdAfter;
                            decimal currentRowTotalRd = currentRdUnder4 + currentRd4to8 + currentRdAfter;
                            decimal currentRowTotalPh = currentPhUnder8 + currentPhAfter;

                            decimal otAmtValParsed = 0;
                            string otAmt = "";

                            if (!isHoU && !isHoD && !isManager) // Only calculate and show OT amount if not HoU, HoD, or Manager
                            {
                                otAmt = CalculateOtAmount(record, hrp, publicHolidayDates, userSetting?.State?.WeekendId);
                                otAmtValParsed = decimal.TryParse(otAmt, out decimal val) ? val : 0;
                            }


                            totalOfficeBreak += (decimal)record.OfficeBreak.GetValueOrDefault(0);
                            totalAfterBreak += (decimal)record.AfterBreak.GetValueOrDefault(0);
                            totalOtHrsOffice += ConvertTimeToDecimal(CalculateOfficeOtHours(record));
                            totalOtHrsAfterOffice += ConvertTimeToDecimal(CalculateAfterOfficeOtHours(record));

                            totalNdOt += currentNdOt;
                            totalOdUnder4 += currentOdUnder4;
                            totalOd4to8 += currentOd4to8;
                            totalOdAfter += currentOdAfter;
                            totalRdUnder4 += currentRdUnder4;
                            totalRd4to8 += currentRd4to8;
                            totalRdAfter += currentRdAfter;
                            totalPhUnder8 += currentPhUnder8;
                            totalPhAfter += currentPhAfter;

                            grandTotalOt += currentRowTotalOt;
                            grandTotalNdOd += currentRowTotalNdOd;
                            grandTotalRd += currentRowTotalRd;
                            grandTotalPh += currentRowTotalPh;
                            grandTotalOtAmount += otAmtValParsed; // Only add if it was calculated

                            if (!isHoU && !isHoD && !isManager) // Only show if not HoU, HoD, or Manager
                            {
                                // Basic Salary
                                worksheet.Cell(currentRow, col).Value = !hasPrintedSalaryDetails ? basicSalary.ToString("N2") : "";
                                worksheet.Cell(currentRow, col++).Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Center;
                                // ORP
                                worksheet.Cell(currentRow, col).Value = !hasPrintedSalaryDetails ? orp.ToString("N2") : "";
                                worksheet.Cell(currentRow, col++).Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Center;
                                // HRP
                                worksheet.Cell(currentRow, col).Value = !hasPrintedSalaryDetails ? hrp.ToString("N2") : "";
                                worksheet.Cell(currentRow, col++).Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Center;
                            }
                            hasPrintedSalaryDetails = true; // Ensure these are printed only once if visible

                            var dayCell = worksheet.Cell(currentRow, col);
                            var dateCell = worksheet.Cell(currentRow, col + 1);

                            if (record.OtDate.Date != previousDate?.Date)
                            {
                                dayCell.Value = record.OtDate.ToString("ddd");
                                dateCell.Value = record.OtDate.ToString("dd-MM-yyyy");
                            }
                            else
                            {
                                dayCell.Value = "";
                                dateCell.Value = "";
                            }
                            ApplyDayTypeStyle(dayCell, record.OtDate, userSetting?.State?.WeekendId, publicHolidayDates);
                            ApplyDayTypeStyle(dateCell, record.OtDate, userSetting?.State?.WeekendId, publicHolidayDates);
                            col += 2;

                            worksheet.Cell(currentRow, col++).Value = record.OfficeFrom?.ToString(@"hh\:mm") ?? "";
                            worksheet.Cell(currentRow, col++).Value = record.OfficeTo?.ToString(@"hh\:mm") ?? "";
                            worksheet.Cell(currentRow, col++).Value = FormatAsHourMinute(record.OfficeBreak, isMinutes: true);

                            worksheet.Cell(currentRow, col++).Value = record.AfterFrom?.ToString(@"hh\:mm") ?? "";
                            worksheet.Cell(currentRow, col++).Value = record.AfterTo?.ToString(@"hh\:mm") ?? "";
                            worksheet.Cell(currentRow, col++).Value = FormatAsHourMinute(record.AfterBreak, isMinutes: true);

                            worksheet.Cell(currentRow, col++).Value = CalculateOfficeOtHours(record);
                            worksheet.Cell(currentRow, col++).Value = CalculateAfterOfficeOtHours(record);

                            worksheet.Cell(currentRow, col++).Value = currentNdOt > 0 ? currentNdOt.ToString("N2") : "";
                            worksheet.Cell(currentRow, col++).Value = currentOdUnder4 > 0 ? currentOdUnder4.ToString("N2") : "";
                            worksheet.Cell(currentRow, col++).Value = currentOd4to8 > 0 ? currentOd4to8.ToString("N2") : "";
                            worksheet.Cell(currentRow, col++).Value = currentOdAfter > 0 ? currentOdAfter.ToString("N2") : "";
                            worksheet.Cell(currentRow, col++).Value = currentRdUnder4 > 0 ? currentRdUnder4.ToString("N2") : "";
                            worksheet.Cell(currentRow, col++).Value = currentRd4to8 > 0 ? currentRd4to8.ToString("N2") : "";
                            worksheet.Cell(currentRow, col++).Value = currentRdAfter > 0 ? currentRdAfter.ToString("N2") : "";
                            worksheet.Cell(currentRow, col++).Value = currentPhUnder8 > 0 ? currentPhUnder8.ToString("N2") : "";
                            worksheet.Cell(currentRow, col++).Value = currentPhAfter > 0 ? currentPhAfter.ToString("N2") : "";

                            worksheet.Cell(currentRow, col++).Value = currentRowTotalOt > 0 ? currentRowTotalOt.ToString("N2") : "";
                            worksheet.Cell(currentRow, col++).Value = currentRowTotalNdOd > 0 ? currentRowTotalNdOd.ToString("N2") : "";
                            worksheet.Cell(currentRow, col++).Value = currentRowTotalRd > 0 ? currentRowTotalRd.ToString("N2") : "";
                            worksheet.Cell(currentRow, col++).Value = currentRowTotalPh > 0 ? currentRowTotalPh.ToString("N2") : "";

                            if (!isHoU && !isHoD && !isManager) // Only show if not HoU, HoD, or Manager
                            {
                                worksheet.Cell(currentRow, col++).Value = otAmt == "0.00" ? "" : otAmt;
                            }

                            if (showStationColumn)
                            {
                                worksheet.Cell(currentRow, col++).Value = record.Stations?.StationName ?? "";
                            }

                            var descriptionCell = worksheet.Cell(currentRow, col);
                            descriptionCell.Value = record.OtDescription ?? "";
                            descriptionCell.Style.Alignment.WrapText = true;
                            descriptionCell.Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Left;
                            descriptionCell.Style.Alignment.Vertical = XLAlignmentVerticalValues.Top;
                            col++;

                            var rowRange = worksheet.Range(currentRow, 1, currentRow, col - 1);
                            rowRange.Style.Border.SetOutsideBorder(XLBorderStyleValues.Thin);
                            rowRange.Style.Border.InsideBorder = XLBorderStyleValues.Thin;
                            rowRange.Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Center;
                            rowRange.Style.Alignment.Vertical = XLAlignmentVerticalValues.Center;
                            descriptionCell.Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Left;
                        }

                        currentRow++;
                        previousDate = record.OtDate.Date;
                    }
                }

                var totalsRowRange = worksheet.Range(currentRow, 1, currentRow, worksheet.LastColumnUsed().ColumnNumber());
                totalsRowRange.Style.Font.SetBold();
                foreach (var cell in totalsRowRange.Cells())
                {
                    ApplyHeaderStyle(cell, 5);
                }
                totalsRowRange.Style.Border.SetOutsideBorder(XLBorderStyleValues.Thin);
                totalsRowRange.Style.Border.InsideBorder = XLBorderStyleValues.Thin;


                if (isSimplifiedExport)
                {
                    int totalLabelStartColumnIndex = 1;
                    int totalLabelEndColumnIndex = 2;

                    worksheet.Range(currentRow, totalLabelStartColumnIndex, currentRow, totalLabelEndColumnIndex).Merge();
                    worksheet.Cell(currentRow, totalLabelStartColumnIndex).Value = "TOTAL";
                    worksheet.Cell(currentRow, totalLabelStartColumnIndex).Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Center;

                    int currentTotalCol = totalLabelEndColumnIndex + 1;

                    currentTotalCol += 6;

                    worksheet.Cell(currentRow, currentTotalCol++).Value = FormatAsHourMinute(totalAllOtMinutes, isMinutes: true);

                    worksheet.Cell(currentRow, currentTotalCol++).Value = FormatAsHourMinute(totalAllBreaksMinutes, isMinutes: true);

                    if (showStationColumn)
                    {
                        currentTotalCol++;
                    }
                }
                else
                {
                    int totalLabelStartColumnIndex = 1;
                    int totalLabelEndColumnIndex;

                    if (!isHoU && !isHoD && !isManager) // If not HoU, HoD, or Manager, include salary columns in merge
                    {
                        totalLabelEndColumnIndex = 3;
                    }
                    else
                    {
                        totalLabelEndColumnIndex = 2;
                    }

                    worksheet.Range(currentRow, totalLabelStartColumnIndex, currentRow, totalLabelEndColumnIndex).Merge();
                    worksheet.Cell(currentRow, totalLabelStartColumnIndex).Value = "TOTAL";
                    worksheet.Cell(currentRow, totalLabelStartColumnIndex).Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Center;

                    int colOfficeBreakIndex = 0;
                    int colAfterBreakIndex = 0;
                    int colNdOtIndex = 0;
                    int colOdUnder4Index = 0;
                    int colOd4to8Index = 0;
                    int colOdAfterIndex = 0;
                    int colRdUnder4Index = 0;
                    int colRd4to8Index = 0;
                    int colRdAfterIndex = 0;
                    int colPhUnder8Index = 0;
                    int colPhAfterIndex = 0;
                    int colTotalOtIndex = 0;
                    int colTotalNdOdIndex = 0;
                    int colTotalRdIndex = 0;
                    int colTotalPhIndex = 0;
                    int colOtAmtIndex = 0;

                    if (!isHoU && !isHoD && !isManager)
                    {
                        colOfficeBreakIndex = 8;
                        colAfterBreakIndex = 11;
                        colNdOtIndex = 14;
                        colOdUnder4Index = 15;
                        colOd4to8Index = 16;
                        colOdAfterIndex = 17;
                        colRdUnder4Index = 18;
                        colRd4to8Index = 19;
                        colRdAfterIndex = 20;
                        colPhUnder8Index = 21;
                        colPhAfterIndex = 22;
                        colTotalOtIndex = 23;
                        colTotalNdOdIndex = 24;
                        colTotalRdIndex = 25;
                        colTotalPhIndex = 26;
                        colOtAmtIndex = 27;
                    }
                    else
                    {
                        colOfficeBreakIndex = 5;
                        colAfterBreakIndex = 8;
                        colNdOtIndex = 11;
                        colOdUnder4Index = 12;
                        colOd4to8Index = 13;
                        colOdAfterIndex = 14;
                        colRdUnder4Index = 15;
                        colRd4to8Index = 16;
                        colRdAfterIndex = 17;
                        colPhUnder8Index = 18;
                        colPhAfterIndex = 19;
                        colTotalOtIndex = 20;
                        colTotalNdOdIndex = 21;
                        colTotalRdIndex = 22;
                        colTotalPhIndex = 23;
                    }

                    worksheet.Cell(currentRow, colOfficeBreakIndex).Value = string.IsNullOrEmpty(FormatAsHourMinute(totalOfficeBreak, isMinutes: true)) ? "0:00" : FormatAsHourMinute(totalOfficeBreak, isMinutes: true);
                    worksheet.Cell(currentRow, colAfterBreakIndex).Value = string.IsNullOrEmpty(FormatAsHourMinute(totalAfterBreak, isMinutes: true)) ? "0:00" : FormatAsHourMinute(totalAfterBreak, isMinutes: true);

                    worksheet.Cell(currentRow, colNdOtIndex).Value = totalNdOt.ToString("N2");
                    worksheet.Cell(currentRow, colOdUnder4Index).Value = totalOdUnder4.ToString("N2");
                    worksheet.Cell(currentRow, colOd4to8Index).Value = totalOd4to8.ToString("N2");
                    worksheet.Cell(currentRow, colOdAfterIndex).Value = totalOdAfter.ToString("N2");
                    worksheet.Cell(currentRow, colRdUnder4Index).Value = totalRdUnder4.ToString("N2");
                    worksheet.Cell(currentRow, colRd4to8Index).Value = totalRd4to8.ToString("N2");
                    worksheet.Cell(currentRow, colRdAfterIndex).Value = totalRdAfter.ToString("N2");
                    worksheet.Cell(currentRow, colPhUnder8Index).Value = totalPhUnder8.ToString("N2");
                    worksheet.Cell(currentRow, colPhAfterIndex).Value = totalPhAfter.ToString("N2");
                    worksheet.Cell(currentRow, colTotalOtIndex).Value = grandTotalOt.ToString("N2");
                    worksheet.Cell(currentRow, colTotalNdOdIndex).Value = grandTotalNdOd.ToString("N2");
                    worksheet.Cell(currentRow, colTotalRdIndex).Value = grandTotalRd.ToString("N2");
                    worksheet.Cell(currentRow, colTotalPhIndex).Value = grandTotalPh.ToString("N2");

                    if (!isHoU && !isHoD && !isManager)
                    {
                        worksheet.Cell(currentRow, colOtAmtIndex).Value = Math.Round(grandTotalOtAmount, MidpointRounding.AwayFromZero).ToString("F2");
                    }
                }

                currentRow++;

                if (!isSimplifiedExport && otStatus != null)
                {
                    currentRow++;

                    worksheet.Cell(currentRow, 1).Value = "Approval Summary:";
                    worksheet.Cell(currentRow, 1).Style.Font.SetBold();
                    currentRow++;

                    int signatureStartCol = 1;
                    int signatureColWidth = 5;

                    int remarksStartColumn = worksheet.LastColumnUsed().ColumnNumber() - 2;

                    void AddApproverSignature(int column, string role, string status, DateTime? submitDate, int? approverUserId)
                    {
                        if (status == "Approved")
                        {
                            var approverUser = _centralDbContext.Users.FirstOrDefault(u => u.Id == approverUserId);
                            if (approverUser != null)
                            {
                                var approvedByCell = worksheet.Cell(currentRow, column);
                                approvedByCell.Value = $"Approved by:";
                                approvedByCell.Style.Font.SetBold();
                                approvedByCell.Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Left;

                                worksheet.Cell(currentRow + 1, column).Value = approverUser.FullName;
                                worksheet.Cell(currentRow + 1, column).Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Left;
                                worksheet.Cell(currentRow + 1, column).Style.Font.SetFontName("Brush Script MT");
                                worksheet.Cell(currentRow + 1, column).Style.Font.SetFontSize(18);

                                worksheet.Cell(currentRow + 2, column).Value = approverUser.FullName;
                                worksheet.Cell(currentRow + 2, column).Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Left;

                                worksheet.Cell(currentRow + 3, column).Value = submitDate?.ToString("dd MMMM yyyy") ?? "N/A";
                                worksheet.Cell(currentRow + 3, column).Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Left;
                            }
                        }
                    }

                    var approvalFlow = _centralDbContext.Hrusersetting
                        .Include(us => us.Approvalflow)
                            .ThenInclude(af => af.HeadOfUnit)
                        .Include(us => us.Approvalflow)
                            .ThenInclude(af => af.HeadOfDepartment)
                        .Include(us => us.Approvalflow)
                            .ThenInclude(af => af.ManagerUser)
                        .Include(us => us.Approvalflow)
                            .ThenInclude(af => af.HRUser)
                        .Where(us => us.UserId == user.Id)
                        .Select(us => us.Approvalflow)
                        .FirstOrDefault();

                    if (approvalFlow != null)
                    {
                        int currentSignatureCol = signatureStartCol;
                        bool hasAnyApprovedSignature = false;

                        if (otStatus.HouStatus == "Approved")
                        {
                            AddApproverSignature(currentSignatureCol, "Head of Unit", otStatus.HouStatus, otStatus.HouSubmitDate, approvalFlow.HoU);
                            currentSignatureCol += signatureColWidth;
                            hasAnyApprovedSignature = true;
                        }

                        if (otStatus.HodStatus == "Approved")
                        {
                            AddApproverSignature(currentSignatureCol, "Head of Department", otStatus.HodStatus, otStatus.HodSubmitDate, approvalFlow.HoD);
                            currentSignatureCol += signatureColWidth;
                            hasAnyApprovedSignature = true;
                        }

                        if (otStatus.ManagerStatus == "Approved")
                        {
                            AddApproverSignature(currentSignatureCol, "Manager", otStatus.ManagerStatus, otStatus.ManagerSubmitDate, approvalFlow.Manager);
                            currentSignatureCol += signatureColWidth;
                            hasAnyApprovedSignature = true;
                        }

                        if (otStatus.HrStatus == "Approved")
                        {
                            AddApproverSignature(currentSignatureCol, "HR", otStatus.HrStatus, otStatus.HrSubmitDate, approvalFlow.HR);
                            currentSignatureCol += signatureColWidth;
                            hasAnyApprovedSignature = true;
                        }

                        int remarksColorStartRow = currentRow - 1;
                        var phColorCell = worksheet.Cell(remarksColorStartRow, remarksStartColumn);
                        phColorCell.Value = " ";
                        phColorCell.Style.Fill.BackgroundColor = XLColor.FromHtml("FFC0CB");
                        phColorCell.Style.Border.SetOutsideBorder(XLBorderStyleValues.Thin);

                        worksheet.Cell(remarksColorStartRow, remarksStartColumn + 1).Value = " Public Holiday";
                        worksheet.Cell(remarksColorStartRow, remarksStartColumn + 1).Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Left;

                        var weekendColorCell = worksheet.Cell(remarksColorStartRow + 1, remarksStartColumn);
                        weekendColorCell.Value = " ";
                        weekendColorCell.Style.Fill.BackgroundColor = XLColor.FromHtml("ADD8E6");
                        weekendColorCell.Style.Border.SetOutsideBorder(XLBorderStyleValues.Thin);

                        worksheet.Cell(remarksColorStartRow + 1, remarksStartColumn + 1).Value = " Weekend";
                        worksheet.Cell(remarksColorStartRow + 1, remarksStartColumn + 1).Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Left;



                        int holidayListRow = remarksColorStartRow + 3;
                        worksheet.Cell(holidayListRow, remarksStartColumn).Value = $"Public Holidays in {displayMonth:MMMM yyyy}:";
                        worksheet.Cell(holidayListRow, remarksStartColumn).Style.Font.SetBold();
                        holidayListRow++;

                        if (publicHolidays != null && publicHolidays.Any())
                        {
                            var monthHolidays = publicHolidays
                                .Where(h => h.HolidayDate.Year == displayMonth.Year && h.HolidayDate.Month == displayMonth.Month)
                                .OrderBy(h => h.HolidayDate.Day)
                                .ToList();

                            if (monthHolidays.Any())
                            {
                                foreach (var holiday in monthHolidays)
                                {
                                    worksheet.Cell(holidayListRow, remarksStartColumn).Value = $"- {holiday.HolidayDate:dd MMMM}: {holiday.HolidayName}";
                                    worksheet.Cell(holidayListRow, remarksStartColumn).Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Left;
                                    holidayListRow++;
                                }
                            }
                            else
                            {
                                worksheet.Cell(holidayListRow, remarksStartColumn).Value = "No public holidays recorded for this month.";
                                worksheet.Cell(holidayListRow, remarksStartColumn).Style.Font.SetItalic();
                                holidayListRow++;
                            }
                        }
                        else
                        {
                            worksheet.Cell(holidayListRow, remarksStartColumn).Value = "No public holiday data found.";
                            worksheet.Cell(holidayListRow, remarksStartColumn).Style.Font.SetItalic();
                            holidayListRow++;
                        }

                        if (hasAnyApprovedSignature)
                        {
                            int messageRow = holidayListRow + 2;

                            int lastContentColumn = worksheet.LastColumnUsed().ColumnNumber();
                            var messageCellRange = worksheet.Range(messageRow, 1, messageRow, lastContentColumn);
                            messageCellRange.Merge();
                            messageCellRange.Value = "This is an automatically generated document. No signature is required for validation.";
                            messageCellRange.Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Center;
                            messageCellRange.Style.Alignment.Vertical = XLAlignmentVerticalValues.Center;
                            messageCellRange.Style.Font.SetItalic();
                            messageCellRange.Style.Font.SetFontSize(10);
                            messageCellRange.Style.Font.FontColor = XLColor.Gray;

                            currentRow = messageRow + 1;
                        }

                        currentRow = Math.Max(currentRow, holidayListRow);
                    }
                }
                else if (isSimplifiedExport)
                {
                    AddRemarksSection(worksheet, ref currentRow, displayMonth, userSetting?.State?.WeekendId, publicHolidays.Select(h => new CalendarModel { HolidayDate = h.HolidayDate, HolidayName = h.HolidayName }).ToList());
                }

                worksheet.Columns().AdjustToContents();

                if (isSimplifiedExport)
                {
                    worksheet.Column(1).Width = 10;
                    worksheet.Column(2).Width = 12;
                    worksheet.Column(3).Width = 9;
                    worksheet.Column(4).Width = 9;
                    worksheet.Column(5).Width = 9;
                    worksheet.Column(6).Width = 9;
                    worksheet.Column(7).Width = 9;
                    worksheet.Column(8).Width = 9;
                    worksheet.Column(9).Width = 15;
                    worksheet.Column(10).Width = 10;

                    int descCol = 11;
                    if (showStationColumn)
                    {
                        worksheet.Column(11).Width = 15;
                        descCol = 12;
                    }
                    worksheet.Column(descCol).Width = 60;
                }
                else
                {
                    if (!isHoU && !isHoD && !isManager) // If not HoU, HoD, or Manager, include salary columns in width adjustment
                    {
                        worksheet.Column(1).Width = 15; // Basic Salary
                        worksheet.Column(2).Width = 10; // ORP
                        worksheet.Column(3).Width = 10; // HRP
                        worksheet.Column(4).Width = 10; // Day
                        worksheet.Column(5).Width = 12; // Date

                        worksheet.Column(6).Width = 9; // Office From
                        worksheet.Column(7).Width = 9; // Office To
                        worksheet.Column(8).Width = 9; // Office Break
                        worksheet.Column(9).Width = 9; // After From
                        worksheet.Column(10).Width = 9; // After To
                        worksheet.Column(11).Width = 9; // After Break

                        worksheet.Column(12).Width = 15; // OT Hrs (Office Hour)
                        worksheet.Column(13).Width = 18; // OT Hrs (After Office Hour)

                        for (int i = 14; i <= 27; i++)
                        {
                            worksheet.Column(i).Width = 12;
                        }

                        int descColIndex = showStationColumn ? 29 : 28;
                        worksheet.Column(descColIndex).Width = 60;
                    }
                    else // If HoU, HoD, or Manager, adjust columns without salary info
                    {
                        worksheet.Column(1).Width = 10;
                        worksheet.Column(2).Width = 12;

                        worksheet.Column(3).Width = 9;
                        worksheet.Column(4).Width = 9;
                        worksheet.Column(5).Width = 9;
                        worksheet.Column(6).Width = 9;
                        worksheet.Column(7).Width = 9;
                        worksheet.Column(8).Width = 9;

                        worksheet.Column(9).Width = 15;
                        worksheet.Column(10).Width = 18;

                        for (int i = 11; i <= 23; i++) // Adjust based on new column count
                        {
                            worksheet.Column(i).Width = 12;
                        }

                        int descColIndex = showStationColumn ? 25 : 24; // Adjust based on new column count
                        worksheet.Column(descColIndex).Width = 60;
                    }
                }

                workbook.SaveAs(stream);
            }

            stream.Position = 0;
            return stream;
        }

        private void AddSimplifiedHeaders(IXLWorksheet worksheet, ref int rowIndex, bool showStationColumn)
        {
            int startRowIndex = rowIndex;
            int currentCol = 1;

            var cellDay = worksheet.Cell(rowIndex, currentCol);
            cellDay.Value = "Day";
            ApplyHeaderStyle(cellDay, 1);
            worksheet.Range(rowIndex, currentCol, rowIndex + 1, currentCol).Merge();
            currentCol++;

            var cellDate = worksheet.Cell(rowIndex, currentCol);
            cellDate.Value = "Date";
            ApplyHeaderStyle(cellDate, 1);
            worksheet.Range(rowIndex, currentCol, rowIndex + 1, currentCol).Merge();
            currentCol++;

            var cellOfficeHour = worksheet.Cell(rowIndex, currentCol);
            cellOfficeHour.Value = "Office Hour";
            ApplyHeaderStyle(cellOfficeHour, 2);
            var mergedRangeOfficeHour = worksheet.Range(rowIndex, currentCol, rowIndex, currentCol + 2).Merge();
            mergedRangeOfficeHour.Style.Border.SetOutsideBorder(XLBorderStyleValues.Thin);
            mergedRangeOfficeHour.Style.Border.InsideBorder = XLBorderStyleValues.Thin;
            currentCol += 3;

            var cellAfterOfficeHour = worksheet.Cell(rowIndex, currentCol);
            cellAfterOfficeHour.Value = "After Office Hour";
            ApplyHeaderStyle(cellAfterOfficeHour, 2);
            var mergedRangeAfterOfficeHour = worksheet.Range(rowIndex, currentCol, rowIndex, currentCol + 2).Merge();
            mergedRangeAfterOfficeHour.Style.Border.SetOutsideBorder(XLBorderStyleValues.Thin);
            mergedRangeAfterOfficeHour.Style.Border.InsideBorder = XLBorderStyleValues.Thin;
            currentCol += 3;

            var cellTotalOTHrs = worksheet.Cell(rowIndex, currentCol);
            cellTotalOTHrs.Value = "Total OT Hours";
            ApplyHeaderStyle(cellTotalOTHrs, 1);
            worksheet.Range(rowIndex, currentCol, rowIndex + 1, currentCol).Merge();
            currentCol++;

            var cellBreakMin = worksheet.Cell(rowIndex, currentCol);
            cellBreakMin.Value = "Break (min)";
            ApplyHeaderStyle(cellBreakMin, 1);
            worksheet.Range(rowIndex, currentCol, rowIndex + 1, currentCol).Merge();
            currentCol++;

            if (showStationColumn)
            {
                var cellStation = worksheet.Cell(rowIndex, currentCol);
                cellStation.Value = "Station";
                ApplyHeaderStyle(cellStation, 1);
                worksheet.Range(rowIndex, currentCol, rowIndex + 1, currentCol).Merge();
                currentCol++;
            }

            var cellDescription = worksheet.Cell(rowIndex, currentCol);
            cellDescription.Value = "Description";
            ApplyHeaderStyle(cellDescription, 1);
            worksheet.Range(rowIndex, currentCol, rowIndex + 1, currentCol).Merge();
            currentCol++;

            var headerRow1Range = worksheet.Range(startRowIndex, 1, startRowIndex, worksheet.LastColumnUsed().ColumnNumber());
            headerRow1Range.Style.Border.SetOutsideBorder(XLBorderStyleValues.Thin);
            headerRow1Range.Style.Border.InsideBorder = XLBorderStyleValues.Thin;

            rowIndex++;


            currentCol = 1;
            currentCol += 2;

            var cellOfficeFrom = worksheet.Cell(rowIndex, currentCol++);
            cellOfficeFrom.Value = "From";
            ApplyHeaderStyle(cellOfficeFrom, 3);

            var cellOfficeTo = worksheet.Cell(rowIndex, currentCol++);
            cellOfficeTo.Value = "To";
            ApplyHeaderStyle(cellOfficeTo, 3);

            var cellOfficeBreak = worksheet.Cell(rowIndex, currentCol++);
            cellOfficeBreak.Value = "Break";
            ApplyHeaderStyle(cellOfficeBreak, 3);

            var cellAfterFrom = worksheet.Cell(rowIndex, currentCol++);
            cellAfterFrom.Value = "From";
            ApplyHeaderStyle(cellAfterFrom, 3);

            var cellAfterTo = worksheet.Cell(rowIndex, currentCol++);
            cellAfterTo.Value = "To";
            ApplyHeaderStyle(cellAfterTo, 3);

            var cellAfterBreak = worksheet.Cell(rowIndex, currentCol++);
            cellAfterBreak.Value = "Break";
            ApplyHeaderStyle(cellAfterBreak, 3);

            currentCol += 2;

            if (showStationColumn)
            {
                currentCol++;
            }

            currentCol++;

            var headerRow2Range = worksheet.Range(rowIndex, 1, rowIndex, worksheet.LastColumnUsed().ColumnNumber());
            headerRow2Range.Style.Border.SetOutsideBorder(XLBorderStyleValues.Thin);
            headerRow2Range.Style.Border.InsideBorder = XLBorderStyleValues.Thin;

            rowIndex++;
        }

        private void ApplyHeaderStyle(IXLCell cell, int styleType)
        {
            cell.Style.Font.SetBold();
            cell.Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Center;
            cell.Style.Alignment.Vertical = XLAlignmentVerticalValues.Center;
            cell.Style.Alignment.WrapText = true;
            cell.Style.Border.SetOutsideBorder(XLBorderStyleValues.Thin);
            cell.Style.Border.InsideBorder = XLBorderStyleValues.Thin;

            switch (styleType)
            {
                case 1:
                    cell.Style.Fill.BackgroundColor = XLColor.FromHtml("#78aafa");
                    cell.Style.Font.FontColor = XLColor.Black;
                    break;
                case 2:
                    cell.Style.Fill.BackgroundColor = XLColor.FromHtml("#DDEBF7");
                    cell.Style.Font.FontColor = XLColor.Black;
                    break;
                case 3:
                    cell.Style.Fill.BackgroundColor = XLColor.FromHtml("#C6E0B4");
                    cell.Style.Font.FontColor = XLColor.Black;
                    break;
                case 4:
                    cell.Style.Fill.BackgroundColor = XLColor.FromHtml("#F8CBAD");
                    cell.Style.Font.FontColor = XLColor.Black;
                    break;
                case 5:
                    cell.Style.Fill.BackgroundColor = XLColor.FromHtml("D8D1F5");
                    cell.Style.Font.FontColor = XLColor.Black;
                    break;
                case 6:
                    cell.Style.Fill.BackgroundColor = XLColor.FromHtml("#FF69B4");
                    cell.Style.Font.FontColor = XLColor.Black;
                    break;
                default:
                    cell.Style.Fill.BackgroundColor = XLColor.FromHtml("#A9D08E");
                    cell.Style.Font.FontColor = XLColor.Black;
                    break;
            }
        }
        private void ApplyDayTypeStyle(IXLCell cell, DateTime date, int? weekendId, List<DateTime> publicHolidays)
        {
            uint styleIndex = GetDayCellColorStyleIndex(date, weekendId, publicHolidays);
            cell.Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Center;
            cell.Style.Alignment.Vertical = XLAlignmentVerticalValues.Center;
            cell.Style.Border.SetOutsideBorder(XLBorderStyleValues.Thin);
            cell.Style.Border.InsideBorder = XLBorderStyleValues.Thin;


            switch (styleIndex)
            {
                case 18:
                    cell.Style.Fill.BackgroundColor = XLColor.FromHtml("FFC0CB");
                    break;
                case 19:
                    cell.Style.Fill.BackgroundColor = XLColor.FromHtml("ADD8E6");
                    break;
                default:
                    cell.Style.Fill.BackgroundColor = XLColor.NoColor;
                    break;
            }
        }

        private void AddNonHoUPSTWAirHeaders(IXLWorksheet worksheet, ref int rowIndex)
        {
            int startRowIndex = rowIndex;
            int currentCol = 1;

            currentCol = 1;
            var cellA = worksheet.Cell(rowIndex, currentCol);
            cellA.Value = "Basic Salary (RM)";
            ApplyHeaderStyle(cellA, 6);
            worksheet.Range(rowIndex, currentCol, rowIndex + 1, currentCol).Merge();
            currentCol++;

            var cellB = worksheet.Cell(rowIndex, currentCol);
            cellB.Value = "ORP";
            ApplyHeaderStyle(cellB, 6);
            worksheet.Range(rowIndex, currentCol, rowIndex + 1, currentCol).Merge();
            currentCol++;

            var cellC = worksheet.Cell(rowIndex, currentCol);
            cellC.Value = "HRP";
            ApplyHeaderStyle(cellC, 6);
            worksheet.Range(rowIndex, currentCol, rowIndex + 1, currentCol).Merge();
            currentCol++;

            var cellD = worksheet.Cell(rowIndex, currentCol);
            cellD.Value = "Day";
            ApplyHeaderStyle(cellD, 1);
            worksheet.Range(rowIndex, currentCol, rowIndex + 1, currentCol).Merge();
            currentCol++;

            var cellE = worksheet.Cell(rowIndex, currentCol);
            cellE.Value = "Date";
            ApplyHeaderStyle(cellE, 1);
            worksheet.Range(rowIndex, currentCol, rowIndex + 1, currentCol).Merge();
            currentCol++;

            var cellF = worksheet.Cell(rowIndex, currentCol);
            cellF.Value = "Office Hour";
            ApplyHeaderStyle(cellF, 2);
            var mergedRangeF = worksheet.Range(rowIndex, currentCol, rowIndex, currentCol + 2).Merge();
            mergedRangeF.Style.Border.SetOutsideBorder(XLBorderStyleValues.Thin);
            mergedRangeF.Style.Border.InsideBorder = XLBorderStyleValues.Thin;
            currentCol += 3;

            var cellI = worksheet.Cell(rowIndex, currentCol);
            cellI.Value = "After Office Hour";
            ApplyHeaderStyle(cellI, 2);
            var mergedRangeI = worksheet.Range(rowIndex, currentCol, rowIndex, currentCol + 2).Merge();
            mergedRangeI.Style.Border.SetOutsideBorder(XLBorderStyleValues.Thin);
            mergedRangeI.Style.Border.InsideBorder = XLBorderStyleValues.Thin;
            currentCol += 3;

            var cellL = worksheet.Cell(rowIndex, currentCol);
            cellL.Value = "OT Hrs (Office Hour)";
            ApplyHeaderStyle(cellL, 1);
            worksheet.Range(rowIndex, currentCol, rowIndex + 1, currentCol).Merge();
            currentCol++;

            var cellM = worksheet.Cell(rowIndex, currentCol);
            cellM.Value = "OT Hrs (After Office Hour)";
            ApplyHeaderStyle(cellM, 1);
            worksheet.Range(rowIndex, currentCol, rowIndex + 1, currentCol).Merge();
            currentCol++;

            var cellN = worksheet.Cell(rowIndex, currentCol);
            cellN.Value = "Normal Day (After Office)";
            ApplyHeaderStyle(cellN, 2);
            worksheet.Range(rowIndex, currentCol, rowIndex + 1, currentCol).Merge();
            currentCol++;

            var cellO = worksheet.Cell(rowIndex, currentCol);
            cellO.Value = "Off Day";
            ApplyHeaderStyle(cellO, 2);
            var mergedRangeO = worksheet.Range(rowIndex, currentCol, rowIndex, currentCol + 2).Merge();
            mergedRangeO.Style.Border.SetOutsideBorder(XLBorderStyleValues.Thin);
            mergedRangeO.Style.Border.InsideBorder = XLBorderStyleValues.Thin;
            currentCol += 3;

            var cellR = worksheet.Cell(rowIndex, currentCol);
            cellR.Value = "Rest Day";
            ApplyHeaderStyle(cellR, 2);
            var mergedRangeR = worksheet.Range(rowIndex, currentCol, rowIndex, currentCol + 2).Merge();
            mergedRangeR.Style.Border.SetOutsideBorder(XLBorderStyleValues.Thin);
            mergedRangeR.Style.Border.InsideBorder = XLBorderStyleValues.Thin;
            currentCol += 3;

            var cellU = worksheet.Cell(rowIndex, currentCol);
            cellU.Value = "Public Holiday";
            ApplyHeaderStyle(cellU, 2);
            var mergedRangeU = worksheet.Range(rowIndex, currentCol, rowIndex, currentCol + 1).Merge();
            mergedRangeU.Style.Border.SetOutsideBorder(XLBorderStyleValues.Thin);
            mergedRangeU.Style.Border.InsideBorder = XLBorderStyleValues.Thin;
            currentCol += 2;

            var cellW = worksheet.Cell(rowIndex, currentCol);
            cellW.Value = "Total OT";
            ApplyHeaderStyle(cellW, 1);
            worksheet.Range(rowIndex, currentCol, rowIndex + 1, currentCol).Merge();
            currentCol++;

            var cellX = worksheet.Cell(rowIndex, currentCol);
            cellX.Value = "Total ND & OD";
            ApplyHeaderStyle(cellX, 1);
            worksheet.Range(rowIndex, currentCol, rowIndex + 1, currentCol).Merge();
            currentCol++;

            var cellY = worksheet.Cell(rowIndex, currentCol);
            cellY.Value = "Total RD";
            ApplyHeaderStyle(cellY, 1);
            worksheet.Range(rowIndex, currentCol, rowIndex + 1, currentCol).Merge();
            currentCol++;

            var cellZ = worksheet.Cell(rowIndex, currentCol);
            cellZ.Value = "Total PH";
            ApplyHeaderStyle(cellZ, 1);
            worksheet.Range(rowIndex, currentCol, rowIndex + 1, currentCol).Merge();
            currentCol++;

            var cellAA = worksheet.Cell(rowIndex, currentCol);
            cellAA.Value = "OT Amt (RM)";
            ApplyHeaderStyle(cellAA, 6);
            worksheet.Range(rowIndex, currentCol, rowIndex + 1, currentCol).Merge();
            currentCol++;

            var cellAB = worksheet.Cell(rowIndex, currentCol);
            cellAB.Value = "Station";
            ApplyHeaderStyle(cellAB, 1);
            worksheet.Range(rowIndex, currentCol, rowIndex + 1, currentCol).Merge();
            currentCol++;

            var cellAC = worksheet.Cell(rowIndex, currentCol);
            cellAC.Value = "Description";
            ApplyHeaderStyle(cellAC, 1);
            worksheet.Range(rowIndex, currentCol, rowIndex + 1, currentCol).Merge();
            currentCol++;

            var headerRow1Range = worksheet.Range(startRowIndex, 1, startRowIndex, worksheet.LastColumnUsed().ColumnNumber());
            headerRow1Range.Style.Border.SetOutsideBorder(XLBorderStyleValues.Thin);
            headerRow1Range.Style.Border.InsideBorder = XLBorderStyleValues.Thin;


            rowIndex++;

            currentCol = 1;

            currentCol += 5;

            var cellF_sub = worksheet.Cell(rowIndex, currentCol++);
            cellF_sub.Value = "From";
            ApplyHeaderStyle(cellF_sub, 3);

            var cellG_sub = worksheet.Cell(rowIndex, currentCol++);
            cellG_sub.Value = "To";
            ApplyHeaderStyle(cellG_sub, 3);

            var cellH_sub = worksheet.Cell(rowIndex, currentCol++);
            cellH_sub.Value = "Break";
            ApplyHeaderStyle(cellH_sub, 3);

            var cellI_sub = worksheet.Cell(rowIndex, currentCol++);
            cellI_sub.Value = "From";
            ApplyHeaderStyle(cellI_sub, 3);

            var cellJ_sub = worksheet.Cell(rowIndex, currentCol++);
            cellJ_sub.Value = "To";
            ApplyHeaderStyle(cellJ_sub, 3);

            var cellK_sub = worksheet.Cell(rowIndex, currentCol++);
            cellK_sub.Value = "Break";
            ApplyHeaderStyle(cellK_sub, 3);

            currentCol += 2;

            var cellN_sub = worksheet.Cell(rowIndex, currentCol++);
            cellN_sub.Value = "ND OT";
            ApplyHeaderStyle(cellN_sub, 3);

            var cellO_sub = worksheet.Cell(rowIndex, currentCol++);
            cellO_sub.Value = "OD < 4";
            ApplyHeaderStyle(cellO_sub, 3);

            var cellP_sub = worksheet.Cell(rowIndex, currentCol++);
            cellP_sub.Value = "OD 4-8";
            ApplyHeaderStyle(cellP_sub, 3);

            var cellQ_sub = worksheet.Cell(rowIndex, currentCol++);
            cellQ_sub.Value = "OD After";
            ApplyHeaderStyle(cellQ_sub, 3);

            var cellR_sub = worksheet.Cell(rowIndex, currentCol++);
            cellR_sub.Value = "RD < 4";
            ApplyHeaderStyle(cellR_sub, 3);

            var cellS_sub = worksheet.Cell(rowIndex, currentCol++);
            cellS_sub.Value = "RD 4-8";
            ApplyHeaderStyle(cellS_sub, 3);

            var cellT_sub = worksheet.Cell(rowIndex, currentCol++);
            cellT_sub.Value = "RD After";
            ApplyHeaderStyle(cellT_sub, 3);

            var cellU_sub = worksheet.Cell(rowIndex, currentCol++);
            cellU_sub.Value = "PH < 8";
            ApplyHeaderStyle(cellU_sub, 3);

            var cellV_sub = worksheet.Cell(rowIndex, currentCol++);
            cellV_sub.Value = "PH After";
            ApplyHeaderStyle(cellV_sub, 3);

            currentCol += 7;

            var headerRow2Range = worksheet.Range(rowIndex, 1, rowIndex, worksheet.LastColumnUsed().ColumnNumber());
            headerRow2Range.Style.Border.SetOutsideBorder(XLBorderStyleValues.Thin);
            headerRow2Range.Style.Border.InsideBorder = XLBorderStyleValues.Thin;

            rowIndex++;
        }

        private void AddNonHoUNonPSTWAirHeaders(IXLWorksheet worksheet, ref int rowIndex)
        {
            int startRowIndex = rowIndex;
            int currentCol;

            currentCol = 1;
            var cellA = worksheet.Cell(rowIndex, currentCol);
            cellA.Value = "Basic Salary (RM)";
            ApplyHeaderStyle(cellA, 6);
            worksheet.Range(rowIndex, currentCol, rowIndex + 1, currentCol).Merge();
            currentCol++;

            var cellB = worksheet.Cell(rowIndex, currentCol);
            cellB.Value = "ORP";
            ApplyHeaderStyle(cellB, 6);
            worksheet.Range(rowIndex, currentCol, rowIndex + 1, currentCol).Merge();
            currentCol++;

            var cellC = worksheet.Cell(rowIndex, currentCol);
            cellC.Value = "HRP";
            ApplyHeaderStyle(cellC, 6);
            worksheet.Range(rowIndex, currentCol, rowIndex + 1, currentCol).Merge();
            currentCol++;

            var cellD = worksheet.Cell(rowIndex, currentCol);
            cellD.Value = "Day";
            ApplyHeaderStyle(cellD, 1);
            worksheet.Range(rowIndex, currentCol, rowIndex + 1, currentCol).Merge();
            currentCol++;

            var cellE = worksheet.Cell(rowIndex, currentCol);
            cellE.Value = "Date";
            ApplyHeaderStyle(cellE, 1);
            worksheet.Range(rowIndex, currentCol, rowIndex + 1, currentCol).Merge();
            currentCol++;

            var cellF = worksheet.Cell(rowIndex, currentCol);
            cellF.Value = "Office Hour";
            ApplyHeaderStyle(cellF, 2);
            var mergedRangeF = worksheet.Range(rowIndex, currentCol, rowIndex, currentCol + 2).Merge();
            mergedRangeF.Style.Border.SetOutsideBorder(XLBorderStyleValues.Thin);
            mergedRangeF.Style.Border.InsideBorder = XLBorderStyleValues.Thin;
            currentCol += 3;

            var cellI = worksheet.Cell(rowIndex, currentCol);
            cellI.Value = "After Office Hour";
            ApplyHeaderStyle(cellI, 2);
            var mergedRangeI = worksheet.Range(rowIndex, currentCol, rowIndex, currentCol + 2).Merge();
            mergedRangeI.Style.Border.SetOutsideBorder(XLBorderStyleValues.Thin);
            mergedRangeI.Style.Border.InsideBorder = XLBorderStyleValues.Thin;
            currentCol += 3;

            var cellL = worksheet.Cell(rowIndex, currentCol);
            cellL.Value = "OT Hrs (Office Hour)";
            ApplyHeaderStyle(cellL, 1);
            worksheet.Range(rowIndex, currentCol, rowIndex + 1, currentCol).Merge();
            currentCol++;

            var cellM = worksheet.Cell(rowIndex, currentCol);
            cellM.Value = "OT Hrs (After Office Hour)";
            ApplyHeaderStyle(cellM, 1);
            worksheet.Range(rowIndex, currentCol, rowIndex + 1, currentCol).Merge();
            currentCol++;

            var cellN = worksheet.Cell(rowIndex, currentCol);
            cellN.Value = "Normal Day (After Office)";
            ApplyHeaderStyle(cellN, 2);
            worksheet.Range(rowIndex, currentCol, rowIndex + 1, currentCol).Merge();
            currentCol++;

            var cellO = worksheet.Cell(rowIndex, currentCol);
            cellO.Value = "Off Day";
            ApplyHeaderStyle(cellO, 2);
            var mergedRangeO = worksheet.Range(rowIndex, currentCol, rowIndex, currentCol + 2).Merge();
            mergedRangeO.Style.Border.SetOutsideBorder(XLBorderStyleValues.Thin);
            mergedRangeO.Style.Border.InsideBorder = XLBorderStyleValues.Thin;
            currentCol += 3;

            var cellR = worksheet.Cell(rowIndex, currentCol);
            cellR.Value = "Rest Day";
            ApplyHeaderStyle(cellR, 2);
            var mergedRangeR = worksheet.Range(rowIndex, currentCol, rowIndex, currentCol + 2).Merge();
            mergedRangeR.Style.Border.SetOutsideBorder(XLBorderStyleValues.Thin);
            mergedRangeR.Style.Border.InsideBorder = XLBorderStyleValues.Thin;
            currentCol += 3;

            var cellU = worksheet.Cell(rowIndex, currentCol);
            cellU.Value = "Public Holiday";
            ApplyHeaderStyle(cellU, 2);
            var mergedRangeU = worksheet.Range(rowIndex, currentCol, rowIndex, currentCol + 1).Merge();
            mergedRangeU.Style.Border.SetOutsideBorder(XLBorderStyleValues.Thin);
            mergedRangeU.Style.Border.InsideBorder = XLBorderStyleValues.Thin;
            currentCol += 2;

            var cellW = worksheet.Cell(rowIndex, currentCol);
            cellW.Value = "Total OT";
            ApplyHeaderStyle(cellW, 1);
            worksheet.Range(rowIndex, currentCol, rowIndex + 1, currentCol).Merge();
            currentCol++;

            var cellX = worksheet.Cell(rowIndex, currentCol);
            cellX.Value = "Total ND & OD";
            ApplyHeaderStyle(cellX, 1);
            worksheet.Range(rowIndex, currentCol, rowIndex + 1, currentCol).Merge();
            currentCol++;

            var cellY = worksheet.Cell(rowIndex, currentCol);
            cellY.Value = "Total RD";
            ApplyHeaderStyle(cellY, 1);
            worksheet.Range(rowIndex, currentCol, rowIndex + 1, currentCol).Merge();
            currentCol++;

            var cellZ = worksheet.Cell(rowIndex, currentCol);
            cellZ.Value = "Total PH";
            ApplyHeaderStyle(cellZ, 1);
            worksheet.Range(rowIndex, currentCol, rowIndex + 1, currentCol).Merge();
            currentCol++;

            var cellAA = worksheet.Cell(rowIndex, currentCol);
            cellAA.Value = "OT Amt (RM)";
            ApplyHeaderStyle(cellAA, 6);
            worksheet.Range(rowIndex, currentCol, rowIndex + 1, currentCol).Merge();
            currentCol++;

            var cellAB = worksheet.Cell(rowIndex, currentCol);
            cellAB.Value = "Description";
            ApplyHeaderStyle(cellAB, 1);
            worksheet.Range(rowIndex, currentCol, rowIndex + 1, currentCol).Merge();
            currentCol++;

            var headerRow1Range = worksheet.Range(startRowIndex, 1, startRowIndex, worksheet.LastColumnUsed().ColumnNumber());
            headerRow1Range.Style.Border.SetOutsideBorder(XLBorderStyleValues.Thin);
            headerRow1Range.Style.Border.InsideBorder = XLBorderStyleValues.Thin;

            rowIndex++;

            currentCol = 1;
            currentCol += 5;

            var cellF_sub = worksheet.Cell(rowIndex, currentCol++);
            cellF_sub.Value = "From";
            ApplyHeaderStyle(cellF_sub, 3);

            var cellG_sub = worksheet.Cell(rowIndex, currentCol++);
            cellG_sub.Value = "To";
            ApplyHeaderStyle(cellG_sub, 3);

            var cellH_sub = worksheet.Cell(rowIndex, currentCol++);
            cellH_sub.Value = "Break";
            ApplyHeaderStyle(cellH_sub, 3);

            var cellI_sub = worksheet.Cell(rowIndex, currentCol++);
            cellI_sub.Value = "From";
            ApplyHeaderStyle(cellI_sub, 3);

            var cellJ_sub = worksheet.Cell(rowIndex, currentCol++);
            cellJ_sub.Value = "To";
            ApplyHeaderStyle(cellJ_sub, 3);

            var cellK_sub = worksheet.Cell(rowIndex, currentCol++);
            cellK_sub.Value = "Break";
            ApplyHeaderStyle(cellK_sub, 3);

            currentCol += 2;

            var cellN_sub = worksheet.Cell(rowIndex, currentCol++);
            cellN_sub.Value = "ND OT";
            ApplyHeaderStyle(cellN_sub, 3);

            var cellO_sub = worksheet.Cell(rowIndex, currentCol++);
            cellO_sub.Value = "OD < 4";
            ApplyHeaderStyle(cellO_sub, 3);

            var cellP_sub = worksheet.Cell(rowIndex, currentCol++);
            cellP_sub.Value = "OD 4-8";
            ApplyHeaderStyle(cellP_sub, 3);

            var cellQ_sub = worksheet.Cell(rowIndex, currentCol++);
            cellQ_sub.Value = "OD After";
            ApplyHeaderStyle(cellQ_sub, 3);

            var cellR_sub = worksheet.Cell(rowIndex, currentCol++);
            cellR_sub.Value = "RD < 4";
            ApplyHeaderStyle(cellR_sub, 3);

            var cellS_sub = worksheet.Cell(rowIndex, currentCol++);
            cellS_sub.Value = "RD 4-8";
            ApplyHeaderStyle(cellS_sub, 3);

            var cellT_sub = worksheet.Cell(rowIndex, currentCol++);
            cellT_sub.Value = "RD After";
            ApplyHeaderStyle(cellT_sub, 3);

            var cellU_sub = worksheet.Cell(rowIndex, currentCol++);
            cellU_sub.Value = "PH < 8";
            ApplyHeaderStyle(cellU_sub, 3);

            var cellV_sub = worksheet.Cell(rowIndex, currentCol++);
            cellV_sub.Value = "PH After";
            ApplyHeaderStyle(cellV_sub, 3);

            currentCol += 6;

            var headerRow2Range = worksheet.Range(rowIndex, 1, rowIndex, worksheet.LastColumnUsed().ColumnNumber());
            headerRow2Range.Style.Border.SetOutsideBorder(XLBorderStyleValues.Thin);
            headerRow2Range.Style.Border.InsideBorder = XLBorderStyleValues.Thin;

            rowIndex++;
        }

        private void AddHoUPSTWAirHeaders(IXLWorksheet worksheet, ref int rowIndex)
        {
            int startRowIndex = rowIndex;
            int currentCol = 1;

            currentCol = 1;
            var cellA = worksheet.Cell(rowIndex, currentCol);
            cellA.Value = "Day";
            ApplyHeaderStyle(cellA, 1);
            worksheet.Range(rowIndex, currentCol, rowIndex + 1, currentCol).Merge();
            currentCol++;

            var cellB = worksheet.Cell(rowIndex, currentCol);
            cellB.Value = "Date";
            ApplyHeaderStyle(cellB, 1);
            worksheet.Range(rowIndex, currentCol, rowIndex + 1, currentCol).Merge();
            currentCol++;

            var cellC = worksheet.Cell(rowIndex, currentCol);
            cellC.Value = "Office Hour";
            ApplyHeaderStyle(cellC, 2);
            var mergedRangeC = worksheet.Range(rowIndex, currentCol, rowIndex, currentCol + 2).Merge();
            mergedRangeC.Style.Border.SetOutsideBorder(XLBorderStyleValues.Thin);
            mergedRangeC.Style.Border.InsideBorder = XLBorderStyleValues.Thin;
            currentCol += 3;

            var cellF = worksheet.Cell(rowIndex, currentCol);
            cellF.Value = "After Office Hour";
            ApplyHeaderStyle(cellF, 2);
            var mergedRangeF = worksheet.Range(rowIndex, currentCol, rowIndex, currentCol + 2).Merge();
            mergedRangeF.Style.Border.SetOutsideBorder(XLBorderStyleValues.Thin);
            mergedRangeF.Style.Border.InsideBorder = XLBorderStyleValues.Thin;
            currentCol += 3;

            var cellI = worksheet.Cell(rowIndex, currentCol);
            cellI.Value = "OT Hrs (Office Hour)";
            ApplyHeaderStyle(cellI, 1);
            worksheet.Range(rowIndex, currentCol, rowIndex + 1, currentCol).Merge();
            currentCol++;

            var cellJ = worksheet.Cell(rowIndex, currentCol);
            cellJ.Value = "OT Hrs (After Office Hour)";
            ApplyHeaderStyle(cellJ, 1);
            worksheet.Range(rowIndex, currentCol, rowIndex + 1, currentCol).Merge();
            currentCol++;

            var cellK = worksheet.Cell(rowIndex, currentCol);
            cellK.Value = "Normal Day (After Office)";
            ApplyHeaderStyle(cellK, 2);
            worksheet.Range(rowIndex, currentCol, rowIndex + 1, currentCol).Merge();
            currentCol++;

            var cellL = worksheet.Cell(rowIndex, currentCol);
            cellL.Value = "Off Day";
            ApplyHeaderStyle(cellL, 2);
            var mergedRangeL = worksheet.Range(rowIndex, currentCol, rowIndex, currentCol + 2).Merge();
            mergedRangeL.Style.Border.SetOutsideBorder(XLBorderStyleValues.Thin);
            mergedRangeL.Style.Border.InsideBorder = XLBorderStyleValues.Thin;
            currentCol += 3;

            var cellO = worksheet.Cell(rowIndex, currentCol);
            cellO.Value = "Rest Day";
            ApplyHeaderStyle(cellO, 2);
            var mergedRangeO = worksheet.Range(rowIndex, currentCol, rowIndex, currentCol + 2).Merge();
            mergedRangeO.Style.Border.SetOutsideBorder(XLBorderStyleValues.Thin);
            mergedRangeO.Style.Border.InsideBorder = XLBorderStyleValues.Thin;
            currentCol += 3;

            var cellR = worksheet.Cell(rowIndex, currentCol);
            cellR.Value = "Public Holiday";
            ApplyHeaderStyle(cellR, 2);
            var mergedRangeR = worksheet.Range(rowIndex, currentCol, rowIndex, currentCol + 1).Merge();
            mergedRangeR.Style.Border.SetOutsideBorder(XLBorderStyleValues.Thin);
            mergedRangeR.Style.Border.InsideBorder = XLBorderStyleValues.Thin;
            currentCol += 2;

            var cellT = worksheet.Cell(rowIndex, currentCol);
            cellT.Value = "Total OT";
            ApplyHeaderStyle(cellT, 1);
            worksheet.Range(rowIndex, currentCol, rowIndex + 1, currentCol).Merge();
            currentCol++;

            var cellU = worksheet.Cell(rowIndex, currentCol);
            cellU.Value = "Total ND & OD";
            ApplyHeaderStyle(cellU, 1);
            worksheet.Range(rowIndex, currentCol, rowIndex + 1, currentCol).Merge();
            currentCol++;

            var cellV = worksheet.Cell(rowIndex, currentCol);
            cellV.Value = "Total RD";
            ApplyHeaderStyle(cellV, 1);
            worksheet.Range(rowIndex, currentCol, rowIndex + 1, currentCol).Merge();
            currentCol++;

            var cellW = worksheet.Cell(rowIndex, currentCol);
            cellW.Value = "Total PH";
            ApplyHeaderStyle(cellW, 1);
            worksheet.Range(rowIndex, currentCol, rowIndex + 1, currentCol).Merge();
            currentCol++;

            var cellX = worksheet.Cell(rowIndex, currentCol);
            cellX.Value = "Station";
            ApplyHeaderStyle(cellX, 1);
            worksheet.Range(rowIndex, currentCol, rowIndex + 1, currentCol).Merge();
            currentCol++;

            var cellY = worksheet.Cell(rowIndex, currentCol);
            cellY.Value = "Description";
            ApplyHeaderStyle(cellY, 1);
            worksheet.Range(rowIndex, currentCol, rowIndex + 1, currentCol).Merge();
            currentCol++;

            var headerRow1Range = worksheet.Range(startRowIndex, 1, startRowIndex, worksheet.LastColumnUsed().ColumnNumber());
            headerRow1Range.Style.Border.SetOutsideBorder(XLBorderStyleValues.Thin);
            headerRow1Range.Style.Border.InsideBorder = XLBorderStyleValues.Thin;

            rowIndex++;

            currentCol = 1;
            currentCol += 2;

            var cellC_sub = worksheet.Cell(rowIndex, currentCol++);
            cellC_sub.Value = "From";
            ApplyHeaderStyle(cellC_sub, 3);

            var cellD_sub = worksheet.Cell(rowIndex, currentCol++);
            cellD_sub.Value = "To";
            ApplyHeaderStyle(cellD_sub, 3);

            var cellE_sub = worksheet.Cell(rowIndex, currentCol++);
            cellE_sub.Value = "Break";
            ApplyHeaderStyle(cellE_sub, 3);

            var cellF_sub = worksheet.Cell(rowIndex, currentCol++);
            cellF_sub.Value = "From";
            ApplyHeaderStyle(cellF_sub, 3);

            var cellG_sub = worksheet.Cell(rowIndex, currentCol++);
            cellG_sub.Value = "To";
            ApplyHeaderStyle(cellG_sub, 3);

            var cellH_sub = worksheet.Cell(rowIndex, currentCol++);
            cellH_sub.Value = "Break";
            ApplyHeaderStyle(cellH_sub, 3);

            currentCol += 2;

            var cellK_sub = worksheet.Cell(rowIndex, currentCol++);
            cellK_sub.Value = "ND OT";
            ApplyHeaderStyle(cellK_sub, 3);

            var cellL_sub = worksheet.Cell(rowIndex, currentCol++);
            cellL_sub.Value = "OD < 4";
            ApplyHeaderStyle(cellL_sub, 3);

            var cellM_sub = worksheet.Cell(rowIndex, currentCol++);
            cellM_sub.Value = "OD 4-8";
            ApplyHeaderStyle(cellM_sub, 3);

            var cellN_sub = worksheet.Cell(rowIndex, currentCol++);
            cellN_sub.Value = "OD After";
            ApplyHeaderStyle(cellN_sub, 3);

            var cellO_sub = worksheet.Cell(rowIndex, currentCol++);
            cellO_sub.Value = "RD < 4";
            ApplyHeaderStyle(cellO_sub, 3);

            var cellP_sub = worksheet.Cell(rowIndex, currentCol++);
            cellP_sub.Value = "RD 4-8";
            ApplyHeaderStyle(cellP_sub, 3);

            var cellQ_sub = worksheet.Cell(rowIndex, currentCol++);
            cellQ_sub.Value = "RD After";
            ApplyHeaderStyle(cellQ_sub, 3);

            var cellR_sub = worksheet.Cell(rowIndex, currentCol++);
            cellR_sub.Value = "PH < 8";
            ApplyHeaderStyle(cellR_sub, 3);

            var cellS_sub = worksheet.Cell(rowIndex, currentCol++);
            cellS_sub.Value = "PH After";
            ApplyHeaderStyle(cellS_sub, 3);

            currentCol += 5;

            var headerRow2Range = worksheet.Range(rowIndex, 1, rowIndex, worksheet.LastColumnUsed().ColumnNumber());
            headerRow2Range.Style.Border.SetOutsideBorder(XLBorderStyleValues.Thin);
            headerRow2Range.Style.Border.InsideBorder = XLBorderStyleValues.Thin;

            rowIndex++;
        }

        private void AddHoUNonPSTWAirHeaders(IXLWorksheet worksheet, ref int rowIndex)
        {
            int startRowIndex = rowIndex;
            int currentCol;

            currentCol = 1;
            var cellA = worksheet.Cell(rowIndex, currentCol);
            cellA.Value = "Day";
            ApplyHeaderStyle(cellA, 1);
            worksheet.Range(rowIndex, currentCol, rowIndex + 1, currentCol).Merge();
            currentCol++;

            var cellB = worksheet.Cell(rowIndex, currentCol);
            cellB.Value = "Date";
            ApplyHeaderStyle(cellB, 1);
            worksheet.Range(rowIndex, currentCol, rowIndex + 1, currentCol).Merge();
            currentCol++;

            var cellC = worksheet.Cell(rowIndex, currentCol);
            cellC.Value = "Office Hour";
            ApplyHeaderStyle(cellC, 2);
            var mergedRangeC = worksheet.Range(rowIndex, currentCol, rowIndex, currentCol + 2).Merge();
            mergedRangeC.Style.Border.SetOutsideBorder(XLBorderStyleValues.Thin);
            mergedRangeC.Style.Border.InsideBorder = XLBorderStyleValues.Thin;
            currentCol += 3;

            var cellF = worksheet.Cell(rowIndex, currentCol);
            cellF.Value = "After Office Hour";
            ApplyHeaderStyle(cellF, 2);
            var mergedRangeF = worksheet.Range(rowIndex, currentCol, rowIndex, currentCol + 2).Merge();
            mergedRangeF.Style.Border.SetOutsideBorder(XLBorderStyleValues.Thin);
            mergedRangeF.Style.Border.InsideBorder = XLBorderStyleValues.Thin;
            currentCol += 3;

            var cellI = worksheet.Cell(rowIndex, currentCol);
            cellI.Value = "OT Hrs (Office Hour)";
            ApplyHeaderStyle(cellI, 1);
            worksheet.Range(rowIndex, currentCol, rowIndex + 1, currentCol).Merge();
            currentCol++;

            var cellJ = worksheet.Cell(rowIndex, currentCol);
            cellJ.Value = "OT Hrs (After Office Hour)";
            ApplyHeaderStyle(cellJ, 1);
            worksheet.Range(rowIndex, currentCol, rowIndex + 1, currentCol).Merge();
            currentCol++;

            var cellK = worksheet.Cell(rowIndex, currentCol);
            cellK.Value = "Normal Day (After Office)";
            ApplyHeaderStyle(cellK, 2);
            worksheet.Range(rowIndex, currentCol, rowIndex + 1, currentCol).Merge();
            currentCol++;

            var cellL = worksheet.Cell(rowIndex, currentCol);
            cellL.Value = "Off Day";
            ApplyHeaderStyle(cellL, 2);
            var mergedRangeL = worksheet.Range(rowIndex, currentCol, rowIndex, currentCol + 2).Merge();
            mergedRangeL.Style.Border.SetOutsideBorder(XLBorderStyleValues.Thin);
            mergedRangeL.Style.Border.InsideBorder = XLBorderStyleValues.Thin;
            currentCol += 3;

            var cellO = worksheet.Cell(rowIndex, currentCol);
            cellO.Value = "Rest Day";
            ApplyHeaderStyle(cellO, 2);
            var mergedRangeO = worksheet.Range(rowIndex, currentCol, rowIndex, currentCol + 2).Merge();
            mergedRangeO.Style.Border.SetOutsideBorder(XLBorderStyleValues.Thin);
            mergedRangeO.Style.Border.InsideBorder = XLBorderStyleValues.Thin;
            currentCol += 3;

            var cellR = worksheet.Cell(rowIndex, currentCol);
            cellR.Value = "Public Holiday";
            ApplyHeaderStyle(cellR, 2);
            var mergedRangeR = worksheet.Range(rowIndex, currentCol, rowIndex, currentCol + 1).Merge();
            mergedRangeR.Style.Border.SetOutsideBorder(XLBorderStyleValues.Thin);
            mergedRangeR.Style.Border.InsideBorder = XLBorderStyleValues.Thin;
            currentCol += 2;

            var cellT = worksheet.Cell(rowIndex, currentCol);
            cellT.Value = "Total OT";
            ApplyHeaderStyle(cellT, 1);
            worksheet.Range(rowIndex, currentCol, rowIndex + 1, currentCol).Merge();
            currentCol++;

            var cellU = worksheet.Cell(rowIndex, currentCol);
            cellU.Value = "Total ND & OD";
            ApplyHeaderStyle(cellU, 1);
            worksheet.Range(rowIndex, currentCol, rowIndex + 1, currentCol).Merge();
            currentCol++;

            var cellV = worksheet.Cell(rowIndex, currentCol);
            cellV.Value = "Total RD";
            ApplyHeaderStyle(cellV, 1);
            worksheet.Range(rowIndex, currentCol, rowIndex + 1, currentCol).Merge();
            currentCol++;

            var cellW = worksheet.Cell(rowIndex, currentCol);
            cellW.Value = "Total PH";
            ApplyHeaderStyle(cellW, 1);
            worksheet.Range(rowIndex, currentCol, rowIndex + 1, currentCol).Merge();
            currentCol++;

            var cellX = worksheet.Cell(rowIndex, currentCol);
            cellX.Value = "Description";
            ApplyHeaderStyle(cellX, 1);
            worksheet.Range(rowIndex, currentCol, rowIndex + 1, currentCol).Merge();
            currentCol++;

            var headerRow1Range = worksheet.Range(startRowIndex, 1, startRowIndex, worksheet.LastColumnUsed().ColumnNumber());
            headerRow1Range.Style.Border.SetOutsideBorder(XLBorderStyleValues.Thin);
            headerRow1Range.Style.Border.InsideBorder = XLBorderStyleValues.Thin;

            rowIndex++;

            currentCol = 1;
            currentCol += 2;

            var cellC_sub = worksheet.Cell(rowIndex, currentCol++);
            cellC_sub.Value = "From";
            ApplyHeaderStyle(cellC_sub, 3);

            var cellD_sub = worksheet.Cell(rowIndex, currentCol++);
            cellD_sub.Value = "To";
            ApplyHeaderStyle(cellD_sub, 3);

            var cellE_sub = worksheet.Cell(rowIndex, currentCol++);
            cellE_sub.Value = "Break";
            ApplyHeaderStyle(cellE_sub, 3);

            var cellF_sub = worksheet.Cell(rowIndex, currentCol++);
            cellF_sub.Value = "From";
            ApplyHeaderStyle(cellF_sub, 3);

            var cellG_sub = worksheet.Cell(rowIndex, currentCol++);
            cellG_sub.Value = "To";
            ApplyHeaderStyle(cellG_sub, 3);

            var cellH_sub = worksheet.Cell(rowIndex, currentCol++);
            cellH_sub.Value = "Break";
            ApplyHeaderStyle(cellH_sub, 3);

            currentCol += 2;

            var cellK_sub = worksheet.Cell(rowIndex, currentCol++);
            cellK_sub.Value = "ND OT";
            ApplyHeaderStyle(cellK_sub, 3);

            var cellL_sub = worksheet.Cell(rowIndex, currentCol++);
            cellL_sub.Value = "OD < 4";
            ApplyHeaderStyle(cellL_sub, 3);

            var cellM_sub = worksheet.Cell(rowIndex, currentCol++);
            cellM_sub.Value = "OD 4-8";
            ApplyHeaderStyle(cellM_sub, 3);

            var cellN_sub = worksheet.Cell(rowIndex, currentCol++);
            cellN_sub.Value = "OD After";
            ApplyHeaderStyle(cellN_sub, 3);

            var cellO_sub = worksheet.Cell(rowIndex, currentCol++);
            cellO_sub.Value = "RD < 4";
            ApplyHeaderStyle(cellO_sub, 3);

            var cellP_sub = worksheet.Cell(rowIndex, currentCol++);
            cellP_sub.Value = "RD 4-8";
            ApplyHeaderStyle(cellP_sub, 3);

            var cellQ_sub = worksheet.Cell(rowIndex, currentCol++);
            cellQ_sub.Value = "RD After";
            ApplyHeaderStyle(cellQ_sub, 3);

            var cellR_sub = worksheet.Cell(rowIndex, currentCol++);
            cellR_sub.Value = "PH < 8";
            ApplyHeaderStyle(cellR_sub, 3);

            var cellS_sub = worksheet.Cell(rowIndex, currentCol++);
            cellS_sub.Value = "PH After";
            ApplyHeaderStyle(cellS_sub, 3);

            currentCol += 4;

            var headerRow2Range = worksheet.Range(rowIndex, 1, rowIndex, worksheet.LastColumnUsed().ColumnNumber());
            headerRow2Range.Style.Border.SetOutsideBorder(XLBorderStyleValues.Thin);
            headerRow2Range.Style.Border.InsideBorder = XLBorderStyleValues.Thin;

            rowIndex++;
        }

        private uint GetDayCellColorStyleIndex(DateTime date, int? weekendId, List<DateTime> publicHolidays)
        {
            if (publicHolidays.Contains(date.Date))
                return 18;

            DayOfWeek dayOfWeek = date.DayOfWeek;
            if ((weekendId == 1 && (dayOfWeek == DayOfWeek.Friday || dayOfWeek == DayOfWeek.Saturday)) ||
                (weekendId == 2 && (dayOfWeek == DayOfWeek.Saturday || dayOfWeek == DayOfWeek.Sunday)))
                return 19;

            return 11;
        }

        private bool IsAdmin(int userId)
        {
            var userRoles = _centralDbContext.UserRoles
                .Where(ur => ur.UserId == userId)
                .Join(_centralDbContext.Roles, ur => ur.RoleId, r => r.Id, (ur, r) => r.Name)
                .ToList();

            return userRoles.Any(role => role.Contains("SuperAdmin") || role.Contains("SystemAdmin"));
        }

        private List<DateTime> GetAllDatesInMonth(DateTime month)
        {
            return Enumerable.Range(1, DateTime.DaysInMonth(month.Year, month.Month))
                                 .Select(day => new DateTime(month.Year, month.Month, day))
                                 .ToList();
        }

        private string GetDayType(DateTime date, int? weekendId, List<DateTime> publicHolidays)
        {
            if (publicHolidays.Contains(date.Date))
            {
                return "Public Holiday";
            }

            DayOfWeek dayOfWeek = date.DayOfWeek;

            if ((weekendId == 1 && (dayOfWeek == DayOfWeek.Friday || dayOfWeek == DayOfWeek.Saturday)) ||
                (weekendId == 2 && (dayOfWeek == DayOfWeek.Saturday || dayOfWeek == DayOfWeek.Sunday)))
            {
                if ((weekendId == 1 && dayOfWeek == DayOfWeek.Friday) ||
                    (weekendId == 2 && dayOfWeek == DayOfWeek.Saturday))
                {
                    return "Off Day";
                }
                if ((weekendId == 1 && dayOfWeek == DayOfWeek.Saturday) ||
                    (weekendId == 2 && dayOfWeek == DayOfWeek.Sunday))
                {
                    return "Rest Day";
                }
            }

            return "Normal Day";
        }

        // ORP = Basic Salary / 26
        private decimal CalculateOrp(decimal basicSalary)
        {
            return basicSalary / 26m;
        }

        // HRP = ORP / 8
        private decimal CalculateHrp(decimal orp)
        {
            return orp / 8m;
        }

        private string FormatAsHourMinute(decimal? totalMinutes, bool isMinutes = false)
        {
            if (totalMinutes == null || totalMinutes == 0)
                return "";

            TimeSpan ts;
            if (isMinutes)
            {
                ts = TimeSpan.FromMinutes((double)totalMinutes.Value);
            }
            else
            {
                ts = TimeSpan.FromMinutes((double)(totalMinutes.Value * 60));
            }

            if (ts.TotalMinutes < 0)
            {
                return $"-{Math.Abs((int)ts.TotalHours)}:{Math.Abs(ts.Minutes):D2}";
            }

            int hours = (int)ts.TotalHours;
            int minutes = ts.Minutes;

            return $"{hours}:{minutes:D2}";
        }


        private decimal ConvertTimeToDecimal(string time)
        {
            if (string.IsNullOrEmpty(time)) return 0;

            var parts = time.Split(':');
            if (parts.Length != 2) return 0;

            if (int.TryParse(parts[0], out int hours) && int.TryParse(parts[1], out int minutes))
            {
                return hours + (minutes / 60m);
            }

            return 0;
        }

        private decimal CalculateTimeDifferenceInMinutes(TimeSpan? from, TimeSpan? to)
        {
            if (!from.HasValue || !to.HasValue) return 0;

            double fromTotalMinutes = from.Value.TotalMinutes;
            double toTotalMinutes = to.Value.TotalMinutes;

            double totalMinutes = toTotalMinutes - fromTotalMinutes;


            if (totalMinutes < 0)
            {
                totalMinutes += 24 * 60;
            }

            return (decimal)Math.Max(0, totalMinutes);
        }

        private string CalculateOfficeOtHours(OtRegisterModel record)
        {
            if (!record.OfficeFrom.HasValue || !record.OfficeTo.HasValue) return "";

            var duration = record.OfficeTo.Value - record.OfficeFrom.Value;
            var totalMinutes = duration.TotalMinutes - (record.OfficeBreak ?? 0);
            totalMinutes = Math.Max(0, totalMinutes);

            int hours = (int)(totalMinutes / 60);
            int minutes = (int)(totalMinutes % 60);

            return $"{hours}:{minutes:D2}";
        }

        private string CalculateAfterOfficeOtHours(OtRegisterModel record)
        {
            if (!record.AfterFrom.HasValue || !record.AfterTo.HasValue) return "";

            var duration = record.AfterTo.Value - record.AfterFrom.Value;
            var totalMinutes = duration.TotalMinutes - (record.AfterBreak ?? 0);
            totalMinutes = Math.Max(0, totalMinutes);

            int hours = (int)(totalMinutes / 60);
            int minutes = (int)(totalMinutes % 60);

            return $"{hours}:{minutes:D2}";
        }

        private Dictionary<string, string> ClassifyOt(OtRegisterModel record, decimal hrp, List<DateTime> publicHolidays, int? weekendId)
        {
            var officeRaw = CalculateOfficeOtHours(record);
            var afterRaw = CalculateAfterOfficeOtHours(record);

            var officeHrs = ConvertTimeToDecimal(officeRaw);
            var afterHrs = ConvertTimeToDecimal(afterRaw);

            var toFixedOrEmpty = (decimal num) => num > 0 ? num.ToString("N2") : "";

            var dayType = GetDayType(record.OtDate, weekendId, publicHolidays);

            var result = new Dictionary<string, string>
            {
                ["ndAfter"] = "",
                ["odUnder4"] = "",
                ["odBetween4And8"] = "",
                ["odAfter"] = "",
                ["rdUnder4"] = "",
                ["rdBetween4And8"] = "",
                ["rdAfter"] = "",
                ["phUnder8"] = "",
                ["phAfter"] = ""
            };

            switch (dayType)
            {
                case "Normal Day":
                    result["ndAfter"] = toFixedOrEmpty(afterHrs);
                    break;
                case "Off Day":
                    if (officeHrs > 0)
                    {
                        if (officeHrs <= 4) result["odUnder4"] = toFixedOrEmpty(officeHrs);
                        else if (officeHrs > 4 && officeHrs <= 8) result["odBetween4And8"] = toFixedOrEmpty(officeHrs);
                    }
                    result["odAfter"] = toFixedOrEmpty(afterHrs);
                    break;
                case "Rest Day":
                    if (officeHrs > 0)
                    {
                        if (officeHrs <= 4) result["rdUnder4"] = toFixedOrEmpty(officeHrs);
                        else if (officeHrs > 4 && officeHrs <= 8) result["rdBetween4And8"] = toFixedOrEmpty(officeHrs);
                    }
                    result["rdAfter"] = toFixedOrEmpty(afterHrs);
                    break;
                case "Public Holiday":
                    if (officeHrs > 0)
                    {
                        if (officeHrs <= 8) result["phUnder8"] = toFixedOrEmpty(officeHrs);
                    }
                    result["phAfter"] = toFixedOrEmpty(afterHrs);
                    break;
            }

            return result;
        }

        private string CalculateTotalOtHrs(OtRegisterModel record, decimal hrp, List<DateTime> publicHolidays, int? weekendId)
        {
            var classified = ClassifyOt(record, hrp, publicHolidays, weekendId);
            decimal total = 0;

            foreach (var value in classified.Values)
            {
                if (decimal.TryParse(value, out decimal num))
                {
                    total += num;
                }
            }

            return total > 0 ? total.ToString("N2") : "";
        }

        private string CalculateNdOdTotal(OtRegisterModel record, decimal hrp, List<DateTime> publicHolidays, int? weekendId)
        {
            var classified = ClassifyOt(record, hrp, publicHolidays, weekendId);

            var nd = decimal.TryParse(classified["ndAfter"], out decimal ndVal) ? ndVal : 0;
            var od1 = decimal.TryParse(classified["odUnder4"], out decimal od1Val) ? od1Val : 0;
            var od2 = decimal.TryParse(classified["odBetween4And8"], out decimal od2Val) ? od2Val : 0;
            var od3 = decimal.TryParse(classified["odAfter"], out decimal od3Val) ? od3Val : 0;

            var total = nd + od1 + od2 + od3;
            return total > 0 ? total.ToString("N2") : "";
        }

        private string CalculateRdTotal(OtRegisterModel record, decimal hrp, List<DateTime> publicHolidays, int? weekendId)
        {
            var classified = ClassifyOt(record, hrp, publicHolidays, weekendId);
            var total =
                (decimal.TryParse(classified["rdUnder4"], out decimal rd1) ? rd1 : 0) +
                (decimal.TryParse(classified["rdBetween4And8"], out decimal rd2) ? rd2 : 0) +
                (decimal.TryParse(classified["rdAfter"], out decimal rd3) ? rd3 : 0);

            return total > 0 ? total.ToString("N2") : "";
        }

        private string CalculatePhTotal(OtRegisterModel record, decimal hrp, List<DateTime> publicHolidays, int? weekendId)
        {
            var classified = ClassifyOt(record, hrp, publicHolidays, weekendId);
            var total =
                (decimal.TryParse(classified["phUnder8"], out decimal ph1) ? ph1 : 0) +
                (decimal.TryParse(classified["phAfter"], out decimal ph2) ? ph2 : 0);

            return total > 0 ? total.ToString("N2") : "";
        }

        private string CalculateOtAmount(OtRegisterModel record, decimal hrp, List<DateTime> publicHolidays, int? weekendId)
        {
            var orp = CalculateOrp(hrp * 208);
            var dayType = GetDayType(record.OtDate, weekendId, publicHolidays);

            var officeRaw = CalculateOfficeOtHours(record);
            var afterRaw = CalculateAfterOfficeOtHours(record);

            var officeHours = ConvertTimeToDecimal(officeRaw);
            var afterOfficeHours = ConvertTimeToDecimal(afterRaw);

            decimal amountOffice = 0;
            decimal amountAfter = 0;

            if (officeHours > 0)
            {
                if (dayType == "Off Day" || dayType == "Rest Day")
                {
                    if (officeHours <= 4)
                    {
                        amountOffice = 0.5m * orp;
                    }
                    else if (officeHours > 4 && officeHours <= 8)
                    {
                        amountOffice = 1 * orp;
                    }
                }
                else if (dayType == "Public Holiday")
                {
                    amountOffice = 2 * orp;
                }
            }

            if (afterOfficeHours > 0)
            {
                switch (dayType)
                {
                    case "Normal Day":
                    case "Off Day":
                        amountAfter = 1.5m * hrp * afterOfficeHours;
                        break;
                    case "Rest Day":
                        amountAfter = 2 * hrp * afterOfficeHours;
                        break;
                    case "Public Holiday":
                        amountAfter = 3 * hrp * afterOfficeHours;
                        break;
                }
            }

            var totalAmount = amountOffice + amountAfter;
            return totalAmount.ToString("N2");
        }
        private void AddRemarksSection(IXLWorksheet worksheet, ref int currentRow, DateTime displayMonth, int? weekendId, List<CalendarModel> publicHolidays)
        {

            int remarksStartColumn = 1;
            int remarksRow = currentRow + 1;

            var phColorCell = worksheet.Cell(remarksRow, remarksStartColumn);
            phColorCell.Value = " ";
            phColorCell.Style.Fill.BackgroundColor = XLColor.FromHtml("FFC0CB");
            phColorCell.Style.Border.SetOutsideBorder(XLBorderStyleValues.Thin);

            worksheet.Cell(remarksRow, remarksStartColumn + 1).Value = " Public Holiday";
            worksheet.Cell(remarksRow, remarksStartColumn + 1).Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Left;
            remarksRow++;

            var weekendColorCell = worksheet.Cell(remarksRow, remarksStartColumn);
            weekendColorCell.Value = " ";
            weekendColorCell.Style.Fill.BackgroundColor = XLColor.FromHtml("ADD8E6");
            weekendColorCell.Style.Border.SetOutsideBorder(XLBorderStyleValues.Thin);

            worksheet.Cell(remarksRow, remarksStartColumn + 1).Value = " Weekend";
            worksheet.Cell(remarksRow, remarksStartColumn + 1).Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Left;
            remarksRow++;

            remarksRow++;

            worksheet.Cell(remarksRow, remarksStartColumn).Value = $"Public Holidays in {displayMonth:MMMM yyyy}:";
            worksheet.Cell(remarksRow, remarksStartColumn).Style.Font.SetBold();
            remarksRow++;

            if (publicHolidays != null && publicHolidays.Any())
            {
                var monthHolidays = publicHolidays
                    .Where(h => h.HolidayDate.Year == displayMonth.Year && h.HolidayDate.Month == displayMonth.Month)
                    .OrderBy(h => h.HolidayDate.Day)
                    .ToList();

                if (monthHolidays.Any())
                {
                    foreach (var holiday in monthHolidays)
                    {
                        worksheet.Cell(remarksRow, remarksStartColumn).Value = $"- {holiday.HolidayDate:dd MMMM}: {holiday.HolidayName}";
                        worksheet.Cell(remarksRow, remarksStartColumn).Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Left;
                        remarksRow++;
                    }
                }
                else
                {
                    worksheet.Cell(remarksRow, remarksStartColumn).Value = "No public holidays recorded for this month.";
                    worksheet.Cell(remarksRow, remarksStartColumn).Style.Font.SetItalic();
                    remarksRow++;
                }
            }
            else
            {
                worksheet.Cell(remarksRow, remarksStartColumn).Value = "No public holiday data found.";
                worksheet.Cell(remarksRow, remarksStartColumn).Style.Font.SetItalic();
                remarksRow++;
            }

            currentRow = remarksRow;
        }

        private string GetWeekendDefinition(int? weekendId)
        {
            if (!weekendId.HasValue) return "N/A";

            switch (weekendId)
            {
                case 1: return "Friday & Saturday";
                case 2: return "Saturday & Sunday";
                default: return "Unknown";
            }
        }
    }
}