using QuestPDF.Fluent;
using QuestPDF.Helpers;
using QuestPDF.Infrastructure;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using PSTW_CentralSystem.Areas.OTcalculate.Models;
using PSTW_CentralSystem.Models;
using Microsoft.EntityFrameworkCore;
using PSTW_CentralSystem.DBContext;

namespace PSTW_CentralSystem.Areas.OTcalculate.Services
{
    public class OvertimePDF
    {
        private readonly CentralSystemContext _centralDbContext;

        public OvertimePDF(CentralSystemContext centralDbContext)
        {
            _centralDbContext = centralDbContext;
        }

        public MemoryStream GenerateOvertimeTablePdf(
                                List<OtRegisterModel> records,
                                UserModel user,
                                decimal userRate,
                                DateTime? selectedMonth = null,
                                byte[]? logoImage = null,
                                bool isRestrictedUser = false, 
                                string? flexiHour = null,
                                List<ApprovalSignatureData>? approvedSignatures = null)
        {
            bool isAdminUser = IsAdmin(user.Id);
            bool showStationColumn = user.departmentId == 2 || user.departmentId == 3 || isAdminUser;

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

            var allDatesInMonth = GetAllDatesInMonth(displayMonth);

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

            var publicHolidaysForUser = _centralDbContext.Holidays
                .Where(h => userSetting != null && h.StateId == userSetting.State.StateId && h.HolidayDate.Month == displayMonth.Month && h.HolidayDate.Year == displayMonth.Year)
                .OrderBy(h => h.HolidayDate)
                .ToList();

            records = records.OrderBy(r => r.OtDate).ToList();
            var stream = new MemoryStream();

            Document.Create(container =>
            {
                container.Page(page =>
                {
                    page.Size(PageSizes.A4.Landscape());
                    page.Margin(30);

                    page.Content().Column(column =>
                    {
                        column.Item().Row(row =>
                        {
                            row.RelativeItem(2).Column(col =>
                            {
                                if (logoImage != null)
                                {
                                    col.Item().PaddingBottom(10).Container().Height(25).Image(logoImage, ImageScaling.FitArea);
                                }

                                col.Item().PaddingBottom(2).Text(text =>
                                {
                                    text.Span("Name: ").SemiBold().FontSize(9);
                                    text.Span($"{user.FullName}  |").FontSize(9);

                                    text.Span("    Department: ").SemiBold().FontSize(9);
                                    text.Span($"{user.Department?.DepartmentName ?? "N/A"}  |").FontSize(9);

                                    if (!string.IsNullOrEmpty(flexiHour))
                                    {
                                        text.Span("    Flexi Hour: ").SemiBold().FontSize(9);
                                        text.Span($"{flexiHour}").FontSize(9);
                                    }
                                });
                            });

                            row.RelativeItem(1).AlignRight().Text($"Generated: {DateTime.Now:dd MMM yyyy HH:mm}")
                                .FontSize(9).FontColor(Colors.Grey.Medium);
                        });

                        column.Item().PaddingTop(3).Row(row =>
                        {
                            row.RelativeItem(2).Text($"Overtime Record: {displayMonth:MMMM yyyy}").FontSize(9).Italic();

                            row.RelativeItem(1).AlignRight().Column(legendCol =>
                            {
                                legendCol.Item().Element(e => e.ShowEntire().Row(subRow =>
                                {
                                    subRow.AutoItem().Text(text =>
                                    {
                                        text.Span("        ").BackgroundColor("#add8e6").FontSize(9);
                                        text.Span(" Weekend").FontSize(8).FontColor(Colors.Black);
                                    });
                                }));
                                legendCol.Item().Element(e => e.ShowEntire().Row(subRow =>
                                {
                                    subRow.AutoItem().Text(text =>
                                    {
                                        text.Span("        ").BackgroundColor("#ffc0cb").FontSize(9);
                                        text.Span(" Public Holiday").FontSize(8).FontColor(Colors.Black);
                                    });
                                }));
                            });
                        });


                        column.Item().PaddingVertical(10).LineHorizontal(0.5f).LineColor(Colors.Grey.Lighten2);

                        // Pass the new isRestrictedUser flag to ComposeTable
                        column.Item().Element(container => ComposeTable(container, records, user, userRate, showStationColumn, allDatesInMonth, isRestrictedUser, publicHolidaysForUser.Select(h => h.HolidayDate.Date).ToList()));

                        column.Item().PaddingTop(20).Element(container =>
                        {
                            container.ShowEntire().Row(row =>
                            {

                                row.RelativeItem().Element(e => e.ShowEntire().Column(approvalCol =>
                                {
                                    if (approvedSignatures != null && approvedSignatures.Any())
                                    {
                                        approvalCol.Item().Element(e => e.ShowEntire().Row(approvalsRow =>
                                        {
                                            approvalsRow.Spacing(20);

                                            foreach (var approval in approvedSignatures)
                                            {
                                                approvalsRow.RelativeItem().Element(e => e.ShowEntire().Column(individualApprovalColumn =>
                                                {
                                                    individualApprovalColumn.Item().Text("Approved by:").FontSize(9).SemiBold().AlignCenter();

                                                    individualApprovalColumn.Item().PaddingTop(1)
                                                        .Height(50)
                                                        .AlignCenter()
                                                        .AlignMiddle()
                                                        .Text(approval.ApproverName)
                                                        .FontSize(15)
                                                        .FontColor(Colors.Black)
                                                        .FontFamily("Brush Script MT");

                                                    individualApprovalColumn.Item().PaddingTop(1)
                                                        .Text(approval.ApproverName).FontSize(9).SemiBold().AlignCenter();

                                                    if (approval.ApprovedDate.HasValue)
                                                    {
                                                        individualApprovalColumn.Item().PaddingTop(2)
                                                            .Text(approval.ApprovedDate.Value.ToString("dd MMMM yyyy"))
                                                            .FontSize(8).AlignCenter();
                                                    }
                                                }));
                                            }
                                        }));
                                    }
                                }));

                                row.RelativeItem().Element(e => e.ShowEntire().Column(remarksCol =>
                                {
                                    remarksCol.Item().Element(e => e.ShowEntire().Row(remarksRow =>
                                    {
                                        remarksRow.RelativeItem(2).Element(e => e.ShowEntire().AlignRight().Column(holidayListCol =>
                                        {
                                            holidayListCol.Item().Text("Public Holidays:").FontSize(9).SemiBold();
                                            holidayListCol.Item().Table(table =>
                                            {
                                                table.ColumnsDefinition(columns =>
                                                {
                                                    columns.RelativeColumn(1);
                                                    columns.RelativeColumn(2);
                                                });

                                                table.Header(header =>
                                                {
                                                    header.Cell().Border(0.25f).Padding(2).Text("Date").FontSize(7).Bold().AlignCenter();
                                                    header.Cell().Border(0.25f).Padding(2).Text("Holiday Name").FontSize(7).Bold().AlignCenter();
                                                });

                                                if (publicHolidaysForUser.Any())
                                                {
                                                    foreach (var holiday in publicHolidaysForUser)
                                                    {
                                                        table.Cell().Border(0.25f).Padding(2).Text($"{holiday.HolidayDate:dd-MM-yyyy}").FontSize(7).AlignCenter();
                                                        table.Cell().Border(0.25f).Padding(2).Text(holiday.HolidayName).FontSize(7).AlignLeft();
                                                    }
                                                }
                                                else
                                                {
                                                    table.Cell().ColumnSpan(2).Border(0.25f).Padding(2)
                                                        .Text($"No public holidays found for {userSetting?.State?.StateName ?? "this state"} in {displayMonth:MMMM yyyy}.")
                                                        .FontSize(7).Italic().AlignCenter();
                                                }
                                            });
                                        }));
                                    }));
                                }));
                            });
                        });

                        if (approvedSignatures != null && approvedSignatures.Any())
                        {
                            column.Item().PaddingTop(20).AlignCenter().Text("This is an automatically generated document. No signature is required for validation.").FontSize(8).Italic().FontColor(Colors.Grey.Darken2);
                        }
                    });
                });
            }).GeneratePdf(stream);

            stream.Position = 0;
            return stream;
        }

        // Update the signature of ComposeTable to accept the new flag
        private void ComposeTable(IContainer container, List<OtRegisterModel> records, UserModel user, decimal userRate, bool showStationColumn, List<DateTime> allDatesInMonth, bool hideSalaryDetails, List<DateTime> publicHolidays)
        {
            var recordsGroupedByDate = records
              .GroupBy(r => r.OtDate.Date)
              .ToDictionary(g => g.Key, g => g.ToList());

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

            container.Table(table =>
            {
                table.ColumnsDefinition(columns =>
                {
                    // Conditionally add salary columns based on hideSalaryDetails
                    if (!hideSalaryDetails)
                    {
                        columns.RelativeColumn(0.25f); // Basic Salary
                        columns.RelativeColumn(0.2f);  // ORP
                        columns.RelativeColumn(0.2f);  // HRP
                    }
                    columns.RelativeColumn(0.2f);
                    columns.RelativeColumn(0.4f);
                    columns.RelativeColumn(0.2f);
                    columns.RelativeColumn(0.2f);
                    columns.RelativeColumn(0.2f);
                    columns.RelativeColumn(0.2f);
                    columns.RelativeColumn(0.2f);
                    columns.RelativeColumn(0.2f);
                    columns.RelativeColumn(0.25f);
                    columns.RelativeColumn(0.25f);
                    columns.RelativeColumn(0.2f);
                    columns.RelativeColumn(0.2f);
                    columns.RelativeColumn(0.2f);
                    columns.RelativeColumn(0.2f);
                    columns.RelativeColumn(0.2f);
                    columns.RelativeColumn(0.2f);
                    columns.RelativeColumn(0.2f);
                    columns.RelativeColumn(0.2f);
                    columns.RelativeColumn(0.2f);
                    columns.RelativeColumn(0.25f);
                    columns.RelativeColumn(0.3f);
                    columns.RelativeColumn(0.2f);
                    columns.RelativeColumn(0.2f);
                    if (!hideSalaryDetails) // Conditionally add Total Amt column
                    {
                        columns.RelativeColumn(0.25f);
                    }

                    if (showStationColumn)
                    {
                        columns.RelativeColumn(0.3f);
                    }

                    columns.RelativeColumn(0.7f);
                });

                table.Header(header =>
                {
                    // Conditionally add salary headers based on hideSalaryDetails
                    if (!hideSalaryDetails)
                    {
                        header.Cell().RowSpan(2).Background("#fce5cd").Border(0.25f).Padding(3).Text("Basic Salary\n(RM)").FontSize(6).Bold().AlignCenter();
                        header.Cell().RowSpan(2).Background("#fce5cd").Border(0.25f).Padding(3).Text("ORP").FontSize(6).Bold().AlignCenter();
                        header.Cell().RowSpan(2).Background("#fce5cd").Border(0.25f).Padding(3).Text("HRP").FontSize(6).Bold().AlignCenter();
                    }
                    header.Cell().RowSpan(2).Background("#e0f7da").Border(0.25f).Padding(3).Text("Day").FontSize(6).Bold().AlignCenter();
                    header.Cell().RowSpan(2).Background("#d0ead2").Border(0.25f).Padding(3).Text("Date").FontSize(6).Bold().AlignCenter();

                    header.Cell().ColumnSpan(3).Background("#dceefb").Border(0.25f).Padding(3).Text("Office Hours").FontSize(6).Bold().AlignCenter();
                    header.Cell().ColumnSpan(3).Background("#edf2f7").Border(0.25f).Padding(3).Text("After Office Hours").FontSize(6).Bold().AlignCenter();

                    header.Cell().RowSpan(2).Background("#fdebd0").Border(0.25f).Padding(3).Text("OT Hrs\n(Office Hour)").FontSize(6).Bold().AlignCenter();
                    header.Cell().RowSpan(2).Background("#fdebd0").Border(0.25f).Padding(3).Text("OT Hrs\n(After Office Hour)").FontSize(6).Bold().AlignCenter();

                    header.Cell().ColumnSpan(1).Background("#deebf7").Border(0.25f).Padding(3).Text("Normal Day").FontSize(5).Bold().AlignCenter();
                    header.Cell().ColumnSpan(3).Background("#deebf7").Border(0.25f).Padding(3).Text("Off Day").FontSize(5).Bold().AlignCenter();
                    header.Cell().ColumnSpan(3).Background("#deebf7").Border(0.25f).Padding(3).Text("Rest Day").FontSize(5).Bold().AlignCenter();
                    header.Cell().ColumnSpan(2).Background("#deebf7").Border(0.25f).Padding(3).Text("Public Holiday").FontSize(5).Bold().AlignCenter();

                    header.Cell().RowSpan(2).Background("#fdebd0").Border(0.25f).Padding(3).Text("Total OT").FontSize(6).Bold().AlignCenter();
                    header.Cell().RowSpan(2).Background("#fdebd0").Border(0.25f).Padding(3).Text("Total\nND & OD").FontSize(6).Bold().AlignCenter();
                    header.Cell().RowSpan(2).Background("#fdebd0").Border(0.25f).Padding(3).Text("Total\nRD").FontSize(6).Bold().AlignCenter();
                    header.Cell().RowSpan(2).Background("#fdebd0").Border(0.25f).Padding(3).Text("Total\nPH").FontSize(6).Bold().AlignCenter();

                    if (!hideSalaryDetails) // Conditionally add Total Amt header
                    {
                        header.Cell().RowSpan(2).Background("#fce5cd").Border(0.25f).Padding(3).Text("OT Amt\n(RM)").FontSize(6).Bold().AlignCenter();
                    }

                    if (showStationColumn)
                    {
                        header.Cell().RowSpan(2).Background("#d0f0ef").Border(0.25f).Padding(3).Text("Station").FontSize(6).Bold().AlignCenter();
                    }

                    header.Cell().RowSpan(2).Background("#e3f2fd").Border(0.25f).Padding(3).Text("Description").FontSize(6).Bold().AlignCenter();

                    header.Cell().Background("#dceefb").Border(0.25f).Padding(3).Text("From").FontSize(5).Bold().AlignCenter();
                    header.Cell().Background("#dceefb").Border(0.25f).Padding(3).Text("To").FontSize(5).Bold().AlignCenter();
                    header.Cell().Background("#dceefb").Border(0.25f).Padding(3).Text("Break\n(min)").FontSize(5).Bold().AlignCenter();

                    header.Cell().Background("#edf2f7").Border(0.25f).Padding(3).Text("From").FontSize(5).Bold().AlignCenter();
                    header.Cell().Background("#edf2f7").Border(0.25f).Padding(3).Text("To").FontSize(5).Bold().AlignCenter();
                    header.Cell().Background("#edf2f7").Border(0.25f).Padding(3).Text("Break\n(min)").FontSize(5).Bold().AlignCenter();

                    header.Cell().Background("#deebf7").Border(0.25f).Padding(3).Text("ND OT").FontSize(5).Bold().AlignCenter();
                    header.Cell().Background("#deebf7").Border(0.25f).Padding(3).Text("OD < 4").FontSize(5).Bold().AlignCenter();
                    header.Cell().Background("#deebf7").Border(0.25f).Padding(3).Text("OD 4-8").FontSize(5).Bold().AlignCenter();
                    header.Cell().Background("#deebf7").Border(0.25f).Padding(3).Text("OD After").FontSize(5).Bold().AlignCenter();
                    header.Cell().Background("#deebf7").Border(0.25f).Padding(3).Text("RD < 4").FontSize(5).Bold().AlignCenter();
                    header.Cell().Background("#deebf7").Border(0.25f).Padding(3).Text("RD 4-8").FontSize(5).Bold().AlignCenter();
                    header.Cell().Background("#deebf7").Border(0.25f).Padding(3).Text("RD After").FontSize(5).Bold().AlignCenter();
                    header.Cell().Background("#deebf7").Border(0.25f).Padding(3).Text("PH < 8").FontSize(5).Bold().AlignCenter();
                    header.Cell().Background("#deebf7").Border(0.25f).Padding(3).Text("PH After").FontSize(5).Bold().AlignCenter();
                });


                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;


                bool alternate = false;

                var basicSalary = userRate; // userRate is now treated as basic salary
                var orp = basicSalary / 26m; // Calculate ORP from basicSalary
                var hrp = orp / 8m;          // Calculate HRP from ORP


                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)
                    {
                        var dayType = GetDayType(date, userSetting?.State?.WeekendId, publicHolidays);
                        var backgroundColor = GetDayCellBackgroundColor(date, userSetting?.State?.WeekendId, publicHolidays);

                        var classified = ClassifyOt(record, hrp, publicHolidays, userSetting?.State?.WeekendId);
                        var totalOt = CalculateTotalOtHrs(record, hrp, publicHolidays, userSetting?.State?.WeekendId);
                        var totalNdOd = CalculateNdOdTotal(record, hrp, publicHolidays, userSetting?.State?.WeekendId);
                        var totalRd = CalculateRdTotal(record, hrp, publicHolidays, userSetting?.State?.WeekendId);
                        var totalPh = CalculatePhTotal(record, hrp, publicHolidays, userSetting?.State?.WeekendId);
                        var otAmt = CalculateOtAmount(record, hrp, publicHolidays, userSetting?.State?.WeekendId);

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

                        totalNdOt += decimal.TryParse(classified["ndAfter"], out decimal ndOtVal) ? ndOtVal : 0;
                        totalOdUnder4 += decimal.TryParse(classified["odUnder4"], out decimal odUnder4Val) ? odUnder4Val : 0;
                        totalOd4to8 += decimal.TryParse(classified["odBetween4And8"], out decimal od4to8Val) ? od4to8Val : 0;
                        totalOdAfter += decimal.TryParse(classified["odAfter"], out decimal odAfterVal) ? odAfterVal : 0;
                        totalRdUnder4 += decimal.TryParse(classified["rdUnder4"], out decimal rdUnder4Val) ? rdUnder4Val : 0;
                        totalRd4to8 += decimal.TryParse(classified["rdBetween4And8"], out decimal rd4to8Val) ? rd4to8Val : 0;
                        totalRdAfter += decimal.TryParse(classified["rdAfter"], out decimal rdAfterVal) ? rdAfterVal : 0;
                        totalPhUnder8 += decimal.TryParse(classified["phUnder8"], out decimal phUnder8Val) ? phUnder8Val : 0;
                        totalPhAfter += decimal.TryParse(classified["phAfter"], out decimal phAfterVal) ? phAfterVal : 0;

                        grandTotalOt += decimal.TryParse(totalOt, out decimal totalOtVal) ? totalOtVal : 0;
                        grandTotalNdOd += decimal.TryParse(totalNdOd, out decimal totalNdOdVal) ? totalNdOdVal : 0;
                        grandTotalRd += decimal.TryParse(totalRd, out decimal totalRdVal) ? totalRdVal : 0;
                        grandTotalPh += decimal.TryParse(totalPh, out decimal totalPhVal) ? totalPhVal : 0;
                        grandTotalOtAmount += decimal.TryParse(otAmt, out decimal otAmtVal) ? otAmtVal : 0;


                        string rowBg = alternate ? "#f9f9f9" : "#ffffff";
                        if (dateRecords == null || !dateRecords.Any())
                            rowBg = alternate ? Colors.Grey.Lighten5 : Colors.White;


                        void AddCell(string value, bool center = true, string? bg = null)
                        {
                            var cell = table.Cell().Background(bg ?? rowBg).Border(0.25f).Padding(2);
                            var text = cell.Text(value).FontSize(6);
                            if (center) text.AlignCenter();
                        }

                        // Conditionally render salary details
                        if (!hideSalaryDetails)
                        {
                            // Display the calculated values here
                            AddCell(!hasPrintedSalaryDetails ? $"{basicSalary:F2}" : "");
                            AddCell(!hasPrintedSalaryDetails ? $"{orp:F2}" : "");
                            AddCell(!hasPrintedSalaryDetails ? $"{hrp:F2}" : "");
                        }
                        hasPrintedSalaryDetails = true;

                        if (date.Date != previousDate?.Date)
                        {
                            AddCell(date.ToString("ddd"), true, backgroundColor);
                            AddCell(date.ToString("dd-MM-yyyy"), true, backgroundColor);
                        }
                        else
                        {
                            AddCell("", true, backgroundColor);
                            AddCell("", true, backgroundColor);
                        }
                        previousDate = date;

                        AddCell(record.OfficeFrom?.ToString(@"hh\:mm") ?? "");
                        AddCell(record.OfficeTo?.ToString(@"hh\:mm") ?? "");
                        AddCell(FormatAsHourMinute(record.OfficeBreak, isMinutes: true));
                        AddCell(record.AfterFrom?.ToString(@"hh\:mm") ?? "");
                        AddCell(record.AfterTo?.ToString(@"hh\:mm") ?? "");
                        AddCell(FormatAsHourMinute(record.AfterBreak, isMinutes: true));
                        AddCell(CalculateOfficeOtHours(record));
                        AddCell(CalculateAfterOfficeOtHours(record));
                        AddCell(classified["ndAfter"]);
                        AddCell(classified["odUnder4"]);
                        AddCell(classified["odBetween4And8"]);
                        AddCell(classified["odAfter"]);
                        AddCell(classified["rdUnder4"]);
                        AddCell(classified["rdBetween4And8"]);
                        AddCell(classified["rdAfter"]);
                        AddCell(classified["phUnder8"]);
                        AddCell(classified["phAfter"]);
                        AddCell(totalOt);
                        AddCell(totalNdOd);
                        AddCell(totalRd);
                        AddCell(totalPh);
                        if (!hideSalaryDetails) // Conditionally render Total Amt column
                        {
                            AddCell(otAmt == "0.00" ? "" : otAmt);
                        }


                        if (showStationColumn)
                        {
                            AddCell(record.Stations?.StationName ?? "");
                        }

                        table.Cell().Background(rowBg).Border(0.25f).Padding(2)
                            .Text(record.OtDescription ?? "").FontSize(6).AlignLeft();

                        alternate = !alternate;
                    }
                }

                // Adjust column span for the TOTAL row based on visibility
                if (!hideSalaryDetails)
                {
                    table.Cell().ColumnSpan(5).Background("#d8d1f5").Border(0.80f).Padding(3)
                        .Text("TOTAL").Bold().FontSize(6).AlignCenter();
                }
                else
                {
                    table.Cell().ColumnSpan(2).Background("#d8d1f5").Border(0.80f).Padding(3)
                        .Text("TOTAL").Bold().FontSize(6).AlignCenter();
                }

                table.Cell().Background("#d8d1f5").Border(0.80f).Padding(3).Text("").FontSize(6).AlignCenter();
                table.Cell().Background("#d8d1f5").Border(0.80f).Padding(3).Text("").FontSize(6).AlignCenter();

                table.Cell().Background("#d8d1f5").Border(0.80f).Padding(3)
                    .Text(totalOfficeBreak == 0 ? "0.00" : FormatAsHourMinute(totalOfficeBreak, isMinutes: true))
                    .Bold().FontSize(6).AlignCenter();

                table.Cell().Background("#d8d1f5").Border(0.80f).Padding(3).Text("").FontSize(6).AlignCenter();
                table.Cell().Background("#d8d1f5").Border(0.80f).Padding(3).Text("").FontSize(6).AlignCenter();

                table.Cell().Background("#d8d1f5").Border(0.80f).Padding(3)
                    .Text(totalAfterBreak == 0 ? "0.00" : FormatAsHourMinute(totalAfterBreak, isMinutes: true))
                    .Bold().FontSize(6).AlignCenter();

                table.Cell().Background("#d8d1f5").Border(0.80f).Padding(3).Text("").FontSize(6).AlignCenter();
                table.Cell().Background("#d8d1f5").Border(0.80f).Padding(3).Text("").FontSize(6).AlignCenter();

                table.Cell().Background("#d8d1f5").Border(0.80f).Padding(3)
                    .Text($"{totalNdOt:N2}").Bold().FontSize(6).AlignCenter();

                table.Cell().Background("#d8d1f5").Border(0.80f).Padding(3)
                    .Text($"{totalOdUnder4:N2}").Bold().FontSize(6).AlignCenter();

                table.Cell().Background("#d8d1f5").Border(0.80f).Padding(3)
                    .Text($"{totalOd4to8:N2}").Bold().FontSize(6).AlignCenter();

                table.Cell().Background("#d8d1f5").Border(0.80f).Padding(3)
                    .Text($"{totalOdAfter:N2}").Bold().FontSize(6).AlignCenter();

                table.Cell().Background("#d8d1f5").Border(0.80f).Padding(3)
                    .Text($"{totalRdUnder4:N2}").Bold().FontSize(6).AlignCenter();

                table.Cell().Background("#d8d1f5").Border(0.80f).Padding(3)
                    .Text($"{totalRd4to8:N2}").Bold().FontSize(6).AlignCenter();

                table.Cell().Background("#d8d1f5").Border(0.80f).Padding(3)
                    .Text($"{totalRdAfter:N2}").Bold().FontSize(6).AlignCenter();

                table.Cell().Background("#d8d1f5").Border(0.80f).Padding(3)
                    .Text($"{totalPhUnder8:N2}").Bold().FontSize(6).AlignCenter();

                table.Cell().Background("#d8d1f5").Border(0.80f).Padding(3)
                    .Text($"{totalPhAfter:N2}").Bold().FontSize(6).AlignCenter();

                table.Cell().Background("#d8d1f5").Border(0.80f).Padding(3)
                    .Text($"{grandTotalOt:N2}").Bold().FontSize(6).AlignCenter();

                table.Cell().Background("#d8d1f5").Border(0.80f).Padding(3)
                    .Text($"{grandTotalNdOd:N2}").Bold().FontSize(6).AlignCenter();

                table.Cell().Background("#d8d1f5").Border(0.80f).Padding(3)
                    .Text($"{grandTotalRd:N2}").Bold().FontSize(6).AlignCenter();

                table.Cell().Background("#d8d1f5").Border(0.80f).Padding(3)
                    .Text($"{grandTotalPh:N2}").Bold().FontSize(6).AlignCenter();

                if (!hideSalaryDetails) // Conditionally render Total Amt in footer
                {
                    table.Cell().Background("#d8d1f5").Border(0.80f).Padding(3)
                        .Text($"{Math.Round(grandTotalOtAmount, MidpointRounding.AwayFromZero):F2}").Bold().FontSize(6).AlignCenter();
                }

                if (showStationColumn)
                {
                    table.Cell().Background("#d8d1f5").Border(0.80f).Padding(3).Text("").FontSize(6).AlignCenter();
                }
                table.Cell().Background("#d8d1f5").Border(0.80f).Padding(3).Text("").FontSize(6).AlignCenter();
            });
        }

        public MemoryStream GenerateSimpleOvertimeTablePdf(
                                List<OtRegisterModel> records,
                                UserModel user,
                                decimal userRate,
                                DateTime? selectedMonth = null,
                                byte[]? logoImage = null,
                                string? flexiHour = null)
        {
            bool isAdminUser = IsAdmin(user.Id);
            bool showStationColumn = user.departmentId == 2 || user.departmentId == 3 || isAdminUser;

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

            var allDatesInMonth = GetAllDatesInMonth(displayMonth);

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

            var publicHolidaysForUser = _centralDbContext.Holidays
                .Where(h => userSetting != null && h.StateId == userSetting.State.StateId && h.HolidayDate.Month == displayMonth.Month && h.HolidayDate.Year == displayMonth.Year)
                .OrderBy(h => h.HolidayDate)
                .ToList();

            records = records.OrderBy(r => r.OtDate).ToList();
            var stream = new MemoryStream();

            Document.Create(container =>
            {
                container.Page(page =>
                {
                    page.Size(PageSizes.A4.Landscape());
                    page.Margin(30);

                    page.Content().Column(column =>
                    {
                        column.Item().Row(row =>
                        {
                            row.RelativeItem(2).Column(col =>
                            {
                                if (logoImage != null)
                                {
                                    col.Item().PaddingBottom(10).Container().Height(25).Image(logoImage, ImageScaling.FitArea);
                                }

                                col.Item().PaddingBottom(2).Text(text =>
                                {
                                    text.Span("Name: ").SemiBold().FontSize(9);
                                    text.Span($"{user.FullName}  |").FontSize(9);

                                    text.Span("    Department: ").SemiBold().FontSize(9);
                                    text.Span($"{user.Department?.DepartmentName ?? "N/A"}  |").FontSize(9);

                                    if (!string.IsNullOrEmpty(flexiHour))
                                    {
                                        text.Span("    Flexi Hour: ").SemiBold().FontSize(9);
                                        text.Span($"{flexiHour}").FontSize(9);
                                    }
                                });
                            });

                            row.RelativeItem(1).AlignRight().Text($"Generated: {DateTime.Now:dd MMM yyyy HH:mm}")
                                .FontSize(9).FontColor(Colors.Grey.Medium);
                        });

                        column.Item().PaddingTop(3).Row(row =>
                        {
                            row.RelativeItem(2).Text($"Overtime Record: {displayMonth:MMMM yyyy}").SemiBold().FontSize(9).Italic();

                            row.RelativeItem(1).AlignRight().Column(legendCol =>
                            {
                                legendCol.Item().Element(e => e.ShowEntire().Row(subRow =>
                                {
                                    subRow.AutoItem().Text(text =>
                                    {
                                        text.Span("        ").BackgroundColor("#add8e6").FontSize(9);
                                        text.Span(" Weekend").FontSize(8).FontColor(Colors.Black);
                                    });
                                }));
                                legendCol.Item().Element(e => e.ShowEntire().Row(subRow =>
                                {
                                    subRow.AutoItem().Text(text =>
                                    {
                                        text.Span("        ").BackgroundColor("#ffc0cb").FontSize(9);
                                        text.Span(" Public Holiday").FontSize(8).FontColor(Colors.Black);
                                    });
                                }));
                            });
                        });

                        column.Item().PaddingVertical(10).LineHorizontal(0.5f).LineColor(Colors.Grey.Lighten2);

                        column.Item().Element(container => ComposeSimpleTable(container, records, user, showStationColumn, allDatesInMonth, publicHolidaysForUser.Select(h => h.HolidayDate.Date).ToList()));

                        column.Item().PaddingTop(20).Element(container =>
                        {
                            container.ShowEntire().Row(row =>
                            {
                                row.RelativeItem().Column(legendCol =>
                                {

                                });

                                row.RelativeItem(2).AlignRight().Column(holidayListCol =>
                                {
                                    holidayListCol.Item().Element(e => e.ShowEntire().Text("Public Holidays:").FontSize(9).SemiBold());

                                    holidayListCol.Item().Table(table =>
                                    {
                                        table.ColumnsDefinition(columns =>
                                        {
                                            columns.RelativeColumn(1);
                                            columns.RelativeColumn(2);
                                        });

                                        table.Header(header =>
                                        {
                                            header.Cell().Border(0.25f).Padding(2).Text("Date").FontSize(7).Bold().AlignCenter();
                                            header.Cell().Border(0.25f).Padding(2).Text("Holiday Name").FontSize(7).Bold().AlignCenter();
                                        });

                                        if (publicHolidaysForUser.Any())
                                        {
                                            foreach (var holiday in publicHolidaysForUser)
                                            {
                                                table.Cell().Border(0.25f).Padding(2).Text($"{holiday.HolidayDate:dd-MM-yyyy}").FontSize(7).AlignCenter();
                                                table.Cell().Border(0.25f).Padding(2).Text(holiday.HolidayName).FontSize(7).AlignLeft();
                                            }
                                        }
                                        else
                                        {
                                            table.Cell().ColumnSpan(2).Border(0.25f).Padding(2)
                                                .Text($"No public holidays found for {userSetting?.State?.StateName ?? "this state"} in {displayMonth:MMMM yyyy}.")
                                                .FontSize(7).Italic().AlignCenter();
                                        }
                                    });
                                });
                            });
                        });
                    });
                });
            }).GeneratePdf(stream);

            stream.Position = 0;
            return stream;
        }

        private void ComposeSimpleTable(IContainer container, List<OtRegisterModel> records, UserModel user, bool showStationColumn, List<DateTime> allDatesInMonth, List<DateTime> publicHolidays)
        {
            var recordsGroupedByDate = records
              .GroupBy(r => r.OtDate.Date)
              .ToDictionary(g => g.Key, g => g.ToList());

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

            container.Table(table =>
            {
                table.ColumnsDefinition(columns =>
                {
                    columns.RelativeColumn(0.8f); // Day (ddd)
                    columns.RelativeColumn(1);    // Date

                    // Office Hour group
                    columns.RelativeColumn(1);    // From
                    columns.RelativeColumn(1);    // To
                    columns.RelativeColumn(0.8f); // Break

                    // After Office Hour group
                    columns.RelativeColumn(1);    // From
                    columns.RelativeColumn(1);    // To
                    columns.RelativeColumn(0.8f); // Break

                    columns.RelativeColumn(1);    // Total OT Hours
                    columns.RelativeColumn(0.8f); // Break (min)

                    if (showStationColumn)
                    {
                        columns.RelativeColumn(1.5f); // Station
                    }

                    columns.RelativeColumn(2);    // Description
                });

                // Header
                table.Header(header =>
                {
                    header.Cell().RowSpan(2).Background("#d9ead3").Border(0.25f).Padding(3)
            .Text("Day").FontSize(6).Bold().AlignCenter();

                    header.Cell().RowSpan(2).Background("#d9ead3").Border(0.25f).Padding(3)
                        .Text("Date").FontSize(6).Bold().AlignCenter();

                    header.Cell().ColumnSpan(3).Background("#cfe2f3").Border(0.25f).Padding(3)
                        .Text("Office Hour").FontSize(6).Bold().AlignCenter();

                    header.Cell().ColumnSpan(3).Background("#cfe2f3").Border(0.25f).Padding(3)
                        .Text("After Office Hour").FontSize(6).Bold().AlignCenter();

                    header.Cell().RowSpan(2).Background("#fce5cd").Border(0.25f).Padding(3)
                        .Text("Total OT Hours").FontSize(6).Bold().AlignCenter();
                    header.Cell().RowSpan(2).Background("#fce5cd").Border(0.25f).Padding(3)
                        .Text("Break (min)").FontSize(6).Bold().AlignCenter();

                    if (showStationColumn)
                    {
                        header.Cell().RowSpan(2).Background("#d0f0ef").Border(0.25f).Padding(3)
                            .Text("Station").FontSize(6).Bold().AlignCenter();
                    }

                    header.Cell().RowSpan(2).Background("#e3f2fd").Border(0.25f).Padding(3)
                        .Text("Description").FontSize(6).Bold().AlignCenter();

                    // Second row of the header (sub-headers)
                    header.Cell().Background("#cfe2f3").Border(0.25f).Padding(3)
            .Text("From").FontSize(6).Bold().AlignCenter();
                    header.Cell().Background("#cfe2f3").Border(0.25f).Padding(3)
                        .Text("To").FontSize(6).Bold().AlignCenter();
                    header.Cell().Background("#cfe2f3").Border(0.25f).Padding(3)
                        .Text("Break").FontSize(6).Bold().AlignCenter();

                    header.Cell().Background("#cfe2f3").Border(0.25f).Padding(3)
                        .Text("From").FontSize(6).Bold().AlignCenter();
                    header.Cell().Background("#cfe2f3").Border(0.25f).Padding(3)
                        .Text("To").FontSize(6).Bold().AlignCenter();
                    header.Cell().Background("#cfe2f3").Border(0.25f).Padding(3)
                        .Text("Break").FontSize(6).Bold().AlignCenter();
                });

                decimal totalHours = 0;
                decimal totalBreak = 0;
                bool alternate = 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)
                    {
                        var backgroundColor = GetDayCellBackgroundColor(date, userSetting?.State?.WeekendId, publicHolidays);

                        string rowBg = alternate ? "#f9f9f9" : "#ffffff";
                        if (dateRecords == null || !dateRecords.Any())
                            rowBg = alternate ? Colors.Grey.Lighten5 : Colors.White;

                        void AddCell(string value, bool center = true, string? bg = null)
                        {
                            var cell = table.Cell().Background(bg ?? rowBg).Border(0.25f).Padding(2);
                            var text = cell.Text(value).FontSize(6);
                            if (center) text.AlignCenter();
                        }

                        if (date.Date != previousDate?.Date)
                        {
                            AddCell(date.ToString("ddd"), true, backgroundColor);
                            AddCell(date.ToString("dd-MM-yyyy"), true, backgroundColor);
                        }
                        else
                        {
                            AddCell("", true, backgroundColor);
                            AddCell("", true, backgroundColor);
                        }
                        previousDate = date;

                        var officeHours = CalculateOfficeOtHours(record);
                        var afterHours = CalculateAfterOfficeOtHours(record);
                        var totalTime = ConvertTimeToDecimal(officeHours) + ConvertTimeToDecimal(afterHours);
                        var breakTime = (record.OfficeBreak ?? 0) + (record.AfterBreak ?? 0);

                        totalHours += totalTime;
                        totalBreak += breakTime;

                        // Office Hour
                        AddCell(record.OfficeFrom?.ToString(@"hh\:mm") ?? "");
                        AddCell(record.OfficeTo?.ToString(@"hh\:mm") ?? "");
                        AddCell(FormatAsHourMinute(record.OfficeBreak, isMinutes: true));

                        // After Office Hour
                        AddCell(record.AfterFrom?.ToString(@"hh\:mm") ?? "");
                        AddCell(record.AfterTo?.ToString(@"hh\:mm") ?? "");
                        AddCell(FormatAsHourMinute(record.AfterBreak, isMinutes: true));

                        // Totals
                        AddCell(FormatAsHourMinute(totalTime, isMinutes: false));
                        AddCell(FormatAsHourMinute(breakTime, isMinutes: true));

                        // Station
                        if (showStationColumn)
                        {
                            AddCell(record.Stations?.StationName ?? "");
                        }

                        // Description
                        table.Cell().Background(rowBg).Border(0.25f).Padding(2)
                            .Text(record.OtDescription ?? "").FontSize(6).AlignLeft();

                        alternate = !alternate;
                    }
                }

                // Footer with totals
                table.Footer(footer =>
                {
                    // TOTAL
                    footer.Cell().ColumnSpan(2).Background("#d8d1f5").Border(0.80f).Padding(3)
            .Text("TOTAL").Bold().FontSize(6).AlignCenter();

                    footer.Cell().ColumnSpan(6).Background("#d8d1f5").Border(0.80f).Padding(3).Text("").FontSize(6).AlignCenter();

                    footer.Cell().Background("#d8d1f5").Border(0.80f).Padding(3)
            .Text(FormatAsHourMinute(totalHours, isMinutes: false)).Bold().FontSize(6).AlignCenter();

                    footer.Cell().Background("#d8d1f5").Border(0.80f).Padding(3)
                        .Text(FormatAsHourMinute(totalBreak, isMinutes: true)).Bold().FontSize(6).AlignCenter();

                    if (showStationColumn)
                    {
                        footer.Cell().Background("#d8d1f5").Border(0.80f).Padding(3).Text("").FontSize(6).AlignCenter();
                    }

                    footer.Cell().Background("#d8d1f5").Border(0.80f).Padding(3).Text("").FontSize(6).AlignCenter();
                });
            });
        }
        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 string GetMonthYearString(List<OtRegisterModel> records)
        {
            if (records == null || !records.Any())
                return "No Records";

            var firstDate = records.First().OtDate;
            var lastDate = records.Last().OtDate;

            if (firstDate.Month == lastDate.Month && firstDate.Year == lastDate.Year)
                return firstDate.ToString("MMMM yyyy");

            return $"{firstDate:MMM yyyy} - {lastDate:MMM yyyy}";
        }

        private static IContainer CellStyle(IContainer container)
        {
            return container
              .Padding(5)
              .Border(1)
              .BorderColor(QuestPDF.Helpers.Colors.Grey.Lighten2)
              .AlignMiddle()
              .AlignLeft();
        }

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

            TimeSpan ts = isMinutes
                ? TimeSpan.FromMinutes((double)hoursOrMinutes.Value)
                : TimeSpan.FromHours((double)hoursOrMinutes.Value);

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

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

        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.Saturday) ||
                    (weekendId == 2 && dayOfWeek == DayOfWeek.Sunday))
            {
                return "Rest Day";
            }

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

            return "Normal Day";
        }

        private decimal CalculateOrp(decimal basicSalary)
        {
            return basicSalary / 26m;
        }

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

        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 string CalculateOfficeOtHours(OtRegisterModel record)
        {
            if (!record.OfficeFrom.HasValue || !record.OfficeTo.HasValue) return "";

            double fromMinutes = record.OfficeFrom.Value.TotalMinutes;
            double toMinutes = record.OfficeTo.Value.TotalMinutes;

            double totalMinutes = toMinutes - fromMinutes;

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

            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 "";

            double fromMinutes = record.AfterFrom.Value.TotalMinutes;
            double toMinutes = record.AfterTo.Value.TotalMinutes;

            double totalMinutes = toMinutes - fromMinutes;

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

            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) // Only process if there are office hours
                    {
                        if (officeHrs <= 4) // If total office hours are 4 or less
                        {
                            result["odUnder4"] = toFixedOrEmpty(officeHrs); // Assign all to 'under 4'
                        }
                        else if (officeHrs <= 8) // If total office hours are more than 4, but 8 or less
                        {
                            result["odBetween4And8"] = toFixedOrEmpty(officeHrs); // Assign all to '4-8'
                        }
                        else // If total office hours are more than 8
                        {
                            result["odAfter"] = toFixedOrEmpty(officeHrs); // Assign all to 'OD After' (for office hours beyond 8)
                        }
                    }

                    result["odAfter"] = toFixedOrEmpty(ConvertTimeToDecimal(result["odAfter"]) + afterHrs);
                    break;

                case "Rest Day":
                    if (officeHrs > 0) // Only process if there are office hours
                    {
                        if (officeHrs <= 4) // If total office hours are 4 or less
                        {
                            result["rdUnder4"] = toFixedOrEmpty(officeHrs); // Assign all to 'under 4'
                        }
                        else if (officeHrs <= 8) // If total office hours are more than 4, but 8 or less
                        {
                            result["rdBetween4And8"] = toFixedOrEmpty(officeHrs); // Assign all to '4-8'
                        }
                        else // If total office hours are more than 8
                        {
                            result["rdAfter"] = toFixedOrEmpty(officeHrs); // Assign all to 'RD After' (for office hours beyond 8)
                        }
                    }

                    result["rdAfter"] = toFixedOrEmpty(ConvertTimeToDecimal(result["rdAfter"]) + afterHrs);
                    break;

                case "Public Holiday":
                    if (officeHrs > 0) // Only process if there are office hours
                    {
                        if (officeHrs <= 8) // If total office hours are 8 or less
                        {
                            result["phUnder8"] = toFixedOrEmpty(officeHrs); // Assign all to 'under 8'
                        }
                        else
                        {
                            result["phAfter"] = toFixedOrEmpty(officeHrs); // Assign all to 'PH After' (for office hours beyond 8)
                        }
                    }

                    result["phAfter"] = toFixedOrEmpty(ConvertTimeToDecimal(result["phAfter"]) + 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)
        {
            decimal orp = hrp * 8m;

            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 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 GetDayCellBackgroundColor(DateTime date, int? weekendId, List<DateTime> publicHolidays)
        {
            if (publicHolidays.Contains(date.Date))
                return "#ffc0cb";

            var dayOfWeek = date.DayOfWeek;

            if ((weekendId == 1 && (dayOfWeek == DayOfWeek.Friday || dayOfWeek == DayOfWeek.Saturday)) ||
                (weekendId == 2 && (dayOfWeek == DayOfWeek.Saturday || dayOfWeek == DayOfWeek.Sunday)))
                return "#add8e6";

            return "#ffffff";
        }
    }
}