using Azure.Core;
using DocumentFormat.OpenXml.InkML;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
using Microsoft.VisualStudio.Web.CodeGenerators.Mvc.Templates.BlazorIdentity.Pages;
using Mono.TextTemplating;
using Newtonsoft.Json;
using PSTW_CentralSystem.Areas.OTcalculate.Models;
using PSTW_CentralSystem.Areas.OTcalculate.Services;
using PSTW_CentralSystem.Controllers.API;
using PSTW_CentralSystem.Controllers.API.Inventory;
using PSTW_CentralSystem.DBContext;
using PSTW_CentralSystem.Models;
using QuestPDF.Fluent;
using QuestPDF.Helpers;
using QuestPDF.Infrastructure;
using RestSharp.Extensions;
using System;
using System.ComponentModel.Design;
using System.Data;
using System.Diagnostics;
using System.Reflection;
using System.Security.Claims;
using System.Threading.Tasks;
using static PSTW_CentralSystem.Areas.OTcalculate.Models.OtRegisterModel;
using static System.Collections.Specialized.BitVector32;

  
namespace PSTW_CentralSystem.Controllers.API
{
    [ApiController]
    [Route("[controller]")]
    public class OvertimeAPI : Controller
    {
        private readonly ILogger<OvertimeAPI> _logger;
        private readonly CentralSystemContext _centralDbContext;
        private readonly UserManager<UserModel> _userManager;

        private readonly IWebHostEnvironment _env;


        public OvertimeAPI(ILogger<OvertimeAPI> logger, CentralSystemContext centralDbContext, UserManager<UserModel> userManager, IWebHostEnvironment env)
        {
            _logger = logger;
            _centralDbContext = centralDbContext;
            _userManager = userManager;
            _env = env;
        }

        #region Settings

        [HttpGet("GetUpdateDates")]
        public IActionResult GetUpdateDates()
        {
            try
            {
                var latestRateUpdate = _centralDbContext.Rates.OrderByDescending(r => r.LastUpdated).FirstOrDefault()?.LastUpdated;
                var latestCalendarUpdate = _centralDbContext.Holidays.OrderByDescending(c => c.LastUpdated).FirstOrDefault()?.LastUpdated;
                var latestFlexiHourUpdate = _centralDbContext.Hrusersetting.OrderByDescending(r => r.FlexiHourUpdate).FirstOrDefault()?.FlexiHourUpdate;
                var latestRegionUpdate = _centralDbContext.Hrusersetting.OrderByDescending(c => c.StateUpdate).FirstOrDefault()?.StateUpdate;
                var latestApprovalFlowUpdate = _centralDbContext.Hrusersetting.OrderByDescending(c => c.ApprovalUpdate).FirstOrDefault()?.ApprovalUpdate;

                var updateDates = new
                {
                    rateUpdateDate = latestRateUpdate.HasValue ? latestRateUpdate.Value.ToString("dd MMMM yyyy") : null,
                    calendarUpdateDate = latestCalendarUpdate.HasValue ? latestCalendarUpdate.Value.ToString("dd MMMM yyyy") : null,
                    flexiHourUpdateDate = latestFlexiHourUpdate.HasValue ? latestFlexiHourUpdate.Value.ToString("dd MMMM yyyy") : null,
                    regionUpdateDate = latestRegionUpdate.HasValue ? latestRegionUpdate.Value.ToString("dd MMMM yyyy") : null,
                    approvalFlowUpdateDate = latestApprovalFlowUpdate.HasValue ? latestApprovalFlowUpdate.Value.ToString("dd MMMM yyyy") : null
                };

                return Json(updateDates);
            }
            catch (Exception ex)
            {
                return BadRequest(ex.Message);
            }
        }

        [HttpGet("CheckIncompleteUserSettings")]
        public async Task<IActionResult> CheckIncompleteUserSettings()
        {
            try
            {
                var incompleteUserIds = new List<int>();

                var allUserIds = await _userManager.Users.Select(u => u.Id).ToListAsync();

                foreach (var userId in allUserIds)
                {
                    bool isIncomplete = false;

                    var hrUserSetting = await _centralDbContext.Hrusersetting
                                                    .Where(h => h.UserId == userId)
                                                    .FirstOrDefaultAsync();

                    if (hrUserSetting == null)
                    {
                        isIncomplete = true;
                    }
                    else
                    {
                        if (hrUserSetting.FlexiHourId == null || hrUserSetting.FlexiHourId == 0)
                        {
                            isIncomplete = true;
                        }
                        if (hrUserSetting.StateId == null || hrUserSetting.StateId == 0)
                        {
                            isIncomplete = true;
                        }
                        if (hrUserSetting.ApprovalFlowId == null || hrUserSetting.ApprovalFlowId == 0)
                        {
                            isIncomplete = true;
                        }
                    }

                    var rateSetting = await _centralDbContext.Rates
                                                .Where(r => r.UserId == userId)
                                                .FirstOrDefaultAsync();

                    if (rateSetting == null)
                    {
                        isIncomplete = true;
                    }
                    else
                    {
                        if (rateSetting.RateValue == 0.00m)
                        {
                            isIncomplete = true;
                        }
                    }

                    if (isIncomplete)
                    {
                        incompleteUserIds.Add(userId); 
                    }
                }

                if (incompleteUserIds.Any())
                {
                    return Ok(new { hasIncompleteSettings = true, numberOfIncompleteUsers = incompleteUserIds.Count });
                }
                else
                {
                    return Ok(new { hasIncompleteSettings = false, numberOfIncompleteUsers = 0 });
                }
            }
            catch (Exception ex)
            {
                return StatusCode(500, $"An error occurred: {ex.Message}");
            }
        }

        #endregion

        #region Rate
        [HttpPost("UpdateRates")]
        public async Task<IActionResult> UpdateRate([FromBody] List<RateModel> rates)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            try
            {
                foreach (var rate in rates)
                {
                    // Change from rate.RateValue < 0 to rate.RateValue < 1
                    if (rate.RateValue < 1)
                    {
                        return BadRequest("Salary cannot be less than 1."); // Update the error message
                    }

                    var existingRate = await _centralDbContext.Rates
                        .FirstOrDefaultAsync(r => r.UserId == rate.UserId);

                    if (existingRate != null)
                    {
                        existingRate.RateValue = rate.RateValue;
                        existingRate.LastUpdated = DateTime.Now;
                        _centralDbContext.Rates.Update(existingRate);
                    }
                    else
                    {
                        _centralDbContext.Rates.Add(new RateModel
                        {
                            UserId = rate.UserId,
                            RateValue = rate.RateValue,
                            LastUpdated = DateTime.Now
                        });
                    }
                }

                await _centralDbContext.SaveChangesAsync();

                var updatedRates = await _centralDbContext.Rates
                    .Include(r => r.Users)
                    .Select(r => new
                    {
                        r.RateId,
                        r.RateValue,
                        r.UserId,
                        FullName = r.Users.FullName,
                        DepartmentName = r.Users.Department.DepartmentName
                    })
                    .ToListAsync();

                return Json(updatedRates);
            }
            catch (Exception ex)
            {
                return BadRequest(ex.Message);
            }
        }

        [HttpPost("GetUserRates")]
        public async Task<IActionResult> GetUserRates()
        {
            try
            {
                var userRates = await _centralDbContext.Rates
                    .Include(rates => rates.Users)
                    .ThenInclude(user => user.Department)
                    .Select(rates => new
                    {
                        rates.RateId,
                        rates.RateValue,
                        rates.UserId,
                        rates.Users.FullName,
                        rates.Users.Department.DepartmentName
                    })
                    .ToListAsync();

                return Json(userRates);
            }
            catch (Exception ex)
            {
                return BadRequest(ex.Message);
            }
        }
        #endregion

        #region FlexiHour State Approval
        private async Task UpdateOrInsertUserSettingAsync(int userId, int? flexiHourId = null, int? stateId = null, int? approvalFlowId = null)
        {
            var setting = await _centralDbContext.Hrusersetting
                .FirstOrDefaultAsync(h => h.UserId == userId);

            if (setting != null)
            {
                if (flexiHourId.HasValue)
                {
                    setting.FlexiHourId = flexiHourId;
                    setting.FlexiHourUpdate = DateTime.Now;
                }

                if (stateId.HasValue)
                {
                    setting.StateId = stateId;
                    setting.StateUpdate = DateTime.Now;
                }

                if (approvalFlowId.HasValue)
                {
                    setting.ApprovalFlowId = approvalFlowId;
                    setting.ApprovalUpdate = DateTime.Now;
                }

                _centralDbContext.Hrusersetting.Update(setting);
            }
            else
            {
                var newSetting = new HrUserSettingModel
                {
                    UserId = userId,
                    FlexiHourId = flexiHourId,
                    FlexiHourUpdate = flexiHourId.HasValue ? DateTime.Now : null,
                    StateId = stateId,
                    StateUpdate = stateId.HasValue ? DateTime.Now : null,
                    ApprovalFlowId = approvalFlowId,
                    ApprovalUpdate = approvalFlowId.HasValue ? DateTime.Now : null
                };
                _centralDbContext.Hrusersetting.Add(newSetting);
            }
        }
        #endregion

        #region FlexiHour
        [HttpGet("GetFlexiHours")]
        public IActionResult GetAllFlexiHours()
        {
            var flexiHours = _centralDbContext.Flexihour
                .Select(f => new { f.FlexiHourId, f.FlexiHour })
                .ToList();
            return Ok(flexiHours);
        }

        [HttpGet("GetUserFlexiHours")]
        public async Task<IActionResult> GetUserFlexiHours()
        {
            try
            {
                var users = await _centralDbContext.Users
                    .Include(u => u.Department)
                    .ToListAsync();

                var hrUserSettings = await _centralDbContext.Hrusersetting
                    .Include(hr => hr.FlexiHour)
                    .ToListAsync();

                var result = users.Select(u => new
                {
                    UserId = u.Id,
                    FullName = u.FullName,
                    DepartmentName = u.Department != null ? u.Department.DepartmentName : "N/A",
                    FlexiHour = hrUserSettings
                        .Where(hr => hr.UserId == u.Id)
                        .Select(hr => hr.FlexiHour != null ? hr.FlexiHour.FlexiHour : "N/A")
                        .FirstOrDefault() ?? "N/A",
                    State = hrUserSettings
                        .Where(hr => hr.UserId == u.Id)
                        .Select(hr => hr.State != null ? hr.State.StateName : "N/A")
                        .FirstOrDefault() ?? "N/A"
                }).ToList();

                Console.WriteLine(JsonConvert.SerializeObject(result));  
                return Ok(result);


            }
            catch (Exception ex)
            {
                return BadRequest(new { message = ex.Message });
            }
        }


        [HttpPost("UpdateUserFlexiHours")]
        public async Task<IActionResult> UpdateUserFlexiHours([FromBody] List<HrUserSettingModel> updates)
        {
            if (!ModelState.IsValid)
                return BadRequest(ModelState);

            try
            {
                foreach (var update in updates)
                {
                    await UpdateOrInsertUserSettingAsync(update.UserId, flexiHourId: update.FlexiHourId);
                }

                await _centralDbContext.SaveChangesAsync();
                return Ok();
            }
            catch (Exception ex)
            {
                return BadRequest(new { message = ex.Message });
            }
        }

        #endregion

        #region State
        [HttpGet("GetUserStates")]
        public async Task<IActionResult> GetUserStates()
        {
            try
            {
                var users = await _centralDbContext.Users
                    .Include(u => u.Department)
                    .ToListAsync();

                var hrUserSettings = await _centralDbContext.Hrusersetting
                    .Include(h => h.State)
                    .Include(h => h.Approvalflow)
                    .ToListAsync();

                var result = users.Select(u =>
                {
                    var hrSetting = hrUserSettings.FirstOrDefault(h => h.UserId == u.Id);
                    return new
                    {
                        u.Id,
                        u.FullName,
                        DepartmentName = u.Department != null ? u.Department.DepartmentName : "N/A",
                        State = hrSetting != null && hrSetting.State != null ? hrSetting.State.StateName : "N/A",
                        approvalName = hrSetting?.Approvalflow?.ApprovalName ?? "N/A"
                    };
                }).ToList();

                return Ok(result);
            }
            catch (Exception ex)
            {
                return StatusCode(500, ex.Message);
            }
        }

        [HttpPost("UpdateUserStates")]
        public async Task<IActionResult> UpdateUserStates([FromBody] List<HrUserSettingModel> updates)
        {
            if (!ModelState.IsValid)
                return BadRequest(ModelState);

            try
            {
                foreach (var update in updates)
                {
                    var existingSetting = await _centralDbContext.Hrusersetting.FirstOrDefaultAsync(h => h.UserId == update.UserId);

                    if (existingSetting != null)
                    {
                        existingSetting.StateId = update.StateId;
                        existingSetting.StateUpdate = DateTime.Now; 
                    }
                    else
                    {
                        _centralDbContext.Hrusersetting.Add(new HrUserSettingModel
                        {
                            UserId = update.UserId,
                            StateId = update.StateId,
                            StateUpdate = DateTime.Now, 
                        });
                    }
                }

                await _centralDbContext.SaveChangesAsync();
                return Ok();
            }
            catch (Exception ex)
            {
                return BadRequest(new { message = ex.Message });
            }
        }

        [HttpPost("UpdateUserApprovalFlow")]
        public async Task<IActionResult> UpdateUserApprovalFlow([FromBody] List<HrUserSettingModel> updates)
        {
            if (!ModelState.IsValid)
                return BadRequest(ModelState);

            try
            {
                foreach (var update in updates)
                {
                    var existingSetting = await _centralDbContext.Hrusersetting.FirstOrDefaultAsync(h => h.UserId == update.UserId);

                    if (existingSetting != null)
                    {
                        existingSetting.ApprovalFlowId = update.ApprovalFlowId;
                        existingSetting.ApprovalUpdate = DateTime.Now;
                    }
                    else
                    {
                        _centralDbContext.Hrusersetting.Add(new HrUserSettingModel
                        {
                            UserId = update.UserId,
                            ApprovalFlowId = update.ApprovalFlowId,
                            ApprovalUpdate = DateTime.Now
                        });
                    }
                }

                await _centralDbContext.SaveChangesAsync();
                return Ok();
            }
            catch (Exception ex)
            {
                return BadRequest(new { message = ex.Message });
            }
        }

        [HttpPost("UpdateApprovalFlow")]
        public async Task<IActionResult> UpdateApprovalFlow([FromBody] ApprovalFlowModel model)
        {
            if (!ModelState.IsValid)
                return BadRequest("Invalid data");

            var existing = await _centralDbContext.Approvalflow.FindAsync(model.ApprovalFlowId);
            if (existing == null)
                return NotFound("Approval flow not found");

            existing.ApprovalName = model.ApprovalName;
            existing.HoU = model.HoU;
            existing.HoD = model.HoD;
            existing.Manager = model.Manager;
            existing.HR = model.HR;

            await _centralDbContext.SaveChangesAsync();
            return Ok();
        }

        [HttpGet("GetApprovalFlowList")]
        public async Task<IActionResult> GetApprovalFlowList()
        {
            try
            {
                var flows = await _centralDbContext.Approvalflow
                    .Select(af => new
                    {
                        af.ApprovalFlowId,
                        af.ApprovalName,
                        hou = af.HoU,
                        hod = af.HoD,
                        manager = af.Manager,
                        hr = af.HR
                    })
                    .ToListAsync();
                return Ok(flows);
            }
            catch (Exception ex)
            {
                return StatusCode(500, new { message = ex.Message });
            }
        }
        #endregion

        #region Approval Flow

        [HttpPost("CreateApprovalFlow")]
        public async Task<IActionResult> CreateApprovalFlow([FromBody] ApprovalFlowModel model)
        {
            if (string.IsNullOrEmpty(model.ApprovalName))
                return BadRequest(new { message = "Approval Name is required." });

            if (!model.HR.HasValue)
                return BadRequest(new { message = "HR approver is required." });

            if (!ModelState.IsValid)
                return BadRequest(new { message = "Invalid approval flow data." });

            try
            {
                _centralDbContext.Approvalflow.Add(model);
                await _centralDbContext.SaveChangesAsync();
                return Ok(new { message = "Approval flow created successfully." });
            }
            catch (Exception ex)
            {
                return StatusCode(500, new { message = $"Error saving approval flow: {ex.InnerException?.Message ?? ex.Message}" });
            }
        }


        [HttpGet("GetApprovalFlowRecord")]
        public async Task<IActionResult> GetApprovalFlowRecord()
        {
            try
            {
                var approvalFlows = await _centralDbContext.Approvalflow
                                                     .Select(af => new { af.ApprovalFlowId, af.ApprovalName })
                                                     .ToListAsync();
                return Ok(approvalFlows);
            }
            catch (Exception ex)
            {
                return StatusCode(500, new { message = $"Error fetching approval flows: {ex.Message}" });
            }
        }

        [HttpPost("EditApprovalFlow")]
        public async Task<IActionResult> EditApprovalFlow([FromBody] ApprovalFlowModel model)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest("Invalid data.");
            }

            var existingFlow = await _centralDbContext.Approvalflow.FindAsync(model.ApprovalFlowId);
            if (existingFlow == null)
            {
                return NotFound("Approval flow not found.");
            }

            existingFlow.ApprovalName = model.ApprovalName;
            existingFlow.HoU = model.HoU;
            existingFlow.HoD = model.HoD;
            existingFlow.Manager = model.Manager;
            existingFlow.HR = model.HR;

            try
            {
                await _centralDbContext.SaveChangesAsync();
                return Ok(new { message = "Approval flow updated successfully." });
            }
            catch (Exception ex)
            {
                return StatusCode(500, new { message = "Failed to update approval flow.", detail = ex.Message });
            }
        }

        [HttpDelete("DeleteApprovalFlow/{id}")]
        public async Task<IActionResult> DeleteApprovalFlow(int id)
        {
            try
            {
                var approvalFlow = await _centralDbContext.Approvalflow.FindAsync(id);
                if (approvalFlow == null)
                {
                    return NotFound(new { message = "Approval flow not found." });
                }

                var usersWithThisFlow = await _centralDbContext.Hrusersetting
                    .AnyAsync(u => u.ApprovalFlowId == id);

                if (usersWithThisFlow)
                {
                    return BadRequest(new
                    {
                        message = "Cannot delete this approval flow because it's being used by one or more users."
                    });
                }

                _centralDbContext.Approvalflow.Remove(approvalFlow);
                await _centralDbContext.SaveChangesAsync();

                return Ok(new { message = "Approval flow deleted successfully." });
            }
            catch (Exception ex)
            {
                return StatusCode(500, new
                {
                    message = $"Error deleting approval flow: {ex.Message}"
                });
            }
        }

        [HttpGet("GetAllUsers")]
        public async Task<IActionResult> GetAllUsers()
        {
            try
            {
                var users = await _centralDbContext.Users
                                    .Select(u => new { u.Id, u.FullName })
                                    .ToListAsync();
                return Ok(users);
            }
            catch (Exception ex)
            {
                return StatusCode(500, new { message = ex.Message });
            }
        }

        #endregion

        #region Calendar
        [HttpGet("GetStatesName")]
        public async Task<IActionResult> GetStatesName()
        {
            try
            {
                var states = await _centralDbContext.States
                    .Select(s => new
                    {
                        s.StateId,
                        s.StateName
                    })
                    .ToListAsync();

                return Json(states);
            }
            catch (Exception ex)
            {
                return BadRequest(ex.Message);
            }
        }


        [HttpPost("UpdateHoliday")]
        public async Task<IActionResult> UpdateHoliday([FromBody] List<CalendarModel> holidays)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            try
            {
                foreach (var calendar in holidays)
                {
                    var existingCalendar = await _centralDbContext.Holidays
                        .FirstOrDefaultAsync(h => h.StateId == calendar.StateId && h.HolidayDate == calendar.HolidayDate);

                    if (existingCalendar != null)
                    {
                        existingCalendar.HolidayName = calendar.HolidayName;
                        existingCalendar.LastUpdated = DateTime.Now;
                        _centralDbContext.Holidays.Update(existingCalendar);
                    }
                    else
                    {
                        _centralDbContext.Holidays.Add(new CalendarModel
                        {
                            HolidayName = calendar.HolidayName,
                            HolidayDate = calendar.HolidayDate,
                            StateId = calendar.StateId,
                            LastUpdated = DateTime.Now
                        });
                    }
                }

                await _centralDbContext.SaveChangesAsync();

                var updatedHoliday = await _centralDbContext.Holidays
                    .Include(h => h.States)
                    .Select(h => new
                    {
                        h.HolidayId,
                        h.HolidayName,
                        h.HolidayDate,
                        h.StateId,
                        StateName = h.States.StateName
                    })
                    .ToListAsync();

                return Json(updatedHoliday);
            }
            catch (Exception ex)
            {
                return BadRequest(ex.Message);
            }
        }

        [HttpGet("GetAllHolidays")]
        public IActionResult GetAllHolidays()
        {
            var holidays = _centralDbContext.Holidays.ToList();
            return Ok(holidays);
        }

        [HttpDelete("DeleteHoliday/{id}")]
        public async Task<IActionResult> DeleteHoliday(int id)
        {
            try
            {
                var holiday = await _centralDbContext.Holidays.FindAsync(id);
                if (holiday == null)
                {
                    return NotFound("Holiday not found.");
                }

                _centralDbContext.Holidays.Remove(holiday);
                await _centralDbContext.SaveChangesAsync();

                return Ok(new { message = "Holiday deleted successfully." });
            }
            catch (Exception ex)
            {
                return BadRequest(ex.Message);
            }
        }

        #endregion

        #region Weekend
        [HttpGet("GetWeekendDay")]
        public async Task<IActionResult> GetWeekendDay()
        {
            try
            {
                var weekends = await _centralDbContext.Weekends
                    .Select(w => new
                    {
                        w.WeekendId,
                        w.Day
                    })
                    .ToListAsync();

                return Json(weekends);
            }
            catch (Exception ex)
            {
                return BadRequest(ex.Message);
            }
        }

        [HttpPost("UpdateWeekend")]
        public async Task<IActionResult> UpdateWeekend([FromBody] List<StateModel> states)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            try
            {
                foreach (var state in states)
                {
                    var existingState = await _centralDbContext.States
                        .FirstOrDefaultAsync(s => s.StateId == state.StateId);

                    if (existingState != null)
                    {
                        existingState.WeekendId = state.WeekendId;
                        _centralDbContext.States.Update(existingState);
                    }
                    else
                    {
                        _centralDbContext.States.Add(new StateModel
                        {
                            StateId = state.StateId,
                            StateName = state.StateName,
                            WeekendId = state.WeekendId
                        });
                    }
                }

                await _centralDbContext.SaveChangesAsync();

                var updatedWeekend = await _centralDbContext.States
                    .Include(w => w.Weekends)
                    .Select(w => new
                    {
                        w.StateId,
                        w.StateName,
                        w.WeekendId,
                        Day = w.Weekends.Day
                    })
                    .ToListAsync();

                return Json(updatedWeekend);
            }
            catch (Exception ex)
            {
                return BadRequest(ex.Message);
            }
        }


        [HttpGet("GetAllWeekends")]
        public IActionResult GetAllWeekends()
        {
            var weekends = _centralDbContext.Weekends.ToList();
            return Ok(weekends);
        }

        [HttpGet("GetStateWeekends")]
        public async Task<IActionResult> GetStateWeekends()
        {
            try
            {
                var stateWeekends = await _centralDbContext.States
                    .Include(s => s.Weekends)
                    .Where(s => s.WeekendId != null)
                    .Select(s => new
                    {
                        s.StateId,
                        s.StateName,
                        Day = s.Weekends.Day
                    })
                    .ToListAsync();

                return Json(stateWeekends);
            }
            catch (Exception ex)
            {
                return BadRequest(ex.Message);
            }
        }

        #endregion

        #region Ot Register
            [HttpGet("GetStationsByDepartment")]
            public async Task<IActionResult> GetStationsByDepartment([FromQuery] int? departmentId)
            {
                if (!departmentId.HasValue)
                {
                    _logger.LogWarning("GetStationsByDepartment called without a departmentId.");
                    return Ok(new List<object>());
                }

                var stations = await _centralDbContext.Stations
                    .Where(s => s.DepartmentId == departmentId.Value)
                    .Select(s => new
                    {
                        s.StationId,
                        StationName = s.StationName ?? "Unnamed Station"
                    })
                    .ToListAsync();

                return Ok(stations);
            }


            [HttpPost("AddOvertime")]
            public async Task<IActionResult> AddOvertimeAsync([FromBody] OvertimeRequestDto request)
            {
                _logger.LogInformation("AddOvertimeAsync called.");
                _logger.LogInformation("Received request: {@Request}", request);

                if (request == null)
                {
                    _logger.LogError("Request is null.");
                    return BadRequest("Invalid data.");
                }

                try
                {
                    if (request.UserId == 0)
                    {
                        _logger.LogWarning("No user ID provided.");
                        return BadRequest("User ID is required.");
                    }

                    var user = await _userManager.FindByIdAsync(request.UserId.ToString());
                    if (user == null)
                    {
                        _logger.LogError("User with ID {UserId} not found for overtime submission.", request.UserId);
                        return Unauthorized("User not found.");
                    }

                    var userRoles = await _userManager.GetRolesAsync(user);
                    var isSuperAdmin = userRoles.Contains("SuperAdmin");
                    var isSystemAdmin = userRoles.Contains("SystemAdmin");

                    var userWithDepartment = await _centralDbContext.Users
                        .Include(u => u.Department)
                        .FirstOrDefaultAsync(u => u.Id == request.UserId);

                    int? userDepartmentId = userWithDepartment?.Department?.DepartmentId;

                    bool stationRequired = false;
                    if (userDepartmentId == 2 || userDepartmentId == 3)
                    {
                        stationRequired = true;
                    }
                    else if (isSuperAdmin || isSystemAdmin)
                    {
                        stationRequired = true;
                    }

                    if (stationRequired && (!request.StationId.HasValue || request.StationId.Value <= 0))
                    {
                        return BadRequest("A station must be selected.");
                    }

                    TimeSpan? officeFrom = string.IsNullOrEmpty(request.OfficeFrom) ? (TimeSpan?)null : TimeSpan.Parse(request.OfficeFrom);
                    TimeSpan? officeTo = string.IsNullOrEmpty(request.OfficeTo) ? (TimeSpan?)null : TimeSpan.Parse(request.OfficeTo);
                    TimeSpan? afterFrom = string.IsNullOrEmpty(request.AfterFrom) ? (TimeSpan?)null : TimeSpan.Parse(request.AfterFrom);
                    TimeSpan? afterTo = string.IsNullOrEmpty(request.AfterTo) ? (TimeSpan?)null : TimeSpan.Parse(request.AfterTo);

                    if ((officeFrom != null && officeTo == null) || (officeFrom == null && officeTo != null))
                    {
                        return BadRequest("Both Office From and To times must be provided if one is entered.");
                    }
                    if ((afterFrom != null && afterTo == null) || (afterFrom == null && afterTo != null))
                    {
                        return BadRequest("Both After Office From and To times must be provided if one is entered.");
                    }

                    TimeSpan minAllowedFromMidnightTo = new TimeSpan(16, 30, 0);
                    TimeSpan maxAllowedFromMidnightTo = new TimeSpan(23, 30, 0);

                    if (officeFrom.HasValue && officeTo.HasValue)
                    {
                        if (officeTo == TimeSpan.Zero)
                        {
                            if (officeFrom == TimeSpan.Zero)
                            {
                                return BadRequest("Invalid Office Hour Time: 'From' and 'To' cannot both be 00:00 (midnight).");
                            }

                            if (officeFrom.Value < minAllowedFromMidnightTo || officeFrom.Value > maxAllowedFromMidnightTo)
                            {
                                return BadRequest("Invalid Office Hour Time: If 'To' is 12:00 am (00:00), 'From' must start between end of your flexi hour to 11:30 pm on the same day.");
                            }
                        }
                        else if (officeTo <= officeFrom)
                        {
                            return BadRequest("Invalid Office Hour Time: 'To' time must be later than 'From' time (same day only).");
                        }
                    }

                    if (afterFrom.HasValue && afterTo.HasValue)
                    {
                        if (afterTo == TimeSpan.Zero)
                        {
                            if (afterFrom == TimeSpan.Zero)
                            {
                                return BadRequest("Invalid After Office Hour Time: 'From' and 'To' cannot both be 00:00 (midnight).");
                            }

                            if (afterFrom.Value < minAllowedFromMidnightTo || afterFrom.Value > maxAllowedFromMidnightTo)
                            {
                                return BadRequest("Invalid After Office Hour Time: If 'To' is 12:00 am (00:00), 'From' must start between end of your flexi hour to 11:30 pm on the same day.");
                            }
                        }
                        else if (afterTo <= afterFrom)
                        {
                            return BadRequest("Invalid After Office Hour Time: 'To' time must be later than 'From' time (same day only).");
                        }
                    }

                    if ((officeFrom == null && officeTo == null) && (afterFrom == null && afterTo == null))
                    {
                        return BadRequest("Please enter either Office Hours or After Office Hours.");
                    }

                    // Convert the request date to a DateOnly for comparison
                    DateOnly requestDate = DateOnly.FromDateTime(request.OtDate);

                    // Fetch existing overtime records for the same user and date
                    var existingOvertimeRecords = await _centralDbContext.Otregisters
                        .Where(o => o.UserId == request.UserId && DateOnly.FromDateTime(o.OtDate) == requestDate)
                        .ToListAsync();

                    // Check for overlaps with existing records
                    foreach (var existingRecord in existingOvertimeRecords)
                    {
                        // Convert existing record times to actual TimeSpan objects
                        var existingOfficeFrom = existingRecord.OfficeFrom;
                        var existingOfficeTo = existingRecord.OfficeTo;
                        var existingAfterFrom = existingRecord.AfterFrom;
                        var existingAfterTo = existingRecord.AfterTo;

                        // Function to check for overlap between two time ranges
                        Func<TimeSpan?, TimeSpan?, TimeSpan?, TimeSpan?, bool> CheckOverlap =
                            (newStart, newEnd, existingStart, existingEnd) =>
                            {
                                if (!newStart.HasValue || !newEnd.HasValue || !existingStart.HasValue || !existingEnd.HasValue)
                                {
                                    return false; // No overlap if either range is incomplete
                                }

                                // Handle midnight (00:00) as end of day (24:00) for comparison purposes
                                TimeSpan adjustedNewEnd = (newEnd == TimeSpan.Zero && newStart != TimeSpan.Zero) ? TimeSpan.FromHours(24) : newEnd.Value;
                                TimeSpan adjustedExistingEnd = (existingEnd == TimeSpan.Zero && existingStart != TimeSpan.Zero) ? TimeSpan.FromHours(24) : existingEnd.Value;


                                // Check for overlap:
                                // New range starts before existing range ends AND
                                // New range ends after existing range starts
                                return (newStart.Value < adjustedExistingEnd && adjustedNewEnd > existingStart.Value);
                            };

                        // Check for overlap between new Office Hours and existing Office Hours
                        if (CheckOverlap(officeFrom, officeTo, existingOfficeFrom, existingOfficeTo))
                        {
                            return BadRequest("Your Office Hours entry overlaps with another record on this date. Kindly adjust your time.");
                        }

                        // Check for overlap between new After Office Hours and existing After Office Hours
                        if (CheckOverlap(afterFrom, afterTo, existingAfterFrom, existingAfterTo))
                        {
                            return BadRequest("Your Office Hours entry overlaps with another record on this date. Kindly adjust your time.");
                        }

                        // Check for overlap between new Office Hours and existing After Office Hours
                        if (CheckOverlap(officeFrom, officeTo, existingAfterFrom, existingAfterTo))
                        {
                            return BadRequest("Your Office Hours entry overlaps with another record on this date. Kindly adjust your time.");
                        }

                        // Check for overlap between new After Office Hours and existing Office Hours
                        if (CheckOverlap(afterFrom, afterTo, existingOfficeFrom, existingOfficeTo))
                        {
                            return BadRequest("Your Office Hours entry overlaps with another record on this date. Kindly adjust your time.");
                        }
                    }

                    var newRecord = new OtRegisterModel
                    {
                        OtDate = request.OtDate,
                        OfficeFrom = officeFrom,
                        OfficeTo = officeTo,
                        OfficeBreak = request.OfficeBreak,
                        AfterFrom = afterFrom,
                        AfterTo = afterTo,
                        AfterBreak = request.AfterBreak,
                        StationId = request.StationId,
                        OtDescription = request.OtDescription,
                        OtDays = request.OtDays,
                        UserId = request.UserId,
                        StatusId = request.StatusId
                    };

                    _centralDbContext.Otregisters.Add(newRecord);
                    await _centralDbContext.SaveChangesAsync();

                    return Ok(new { message = "Overtime registered successfully." });
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "Error registering overtime for user {UserId}.", request.UserId);
                    return StatusCode(500, $"An error occurred while saving overtime: {ex.InnerException?.Message ?? ex.Message}");
                }
            }

            [HttpGet("GetUserStateAndHolidays/{userId}")]
            public async Task<IActionResult> GetUserStateAndHolidaysAsync(int userId)
            {
                try
                {
                    var hrSettings = await _centralDbContext.Hrusersetting
                        .Include(h => h.State)
                            .ThenInclude(s => s.Weekends)
                        .Include(h => h.FlexiHour)
                        .Where(h => h.UserId == userId)
                        .FirstOrDefaultAsync();

                    if (hrSettings?.State == null)
                    {
                        return Ok(new { state = (object)null, publicHolidays = new List<object>() });
                    }

                    var publicHolidays = await _centralDbContext.Holidays
                        .Where(ph => ph.StateId == hrSettings.StateId && ph.HolidayDate.Year == DateTime.Now.Year)
                        .Select(ph => new { Date = ph.HolidayDate.ToString("yyyy-MM-dd") })
                        .ToListAsync();

                    return Ok(new
                    {
                        state = new
                        {
                            stateId = hrSettings.StateId,
                            stateName = hrSettings.State?.StateName,
                            weekendDay = hrSettings.State?.Weekends?.Day,
                            weekendId = hrSettings.State?.WeekendId,
                            flexiHour = hrSettings.FlexiHour?.FlexiHour
                        },
                        publicHolidays
                    });
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "Error fetching user state and public holidays.");
                    return StatusCode(500, "An error occurred while fetching user state and public holidays.");
                }
            }

            [HttpGet("CheckUserSettings/{userId}")]
            public async Task<IActionResult> CheckUserSettings(int userId)
            {
                try
                {
                    var hrSettings = await _centralDbContext.Hrusersetting
                        .Where(h => h.UserId == userId)
                        .FirstOrDefaultAsync();

                    if (hrSettings == null)
                    {
                        return Ok(new { isComplete = false });
                    }

                    if (hrSettings.FlexiHourId == null || hrSettings.StateId == null || hrSettings.ApprovalFlowId == null)
                    {
                        return Ok(new { isComplete = false });
                    }

                    var rateSetting = await _centralDbContext.Rates
                        .Where(r => r.UserId == userId)
                        .FirstOrDefaultAsync();

                    if (rateSetting == null)
                    {
                        return Ok(new { isComplete = false });
                    }
                    else
                    {
                        if (rateSetting.RateValue <= 0.00m)
                        {
                            return Ok(new { isComplete = false });
                        }
                    }

                    return Ok(new { isComplete = true });
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "Error checking user settings for user {UserId}", userId);
                    return StatusCode(500, $"An error occurred while checking user settings: {ex.Message}");
                }
            }
        #endregion

        #region Ot Records 

        [HttpGet("GetUserOvertimeRecords/{userId}")]
        public IActionResult GetUserOvertimeRecords(int userId)
        {
            try
            {
                var records = _centralDbContext.Otregisters
                    .Include(o => o.Stations) 
                    .Where(o => o.UserId == userId)
                    .OrderByDescending(o => o.OtDate)
                    .Select(o => new
                    {
                        o.OvertimeId,
                        o.OtDate,
                        o.OfficeFrom,
                        o.OfficeTo,
                        o.OfficeBreak,
                        o.AfterFrom,
                        o.AfterTo,
                        o.AfterBreak,
                        o.StationId,
                        StationName = o.Stations != null ? o.Stations.StationName : "N/A",
                        o.OtDescription,
                        o.OtDays,
                        o.UserId
                    })
                    .ToList();

                return Ok(records);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Failed to fetch OT records.");
                return StatusCode(500, "Error retrieving OT records.");
            }
        }

        [HttpDelete("DeleteOvertimeRecord/{id}")]
        public IActionResult DeleteOvertimeRecord(int id)
        {
            try
            {
                var record = _centralDbContext.Otregisters.FirstOrDefault(o => o.OvertimeId == id);
                if (record == null)
                {
                    _logger.LogWarning("Overtime record not found for Id: {OvertimeId}", id);
                    return NotFound("Overtime record not found.");
                }

                _centralDbContext.Otregisters.Remove(record);
                _centralDbContext.SaveChanges();

                _logger.LogInformation("Overtime record deleted successfully for Id: {OvertimeId}", id);
                return Ok(new { message = "Record deleted successfully." });
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Failed to delete OT record.");
                return StatusCode(500, "Error deleting OT record.");
            }
        }

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

        [HttpPost("SubmitOvertime")]
        public async Task<IActionResult> SubmitOvertime([FromForm] OvertimeSubmissionModel model)
        {
            if (model.File == null || model.File.Length == 0)
                return BadRequest("No file uploaded.");

            var userIdStr = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
            if (string.IsNullOrEmpty(userIdStr) || !int.TryParse(userIdStr, out int userId))
                return Unauthorized();

            try
            {
                var uploadsFolder = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot/Media/Overtime");
                if (!Directory.Exists(uploadsFolder))
                    Directory.CreateDirectory(uploadsFolder);

                var uniqueFileName = $"{Guid.NewGuid()}_{model.File.FileName}";
                var filePath = Path.Combine(uploadsFolder, uniqueFileName);

                using (var fileStream = new FileStream(filePath, FileMode.Create))
                {
                    await model.File.CopyToAsync(fileStream);
                }

                var relativePath = $"/Media/Overtime/{uniqueFileName}";

                var statusModel = new OtStatusModel
                {
                    UserId = userId,
                    Month = model.Month,
                    Year = model.Year,
                    FilePath = relativePath,
                    SubmitDate = DateTime.Now,
                    HouStatus = "Pending",
                    HodStatus = "Pending",
                    ManagerStatus = "Pending",
                    HrStatus = "Pending"
                };

                _centralDbContext.Otstatus.Add(statusModel);
                await _centralDbContext.SaveChangesAsync();

                var monthStart = new DateTime(model.Year, model.Month, 1);
                var monthEnd = monthStart.AddMonths(1);

                var otRecords = _centralDbContext.Otregisters
                    .Where(r => r.UserId == userId && r.OtDate >= monthStart && r.OtDate < monthEnd)
                    .ToList();

                foreach (var record in otRecords)
                {
                    record.StatusId = statusModel.StatusId;
                }

                _centralDbContext.Otregisters.UpdateRange(otRecords);
                await _centralDbContext.SaveChangesAsync();

                var userSetting = _centralDbContext.Hrusersetting.FirstOrDefault(s => s.UserId == userId);
                if (userSetting != null)
                {
                    userSetting.ApprovalUpdate = DateTime.Now;
                    _centralDbContext.Hrusersetting.Update(userSetting);
                }

                await _centralDbContext.SaveChangesAsync();

                return Ok();
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Failed to submit overtime.");
                return StatusCode(500, "An error occurred while submitting overtime.");
            }
        }

        [HttpGet("CheckOvertimeSubmitted/{userId}/{month}/{year}")]
        public IActionResult CheckOvertimeSubmitted(int userId, int month, int year)
        {
            try
            {
                var latestStatus = _centralDbContext.Otstatus
                    .Where(s => s.UserId == userId && s.Month == month && s.Year == year)
                    .OrderByDescending(s => s.SubmitDate)
                    .FirstOrDefault();

                if (latestStatus == null)
                {
                    return Ok(false); 
                }

                if (latestStatus.HouStatus?.ToLower() == "rejected" ||
                    latestStatus.HodStatus?.ToLower() == "rejected" ||
                    latestStatus.ManagerStatus?.ToLower() == "rejected" ||
                    latestStatus.HrStatus?.ToLower() == "rejected")
                {
                    return Ok(false); 
                }

                if (latestStatus.HouStatus?.ToLower() == "pending" ||
                    latestStatus.HodStatus?.ToLower() == "pending" ||
                    latestStatus.ManagerStatus?.ToLower() == "pending" ||
                    latestStatus.HrStatus?.ToLower() == "pending")
                {
                    return Ok(true); 
                }

                return Ok(true);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error while checking overtime submission status.");
                return StatusCode(500, new { error = "Internal server error occurred." });
            }
        }

        #endregion

        #region Ot Edit
        [HttpGet("GetStationsByDepartmentAir")]
        public IActionResult GetStationsByDepartmentAir()
        {
            var stations = _centralDbContext.Stations

              .Where(s => s.DepartmentId == 2)
              .Select(s => new
              {
                  s.StationId,
                  StationName = s.StationName ?? "Unnamed Station"
              })

              .ToList();

            return Ok(stations);
        }

        [HttpGet("GetStationsByDepartmentMarine")]
        public IActionResult GetStationsByDepartmentMarine()
        {
            var stations = _centralDbContext.Stations

              .Where(s => s.DepartmentId == 3)
              .Select(s => new
              {
                  s.StationId,
                  StationName = s.StationName ?? "Unnamed Station"
              })

              .ToList();

            return Ok(stations);
        }

        [HttpGet("GetOvertimeRecordById/{id}")]
        public async Task<IActionResult> GetOvertimeRecordById(int id)
        {
            var record = await _centralDbContext.Otregisters.FindAsync(id);
            if (record == null)
                return NotFound();

            return Ok(record);
        }

        [HttpGet("GetUserFlexiHour/{userId}")]
        public async Task<IActionResult> GetUserFlexiHour(int userId)
        {
            try
            {
                var userSetting = await _centralDbContext.Hrusersetting
                                        .Include(hs => hs.FlexiHour) 
                                        .FirstOrDefaultAsync(hs => hs.UserId == userId);

                if (userSetting == null || userSetting.FlexiHour == null)
                {
                    _logger.LogWarning("Flexi hour not found for UserId: {UserId}", userId);
                    return NotFound(new { message = "Flexi hour not found for this user." });
                }

                return Ok(new { flexiHour = userSetting.FlexiHour });
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error fetching user flexi hour for UserId: {UserId}", userId);
                return StatusCode(500, new { message = "An error occurred while fetching flexi hour." });
            }
        }

        [HttpPost]
        [Route("UpdateOvertimeRecord")]
        public IActionResult UpdateOvertimeRecord([FromBody] OtRegisterUpdateDto model)
        {
            _logger.LogInformation("UpdateOvertimeRecord called. Model: {@Model}", model);

            try
            {
                if (!ModelState.IsValid)
                {
                    return BadRequest(ModelState);
                }

                var timeValidationError = ValidateTimeRanges(model);
                if (timeValidationError != null)
                {
                    return BadRequest(new { message = timeValidationError });
                }

                if (HasOverlappingRecords(model, model.UserId))
                {
                    return BadRequest(new { message = "Your Office Hours entry overlaps with another record on this date. Kindly adjust your time." });
                }

                var existing = _centralDbContext.Otregisters.FirstOrDefault(o => o.OvertimeId == model.OvertimeId);
                if (existing == null)
                {
                    return NotFound(new { message = "Overtime record not found." });
                }

                existing.OtDate = model.OtDate;
                existing.OfficeFrom = TimeSpan.TryParse(model.OfficeFrom, out var officeFrom) ? officeFrom : null;
                existing.OfficeTo = TimeSpan.TryParse(model.OfficeTo, out var officeTo) ? officeTo : null;
                existing.OfficeBreak = model.OfficeBreak;
                existing.AfterFrom = TimeSpan.TryParse(model.AfterFrom, out var afterFrom) ? afterFrom : null;
                existing.AfterTo = TimeSpan.TryParse(model.AfterTo, out var afterTo) ? afterTo : null;
                existing.AfterBreak = model.AfterBreak;
                existing.StationId = model.StationId;
                existing.OtDescription = model.OtDescription;
                existing.OtDays = model.OtDays;
                existing.UserId = model.UserId;

                _centralDbContext.SaveChanges();
                return Ok(new { message = "Record updated successfully." });
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error updating overtime record.");
                return StatusCode(500, new { message = "Failed to update record." });
            }
        }

        private string ValidateTimeRanges(OtRegisterUpdateDto model)
        {
            TimeSpan? officeFrom = string.IsNullOrEmpty(model.OfficeFrom) ? (TimeSpan?)null : TimeSpan.Parse(model.OfficeFrom);
            TimeSpan? officeTo = string.IsNullOrEmpty(model.OfficeTo) ? (TimeSpan?)null : TimeSpan.Parse(model.OfficeTo);
            TimeSpan? afterFrom = string.IsNullOrEmpty(model.AfterFrom) ? (TimeSpan?)null : TimeSpan.Parse(model.AfterFrom);
            TimeSpan? afterTo = string.IsNullOrEmpty(model.AfterTo) ? (TimeSpan?)null : TimeSpan.Parse(model.AfterTo);

            TimeSpan minAllowedFromMidnightTo = new TimeSpan(16, 30, 0); 
            TimeSpan maxAllowedFromMidnightTo = new TimeSpan(23, 30, 0);

            if (officeFrom.HasValue && officeTo.HasValue)
            {
                if (officeTo == TimeSpan.Zero) 
                {
                    if (officeFrom == TimeSpan.Zero)
                    {
                        return "Invalid Office Hour Time: 'From' and 'To' cannot both be 00:00 (midnight).";
                    }

                    if (officeFrom.Value < minAllowedFromMidnightTo || officeFrom.Value > maxAllowedFromMidnightTo)
                    {
                        return "Invalid Office Hour Time: If 'To' is 12:00 am (00:00), 'From' must start between end of your flexi hour to 11:30 pm on the same day.";
                    }
                }
                else if (officeTo <= officeFrom) 
                {
                    return "Invalid Office Hour Time: 'To' time must be later than 'From' time (same day only).";
                }
            }

            if (afterFrom.HasValue && afterTo.HasValue)
            {
                if (afterTo == TimeSpan.Zero) 
                {
                    if (afterFrom == TimeSpan.Zero)
                    {
                        return "Invalid After Office Hour Time: 'From' and 'To' cannot both be 00:00 (midnight).";
                    }

                    if (afterFrom.Value < minAllowedFromMidnightTo || afterFrom.Value > maxAllowedFromMidnightTo)
                    {
                        return "Invalid After Office Hour Time: If 'To' is 12:00 am (00:00), 'From' must start between end of your flexi hour to 11:30 pm on the same day.";
                    }
                }
                else if (afterTo <= afterFrom) 
                {
                    return "Invalid After Office Hour Time: 'To' time must be later than 'From' time (same day only).";
                }
            }

            if ((officeFrom == null && officeTo == null) && (afterFrom == null && afterTo == null))
            {
                return "Please enter either Office Hours or After Office Hours.";
            }

            return null;
        }

        private bool HasOverlappingRecords(OtRegisterUpdateDto model, int userId)
        {
            // Retrieve all other overtime records for the same user and date,
            // excluding the current record being updated.
            var existingRecords = _centralDbContext.Otregisters
                .Where(o => o.UserId == userId && o.OtDate.Date == model.OtDate.Date && o.OvertimeId != model.OvertimeId)
                .ToList();

            // The logic to check for overlap between two time ranges A and B is:
            // A_start < B_end AND B_start < A_end
            // This handles all scenarios, including one range being entirely inside another.

            // Check for overlap with the Office Hours block
            if (!string.IsNullOrEmpty(model.OfficeFrom) && !string.IsNullOrEmpty(model.OfficeTo))
            {
                var newOfficeStart = TimeSpan.Parse(model.OfficeFrom);
                var newOfficeEnd = TimeSpan.Parse(model.OfficeTo);
                foreach (var record in existingRecords)
                {
                    TimeSpan? existingOfficeStart = record.OfficeFrom;
                    TimeSpan? existingOfficeEnd = record.OfficeTo;
                    TimeSpan? existingAfterStart = record.AfterFrom;
                    TimeSpan? existingAfterEnd = record.AfterTo;

                    // Check against existing Office Hours
                    if (existingOfficeStart.HasValue && existingOfficeEnd.HasValue)
                    {
                        if (newOfficeStart < existingOfficeEnd.Value && existingOfficeStart.Value < newOfficeEnd)
                        {
                            return true;
                        }
                    }
                    // Check against existing After Office Hours
                    if (existingAfterStart.HasValue && existingAfterEnd.HasValue)
                    {
                        if (newOfficeStart < existingAfterEnd.Value && existingAfterStart.Value < newOfficeEnd)
                        {
                            return true;
                        }
                    }
                }
            }

            // Check for overlap with the After Office Hours block
            if (!string.IsNullOrEmpty(model.AfterFrom) && !string.IsNullOrEmpty(model.AfterTo))
            {
                var newAfterStart = TimeSpan.Parse(model.AfterFrom);
                var newAfterEnd = TimeSpan.Parse(model.AfterTo);
                foreach (var record in existingRecords)
                {
                    TimeSpan? existingOfficeStart = record.OfficeFrom;
                    TimeSpan? existingOfficeEnd = record.OfficeTo;
                    TimeSpan? existingAfterStart = record.AfterFrom;
                    TimeSpan? existingAfterEnd = record.AfterTo;

                    // Check against existing Office Hours
                    if (existingOfficeStart.HasValue && existingOfficeEnd.HasValue)
                    {
                        if (newAfterStart < existingOfficeEnd.Value && existingOfficeStart.Value < newAfterEnd)
                        {
                            return true;
                        }
                    }
                    // Check against existing After Office Hours
                    if (existingAfterStart.HasValue && existingAfterEnd.HasValue)
                    {
                        if (newAfterStart < existingAfterEnd.Value && existingAfterStart.Value < newAfterEnd)
                        {
                            return true;
                        }
                    }
                }
            }
            return false;
        }
        #endregion

        #region OT Status
        [HttpGet("GetUserOtStatus")]
        public IActionResult GetUserOtStatus()
        {
            var userIdClaim = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;

            if (string.IsNullOrEmpty(userIdClaim))
                return BadRequest("User ID is not available.");

            if (!int.TryParse(userIdClaim, out int userId))
                return BadRequest("Invalid User ID.");

            var approvalFlowId = _centralDbContext.Hrusersetting
                .Where(x => x.UserId == userId)
                .Select(x => x.ApprovalFlowId)
                .FirstOrDefault();

            bool includeHou = false;
            bool includeHod = false;
            bool includeManager = false;
            bool includeHr = false;

            if (approvalFlowId != null)
            {
                var flow = _centralDbContext.Approvalflow
                    .FirstOrDefault(f => f.ApprovalFlowId == approvalFlowId);

                if (flow != null)
                {
                    includeHou = flow.HoU.HasValue;
                    includeHod = flow.HoD.HasValue;
                    includeManager = flow.Manager.HasValue;
                    includeHr = flow.HR.HasValue;
                }
            }

            var otStatuses = _centralDbContext.Otstatus
                .Where(o => o.UserId == userId)
                .Select(o => new
                {
                    o.Month,
                    o.Year,
                    o.SubmitDate,
                    HouStatus = includeHou ? o.HouStatus : null,
                    HodStatus = includeHod ? o.HodStatus : null,
                    ManagerStatus = includeManager ? o.ManagerStatus : null,
                    HrStatus = includeHr ? o.HrStatus : null,
                    o.FilePath,
                    Updated = o.HouUpdate != null || o.HodUpdate != null || o.ManagerUpdate != null || o.HrUpdate != null,
                    o.HouUpdate,
                    o.HodUpdate,
                    o.ManagerUpdate,
                    o.HrUpdate
                })
                .ToList();

            return Ok(new
            {
                includeHou,
                includeHod,
                includeManager,
                includeHr,
                otStatuses,
                hasApprovalFlow = approvalFlowId != null
            });
        }
        #endregion

        #region OT Approval
        [HttpGet("GetPendingApproval")]
        public IActionResult GetPendingApproval(int month, int year)
        {
            var userIdStr = _userManager.GetUserId(User);
            if (string.IsNullOrEmpty(userIdStr) || !int.TryParse(userIdStr, out int currentUserId))
                return Unauthorized("Invalid or missing user ID");

            var flows = _centralDbContext.Approvalflow
                .Where(f => f.HoU == currentUserId || f.HoD == currentUserId || f.Manager == currentUserId || f.HR == currentUserId)
                .ToList();

            if (!flows.Any())
                return Json(new { Roles = new List<string>(), Data = new List<object>(), OverallPendingMonths = new List<string>() });

            var flowRoleMap = new Dictionary<int, string>();
            foreach (var flow in flows)
            {
                if (flow.HoU == currentUserId) flowRoleMap[flow.ApprovalFlowId] = "HoU";
                if (flow.HoD == currentUserId) flowRoleMap[flow.ApprovalFlowId] = "HoD";
                if (flow.Manager == currentUserId) flowRoleMap[flow.ApprovalFlowId] = "Manager";
                if (flow.HR == currentUserId) flowRoleMap[flow.ApprovalFlowId] = "HR";
            }

            var allRelevantOtEntries = (from status in _centralDbContext.Otstatus
                                        join setting in _centralDbContext.Hrusersetting on status.UserId equals setting.UserId
                                        where setting.ApprovalFlowId.HasValue && flowRoleMap.Keys.Contains(setting.ApprovalFlowId.Value)
                                        select new
                                        {
                                            status.Month,
                                            status.Year,
                                            setting.ApprovalFlowId,
                                            status.HouStatus,
                                            status.HodStatus,
                                            status.ManagerStatus,
                                            status.HrStatus
                                        }).ToList();

            var pendingMonthsAndYears = new HashSet<string>();

            var allFlows = _centralDbContext.Approvalflow.ToList(); 

            foreach (var entry in allRelevantOtEntries)
            {
                var role = flowRoleMap[entry.ApprovalFlowId.Value];
                var flow = allFlows.FirstOrDefault(f => f.ApprovalFlowId == entry.ApprovalFlowId); 
                if (flow == null) continue;

                bool isPendingForCurrentUser = false;

                if (role == "HoU" && (entry.HouStatus == null || entry.HouStatus == "Pending") &&
                    !(entry.HodStatus == "Rejected" || entry.ManagerStatus == "Rejected" || entry.HrStatus == "Rejected"))
                {
                    isPendingForCurrentUser = true;
                }
                else if (role == "HoD" && (entry.HodStatus == null || entry.HodStatus == "Pending") &&
                         (!flow.HoU.HasValue || entry.HouStatus == "Approved") &&
                         !(entry.HouStatus == "Rejected" || entry.ManagerStatus == "Rejected" || entry.HrStatus == "Rejected"))
                {
                    isPendingForCurrentUser = true;
                }
                else if (role == "Manager" && (entry.ManagerStatus == null || entry.ManagerStatus == "Pending") &&
                         (!flow.HoU.HasValue || entry.HouStatus == "Approved") &&
                         (!flow.HoD.HasValue || entry.HodStatus == "Approved") &&
                         !(entry.HouStatus == "Rejected" || entry.HodStatus == "Rejected" || entry.HrStatus == "Rejected"))
                {
                    isPendingForCurrentUser = true;
                }
                else if (role == "HR" && (entry.HrStatus == null || entry.HrStatus == "Pending") &&
                         (!flow.HoU.HasValue || entry.HouStatus == "Approved") &&
                         (!flow.HoD.HasValue || entry.HodStatus == "Approved") &&
                         (!flow.Manager.HasValue || entry.ManagerStatus == "Approved") &&
                         !(entry.HouStatus == "Rejected" || entry.HodStatus == "Rejected" || entry.ManagerStatus == "Rejected"))
                {
                    isPendingForCurrentUser = true;
                }

                if (isPendingForCurrentUser)
                {
                    pendingMonthsAndYears.Add($"{entry.Month:D2}/{entry.Year}");
                }
            }

            var otEntriesForSelectedMonth = (from status in _centralDbContext.Otstatus
                                             join user in _centralDbContext.Users on status.UserId equals user.Id
                                             join setting in _centralDbContext.Hrusersetting on status.UserId equals setting.UserId
                                             where status.Month == month && status.Year == year && setting.ApprovalFlowId.HasValue
                                             select new
                                             {
                                                 status.StatusId,
                                                 status.UserId,
                                                 status.SubmitDate,
                                                 status.HouStatus,
                                                 status.HodStatus,
                                                 status.ManagerStatus,
                                                 status.HrStatus,
                                                 setting.ApprovalFlowId,
                                                 fullName = user.FullName
                                             }).ToList();

            var processedList = new List<object>();
            var distinctRoles = new HashSet<string>();

            foreach (var entry in otEntriesForSelectedMonth)
            {
                if (!entry.ApprovalFlowId.HasValue || !flowRoleMap.ContainsKey(entry.ApprovalFlowId.Value))
                    continue;

                var role = flowRoleMap[entry.ApprovalFlowId.Value];
                distinctRoles.Add(role);

                var flow = allFlows.FirstOrDefault(f => f.ApprovalFlowId == entry.ApprovalFlowId); 
                if (flow == null) continue;

                bool canApprove = false;
                string currentUserStatus = "N/A";

                if (role == "HoU")
                {
                    currentUserStatus = entry.HouStatus ?? "Pending";
                    canApprove = currentUserStatus == "Pending" &&
                                 !(entry.HodStatus == "Rejected" || entry.ManagerStatus == "Rejected" || entry.HrStatus == "Rejected");
                }
                else if (role == "HoD")
                {
                    currentUserStatus = entry.HodStatus ?? "Pending";
                    canApprove = currentUserStatus == "Pending" &&
                                 (!flow.HoU.HasValue || entry.HouStatus == "Approved") &&
                                 !(entry.HouStatus == "Rejected" || entry.ManagerStatus == "Rejected" || entry.HrStatus == "Rejected");
                }
                else if (role == "Manager")
                {
                    currentUserStatus = entry.ManagerStatus ?? "Pending";
                    canApprove = currentUserStatus == "Pending" &&
                                 (!flow.HoU.HasValue || entry.HouStatus == "Approved") &&
                                 (!flow.HoD.HasValue || entry.HodStatus == "Approved") &&
                                 !(entry.HouStatus == "Rejected" || entry.HodStatus == "Rejected" || entry.HrStatus == "Rejected");
                }
                else if (role == "HR")
                {
                    currentUserStatus = entry.HrStatus ?? "Pending";
                    canApprove = currentUserStatus == "Pending" &&
                                 (!flow.HoU.HasValue || entry.HouStatus == "Approved") &&
                                 (!flow.HoD.HasValue || entry.HodStatus == "Approved") &&
                                 (!flow.Manager.HasValue || entry.ManagerStatus == "Approved") &&
                                 !(entry.HouStatus == "Rejected" || entry.HodStatus == "Rejected" || entry.ManagerStatus == "Rejected");
                }

                bool isOverallRejected = (entry.HouStatus == "Rejected" ||
                                          entry.HodStatus == "Rejected" ||
                                          entry.ManagerStatus == "Rejected" ||
                                          entry.HrStatus == "Rejected");

                processedList.Add(new
                {
                    entry.StatusId,
                    entry.SubmitDate,
                    entry.HouStatus,
                    entry.HodStatus,
                    entry.ManagerStatus,
                    entry.HrStatus,
                    entry.ApprovalFlowId,
                    entry.fullName,
                    Role = role,
                    CanApprove = canApprove,
                    CurrentUserStatus = currentUserStatus,
                    IsOverallRejected = isOverallRejected
                });
            }

            return Json(new
            {
                Roles = distinctRoles.ToList(),
                Data = processedList,
                OverallPendingMonths = pendingMonthsAndYears.OrderByDescending(m => m).ToList() 
            });
        }

        [HttpPost("UpdateApprovalStatus")]
        public IActionResult UpdateApprovalStatus([FromBody] UpdateStatusDto dto)
        {
            if (dto == null)
                return BadRequest("DTO is null or improperly formatted.");

            if (dto.StatusId == 0 || string.IsNullOrWhiteSpace(dto.Decision))
                return BadRequest("Missing StatusId or Decision.");

            var userIdStr = _userManager.GetUserId(User);
            if (string.IsNullOrEmpty(userIdStr) || !int.TryParse(userIdStr, out int currentUserId))
                return Unauthorized("Invalid user");

            var status = _centralDbContext.Otstatus.FirstOrDefault(s => s.StatusId == dto.StatusId);
            if (status == null) return NotFound("OT Status not found");

            var setting = _centralDbContext.Hrusersetting.FirstOrDefault(s => s.UserId == status.UserId);
            if (setting == null) return BadRequest("User setting not found");

            var flow = _centralDbContext.Approvalflow.FirstOrDefault(f => f.ApprovalFlowId == setting.ApprovalFlowId);
            if (flow == null) return BadRequest("Approval flow not found");

            var now = DateTime.Now;

            if (status.HouStatus == "Rejected" || status.HodStatus == "Rejected" || status.ManagerStatus == "Rejected" || status.HrStatus == "Rejected")
            {
                return BadRequest("This request has already been rejected by a prior approver.");
            }

            bool isAuthorizedToAct = false;
            string currentRoleStatus = "";

            if (flow.HoU == currentUserId)
            {
                currentRoleStatus = status.HouStatus ?? "Pending";
                if (currentRoleStatus == "Pending") isAuthorizedToAct = true;
            }
            else if (flow.HoD == currentUserId)
            {
                currentRoleStatus = status.HodStatus ?? "Pending";
                if (currentRoleStatus == "Pending" && (!flow.HoU.HasValue || status.HouStatus == "Approved")) isAuthorizedToAct = true;
            }
            else if (flow.Manager == currentUserId)
            {
                currentRoleStatus = status.ManagerStatus ?? "Pending";
                if (currentRoleStatus == "Pending" &&
                    (!flow.HoU.HasValue || status.HouStatus == "Approved") &&
                    (!flow.HoD.HasValue || status.HodStatus == "Approved")) isAuthorizedToAct = true;
            }
            else if (flow.HR == currentUserId)
            {
                currentRoleStatus = status.HrStatus ?? "Pending";
                if (currentRoleStatus == "Pending" &&
                    (!flow.HoU.HasValue || status.HouStatus == "Approved") &&
                    (!flow.HoD.HasValue || status.HodStatus == "Approved") &&
                    (!flow.Manager.HasValue || status.ManagerStatus == "Approved")) isAuthorizedToAct = true;
            }

            if (!isAuthorizedToAct)
            {
                return BadRequest("You are not authorized to act on this request at this stage or the status has already been set.");
            }

            if (dto.Decision.ToLower() == "rejected")
            {
                if (flow.HoU == currentUserId) { status.HouStatus = "Rejected"; status.HouSubmitDate = now; }
                else if (flow.HoD == currentUserId) { status.HodStatus = "Rejected"; status.HodSubmitDate = now; }
                else if (flow.Manager == currentUserId) { status.ManagerStatus = "Rejected"; status.ManagerSubmitDate = now; }
                else if (flow.HR == currentUserId) { status.HrStatus = "Rejected"; status.HrSubmitDate = now; }
            }
            else if (dto.Decision.ToLower() == "approved")
            {
                if (flow.HoU == currentUserId) { status.HouStatus = "Approved"; status.HouSubmitDate = now; }
                else if (flow.HoD == currentUserId) { status.HodStatus = "Approved"; status.HodSubmitDate = now; }
                else if (flow.Manager == currentUserId) { status.ManagerStatus = "Approved"; status.ManagerSubmitDate = now; }
                else if (flow.HR == currentUserId) { status.HrStatus = "Approved"; status.HrSubmitDate = now; }
            }
            else
            {
                return BadRequest("Invalid decision value.");
            }

            _centralDbContext.SaveChanges();
            return Ok(new { message = "Status updated successfully." });
        }
        #endregion

        #region OT Review

        [HttpGet("GetAllStations")]
        public IActionResult GetAllStations()
        {
            var stations = _centralDbContext.Stations.Select(s => new { s.StationId, s.StationName }).ToList();
            return Ok(stations);
        }

        [HttpGet("GetOtRecordsByStatusId/{statusId}")]
        public IActionResult GetOtRecordsByStatusId(int statusId)
        {
            var otStatus = _centralDbContext.Otstatus.FirstOrDefault(s => s.StatusId == statusId);
            if (otStatus == null)
                return NotFound("OT status not found.");

            var user = _centralDbContext.Users.FirstOrDefault(u => u.Id == otStatus.UserId);
            if (user == null)
                return NotFound("User not found.");

            var department = _centralDbContext.Departments
                .Where(d => d.DepartmentId == user.departmentId)
                .Select(d => d.DepartmentName)
                .FirstOrDefault();

            var userBasicSalary = _centralDbContext.Rates
                .Where(r => r.UserId == user.Id)
                .Select(r => r.RateValue)
                .FirstOrDefault();

            var userSetting = _centralDbContext.Hrusersetting
                .Include(us => us.State)
                .Include(us => us.Approvalflow)
                    .ThenInclude(af => af.HeadOfUnit)
                .Include(us => us.FlexiHour)
                .FirstOrDefault(us => us.UserId == user.Id);

            if (userSetting?.State == null)
                return NotFound("User state information not found in HR User Settings.");

            if (userSetting?.Approvalflow == null)
                return NotFound("Approval flow information not found for the user.");

            var publicHolidaysForTable = _centralDbContext.Holidays
                .Where(h => h.StateId == userSetting.State.StateId)
                .Select(h => h.HolidayDate.Date.ToString("yyyy-MM-dd")) 
                .ToList();

            var otRecords = _centralDbContext.Otregisters
                .Include(o => o.Stations)
                .Where(o => o.StatusId == statusId)
                .ToList()
                .Select(o =>
                {
                    string dayType;
                    DateTime otDate = o.OtDate.Date;
                    DayOfWeek dayOfWeek = otDate.DayOfWeek;

                    if (publicHolidaysForTable.Contains(otDate.ToString("yyyy-MM-dd"))) 
                    {
                        dayType = "Public Holiday";
                    }
                    else if (userSetting.State.WeekendId == 1) 
                    {
                        if (dayOfWeek == DayOfWeek.Friday) dayType = "Off Day";
                        else if (dayOfWeek == DayOfWeek.Saturday) dayType = "Rest Day";
                        else dayType = "Normal Day";
                    }
                    else if (userSetting.State.WeekendId == 2) 
                    {
                        if (dayOfWeek == DayOfWeek.Saturday) dayType = "Off Day";
                        else if (dayOfWeek == DayOfWeek.Sunday) dayType = "Rest Day";
                        else dayType = "Normal Day";
                    }
                    else
                    {
                        dayType = "Normal Day"; 
                    }

                    return new
                    {
                        o.OvertimeId,
                        o.OtDate,
                        o.OfficeFrom,
                        o.OfficeTo,
                        o.OfficeBreak,
                        o.AfterFrom,
                        o.AfterTo,
                        o.AfterBreak,
                        o.StationId,
                        StationName = o.Stations != null ? o.Stations.StationName : "N/A",
                        o.OtDescription,
                        o.OtDays,
                        o.UserId,
                        Rate = userBasicSalary, // Pass the Basic Salary as 'Rate'
                        DayType = dayType, 
                    };
                })
                .ToList();

            var currentLoggedInUserId = GetCurrentLoggedInUserId();
            string approverRole = GetApproverRole(currentLoggedInUserId, statusId);

            bool hasApproverActed = false;
            switch (approverRole)
            {
                case "HoU":
                    hasApproverActed = !string.IsNullOrEmpty(otStatus.HouStatus) && otStatus.HouStatus != "Pending";
                    break;
                case "HoD":
                    hasApproverActed = !string.IsNullOrEmpty(otStatus.HodStatus) && otStatus.HodStatus != "Pending";
                    break;
                case "Manager":
                    hasApproverActed = !string.IsNullOrEmpty(otStatus.ManagerStatus) && otStatus.ManagerStatus != "Pending";
                    break;
                case "HR":
                    hasApproverActed = !string.IsNullOrEmpty(otStatus.HrStatus) && otStatus.HrStatus != "Pending";
                    break;
                default:
                    hasApproverActed = true; 
                    break;
            }

            var result = new
            {
                userInfo = new
                {
                    fullName = user.FullName,
                    departmentName = department,
                    user.departmentId,
                    filePath = otStatus.FilePath,
                    fullNameLower = user.FullName?.ToLower(),
                    flexiHour = userSetting.FlexiHour?.FlexiHour,
                    stateId = userSetting.State.StateId, 
                    weekendId = userSetting.State.WeekendId,
                    rate = userBasicSalary 
                },
                records = otRecords,
                isHoU = userSetting.Approvalflow?.HoU == currentLoggedInUserId,
                otStatus.HouStatus,
                otStatus.HodStatus,
                otStatus.ManagerStatus,
                otStatus.HrStatus,
                approverRole,
                hasApproverActed

            };

            return Ok(result);
        }

        [HttpGet("GetPublicHolidaysByState/{stateId}")]
        public IActionResult GetPublicHolidaysByState(int stateId)
        {
            var holidays = _centralDbContext.Holidays
                .Where(h => h.StateId == stateId)
                .Select(h => new
                {
                    date = h.HolidayDate.ToString("yyyy-MM-dd"),
                    name = h.HolidayName
                })
                .ToList();

            return Ok(holidays);
        }

        [HttpPost("UpdateOtRecordByApprover")]
        public IActionResult UpdateOtRecordByApprover([FromBody] OtRegisterEditDto updatedRecordDto)
        {
            if (updatedRecordDto == null)
            {
                return BadRequest("Invalid record data.");
            }

            var existingRecord = _centralDbContext.Otregisters.FirstOrDefault(o => o.OvertimeId == updatedRecordDto.OvertimeId);
            if (existingRecord == null)
            {
                return NotFound(new { message = "Overtime record not found." });
            }

            // **NEW LOGIC: Check for overlapping entries**
            if (IsOverlapping(updatedRecordDto, existingRecord.UserId, updatedRecordDto.OvertimeId))
            {
                return BadRequest(new { message = "The new overtime time range overlaps with an existing entry for the same date." });
            }

            // ... (rest of your existing logic for finding otStatus, permissions, and logging)
            // The previous code for validation will be moved to a helper method or retained if it's still needed
            var otStatus = _centralDbContext.Otstatus.FirstOrDefault(s => s.StatusId == updatedRecordDto.StatusId);
            if (otStatus == null)
            {
                return NotFound("OT status not found.");
            }

            // ... (rest of the code for checking permissions and logging)
            var currentLoggedInUserId = GetCurrentLoggedInUserId();
            string approverRole = GetApproverRole(currentLoggedInUserId, otStatus.StatusId);

            bool hasApproverActed = false;
            switch (approverRole)
            {
                case "HoU":
                    hasApproverActed = !string.IsNullOrEmpty(otStatus.HouStatus) && otStatus.HouStatus != "Pending";
                    break;
                case "HoD":
                    hasApproverActed = !string.IsNullOrEmpty(otStatus.HodStatus) && otStatus.HodStatus != "Pending";
                    break;
                case "Manager":
                    hasApproverActed = !string.IsNullOrEmpty(otStatus.ManagerStatus) && otStatus.ManagerStatus != "Pending";
                    break;
                case "HR":
                    hasApproverActed = !string.IsNullOrEmpty(otStatus.HrStatus) && otStatus.HrStatus != "Pending";
                    break;
            }

            if (hasApproverActed)
            {
                return Forbid("You cannot edit this record as you have already acted on this OT submission.");
            }

            var originalRecordData = JsonConvert.SerializeObject(existingRecord, new JsonSerializerSettings
            {
                ReferenceLoopHandling = ReferenceLoopHandling.Ignore
            });

            // Update the existing record with the new data
            existingRecord.OtDate = updatedRecordDto.OtDate;
            existingRecord.OfficeFrom = ParseTimeStringToTimeSpan(updatedRecordDto.OfficeFrom);
            existingRecord.OfficeTo = ParseTimeStringToTimeSpan(updatedRecordDto.OfficeTo);
            existingRecord.OfficeBreak = updatedRecordDto.OfficeBreak;
            existingRecord.AfterFrom = ParseTimeStringToTimeSpan(updatedRecordDto.AfterFrom);
            existingRecord.AfterTo = ParseTimeStringToTimeSpan(updatedRecordDto.AfterTo);
            existingRecord.AfterBreak = updatedRecordDto.AfterBreak;
            existingRecord.StationId = updatedRecordDto.StationId;
            existingRecord.OtDescription = updatedRecordDto.OtDescription;

            _centralDbContext.SaveChanges();

            var updateLog = new OtUpdateLog
            {
                ApproverRole = approverRole,
                ApproverUserId = currentLoggedInUserId,
                UpdateTimestamp = DateTime.Now,
                ChangeType = "Edit",
                BeforeEdit = JsonConvert.DeserializeObject<OtRegisterModel>(originalRecordData),
                AfterEdit = updatedRecordDto
            };

            var logJson = JsonConvert.SerializeObject(updateLog);

            switch (approverRole)
            {
                case "HoU":
                    otStatus.HouUpdate = AppendUpdateLog(otStatus.HouUpdate, logJson);
                    break;
                case "HoD":
                    otStatus.HodUpdate = AppendUpdateLog(otStatus.HodUpdate, logJson);
                    break;
                case "Manager":
                    otStatus.ManagerUpdate = AppendUpdateLog(otStatus.ManagerUpdate, logJson);
                    break;
                case "HR":
                    otStatus.HrUpdate = AppendUpdateLog(otStatus.HrUpdate, logJson);
                    break;
                default:
                    return Unauthorized("You are not authorized to edit this record.");
            }
            _centralDbContext.SaveChanges();

            return Ok(new { message = "Overtime record updated successfully and changes logged." });
        }

        // **NEW HELPER METHOD: IsOverlapping**
        private bool IsOverlapping(OtRegisterEditDto updatedRecord, int userId, int currentRecordId)
        {
            // Filter existing records for the same date, excluding the one being edited
            var existingRecords = _centralDbContext.Otregisters
                .Where(o => o.UserId == userId && o.OtDate.Date == updatedRecord.OtDate.Date && o.OvertimeId != currentRecordId)
                .ToList();

            // Check for overlaps with the new time ranges
            TimeSpan? newOfficeFrom = ParseTimeStringToTimeSpan(updatedRecord.OfficeFrom);
            TimeSpan? newOfficeTo = ParseTimeStringToTimeSpan(updatedRecord.OfficeTo);
            TimeSpan? newAfterFrom = ParseTimeStringToTimeSpan(updatedRecord.AfterFrom);
            TimeSpan? newAfterTo = ParseTimeStringToTimeSpan(updatedRecord.AfterTo);

            foreach (var existing in existingRecords)
            {
                // Check if the new office hours overlap with any existing time range
                if (newOfficeFrom.HasValue && newOfficeTo.HasValue)
                {
                    if (CheckOverlapBetween(newOfficeFrom.Value, newOfficeTo.Value, existing.OfficeFrom, existing.OfficeTo) ||
                        CheckOverlapBetween(newOfficeFrom.Value, newOfficeTo.Value, existing.AfterFrom, existing.AfterTo))
                    {
                        return true;
                    }
                }

                // Check if the new after office hours overlap with any existing time range
                if (newAfterFrom.HasValue && newAfterTo.HasValue)
                {
                    if (CheckOverlapBetween(newAfterFrom.Value, newAfterTo.Value, existing.OfficeFrom, existing.OfficeTo) ||
                        CheckOverlapBetween(newAfterFrom.Value, newAfterTo.Value, existing.AfterFrom, existing.AfterTo))
                    {
                        return true;
                    }
                }
            }

            return false;
        }

        // **NEW HELPER METHOD: CheckOverlapBetween**
        private bool CheckOverlapBetween(TimeSpan start1, TimeSpan end1, TimeSpan? start2, TimeSpan? end2)
        {
            // If either of the second time range's values is missing, there can be no overlap.
            if (!start2.HasValue || !end2.HasValue)
            {
                return false;
            }

            // Create local, non-nullable variables to work with.
            TimeSpan s1 = start1;
            TimeSpan e1 = end1;
            TimeSpan s2 = start2.Value;
            TimeSpan e2 = end2.Value;

            // Handle overnight cases for both ranges by adding 24 hours to the end time
            // if it's on or before the start time.
            // TimeSpan.FromHours(24) is a cleaner way to express this.
            if (e1 <= s1)
            {
                e1 = e1.Add(TimeSpan.FromHours(24));
            }
            if (e2 <= s2)
            {
                e2 = e2.Add(TimeSpan.FromHours(24));
            }

            // Overlap exists if the start of one range is before the end of the other,
            // AND the start of the other is before the end of the first.
            return s1 < e2 && s2 < e1;
        }

        [HttpDelete("DeleteOvertimeInOtReview/{id}")]
        public IActionResult DeleteOvertimeInOtReview(int id)
        {
            var recordToDelete = _centralDbContext.Otregisters.FirstOrDefault(o => o.OvertimeId == id);
            if (recordToDelete == null)
            {
                return NotFound(new { message = "Overtime record not found." });
            }

            var statusIdForRecord = recordToDelete.StatusId;
            if (!statusIdForRecord.HasValue)
            {
                return BadRequest("Overtime record is not associated with a status.");
            }

            var otStatus = _centralDbContext.Otstatus.FirstOrDefault(s => s.StatusId == statusIdForRecord.Value);
            if (otStatus == null)
            {
                return NotFound("OT status for this record not found.");
            }

            var currentLoggedInUserId = GetCurrentLoggedInUserId();
            string approverRole = GetApproverRole(currentLoggedInUserId, statusIdForRecord.Value);

            bool hasApproverActed = false;
            switch (approverRole)
            {
                case "HoU":
                    hasApproverActed = !string.IsNullOrEmpty(otStatus.HouStatus) && otStatus.HouStatus != "Pending";
                    break;
                case "HoD":
                    hasApproverActed = !string.IsNullOrEmpty(otStatus.HodStatus) && otStatus.HodStatus != "Pending";
                    break;
                case "Manager":
                    hasApproverActed = !string.IsNullOrEmpty(otStatus.ManagerStatus) && otStatus.ManagerStatus != "Pending";
                    break;
                case "HR":
                    hasApproverActed = !string.IsNullOrEmpty(otStatus.HrStatus) && otStatus.HrStatus != "Pending";
                    break;
            }

            if (hasApproverActed)
            {
                return Forbid("You cannot delete this record as you have already acted on this OT submission.");
            }

            var deletedRecordData = JsonConvert.SerializeObject(recordToDelete, new JsonSerializerSettings
            {
                ReferenceLoopHandling = ReferenceLoopHandling.Ignore
            });

            _centralDbContext.Otregisters.Remove(recordToDelete);
            _centralDbContext.SaveChanges();

            var deleteLog = new OtUpdateLog
            {
                ApproverRole = approverRole,
                ApproverUserId = currentLoggedInUserId,
                UpdateTimestamp = DateTime.Now,
                ChangeType = "Delete",
                DeletedRecord = JsonConvert.DeserializeObject<OtRegisterModel>(deletedRecordData)
            };

            var logJson = JsonConvert.SerializeObject(deleteLog);

            switch (approverRole)
            {
                case "HoU":
                    otStatus.HouUpdate = AppendUpdateLog(otStatus.HouUpdate, logJson);
                    break;
                case "HoD":
                    otStatus.HodUpdate = AppendUpdateLog(otStatus.HodUpdate, logJson);
                    break;
                case "Manager":
                    otStatus.ManagerUpdate = AppendUpdateLog(otStatus.ManagerUpdate, logJson);
                    break;
                case "HR":
                    otStatus.HrUpdate = AppendUpdateLog(otStatus.HrUpdate, logJson);
                    break;
                default:
                    Console.WriteLine($"Unauthorized deletion attempt by user {currentLoggedInUserId} for status {statusIdForRecord.Value}");
                    break;
            }
            _centralDbContext.SaveChanges();

            return Ok(new { message = "Overtime record deleted successfully and deletion logged." });
        }

        private int GetCurrentLoggedInUserId()
        {
            if (User.Identity.IsAuthenticated)
            {
                var userIdClaim = User.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier);
                if (userIdClaim != null && int.TryParse(userIdClaim.Value, out int userId))
                {
                    return userId;
                }
            }
            return -1;
        }

        private string GetApproverRole(int currentUserId, int statusId)
        {
            var otStatus = _centralDbContext.Otstatus.FirstOrDefault(s => s.StatusId == statusId);

            if (otStatus == null)
            {
                return "Unknown: Status not found";
            }

            var submittedByUserId = otStatus.UserId;

            var hrUserSetting = _centralDbContext.Hrusersetting
                .Include(hus => hus.Approvalflow)
                .FirstOrDefault(hus => hus.UserId == submittedByUserId);

            if (hrUserSetting?.Approvalflow == null)
            {
                return "Unknown: Approval flow not configured for user";
            }

            var approvalFlow = hrUserSetting.Approvalflow;

            if (approvalFlow.HoU == currentUserId) return "HoU";
            if (approvalFlow.HoD == currentUserId) return "HoD";
            if (approvalFlow.Manager == currentUserId) return "Manager";
            if (approvalFlow.HR == currentUserId) return "HR";

            return "Unknown: Not an assigned approver";
        }

        private string AppendUpdateLog(string? existingLogJson, string newLogJson)
        {
            List<OtUpdateLog> logs;
            if (!string.IsNullOrEmpty(existingLogJson))
            {
                try
                {
                    logs = JsonConvert.DeserializeObject<List<OtUpdateLog>>(existingLogJson);
                    if (logs == null) logs = new List<OtUpdateLog>();
                }
                catch
                {
                    logs = new List<OtUpdateLog>();
                }
            }
            else
            {
                logs = new List<OtUpdateLog>();
            }

            var newLogEntry = JsonConvert.DeserializeObject<OtUpdateLog>(newLogJson);
            if (newLogEntry != null)
            {
                logs.Add(newLogEntry);
            }

            return JsonConvert.SerializeObject(logs);
        }

        private TimeSpan? ParseTimeStringToTimeSpan(string? timeString)
        {
            if (string.IsNullOrEmpty(timeString))
            {
                return null;
            }
            if (TimeSpan.TryParse(timeString, out TimeSpan result))
            {
                return result;
            }
            return null;
        }

        #endregion

        #region OT Review/ OT Record PDF Excel
        [HttpGet("GetOvertimePdfByStatusId/{statusId}")]
        public IActionResult GetOvertimePdfByStatusId(int statusId)
        {
            var otStatus = _centralDbContext.Otstatus.FirstOrDefault(s => s.StatusId == statusId);
            if (otStatus == null)
                return NotFound("OT status not found.");

            var user = _centralDbContext.Users
                .Include(u => u.Department)
                .FirstOrDefault(u => u.Id == otStatus.UserId);
            if (user == null)
                return NotFound("User not found.");

            var userRate = _centralDbContext.Rates
                .Where(r => r.UserId == user.Id)
                .OrderByDescending(r => r.LastUpdated)
                .FirstOrDefault()?.RateValue ?? 0m;

            var otRecords = _centralDbContext.Otregisters
                .Include(o => o.Stations)
                .Where(o => o.StatusId == statusId)
                .ToList();

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

            byte[]? logoImage = null;
            var logoPath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "images", "logo.jpg");
            if (System.IO.File.Exists(logoPath))
            {
                logoImage = System.IO.File.ReadAllBytes(logoPath);
            }

            var currentLoggedInUserId = GetCurrentLoggedInUserId();

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

            // Determine if the current logged-in user is HoU, HoD, or Manager for the OT user
            bool hideSalaryDetails = false;
            if (userSetting?.Approvalflow != null)
            {
                if (userSetting.Approvalflow.HoU == currentLoggedInUserId ||
                    userSetting.Approvalflow.HoD == currentLoggedInUserId ||
                    userSetting.Approvalflow.Manager == currentLoggedInUserId)
                {
                    hideSalaryDetails = true;
                }
            }


            string? flexiHour = userSetting?.FlexiHour?.FlexiHour;

            var approvedSignatures = new List<ApprovalSignatureData>();

            var approvalFlow = userSetting?.Approvalflow;

            if (approvalFlow != null)
            {

                var approvalStages = new List<(int? approverId, string statusField, DateTime? submitDate, UserModel? approverUser)>
                {
                    (approvalFlow.HoU, otStatus.HouStatus, otStatus.HouSubmitDate, _centralDbContext.Users.FirstOrDefault(u => u.Id == approvalFlow.HoU)),
                    (approvalFlow.HoD, otStatus.HodStatus, otStatus.HodSubmitDate, _centralDbContext.Users.FirstOrDefault(u => u.Id == approvalFlow.HoD)),
                    (approvalFlow.Manager, otStatus.ManagerStatus, otStatus.ManagerSubmitDate, _centralDbContext.Users.FirstOrDefault(u => u.Id == approvalFlow.Manager)),
                    (approvalFlow.HR, otStatus.HrStatus, otStatus.HrSubmitDate, _centralDbContext.Users.FirstOrDefault(u => u.Id == approvalFlow.HR))
                };

                foreach (var stage in approvalStages
                    .Where(s => s.approverUser != null && s.statusField == "Approved" && s.submitDate.HasValue)
                    .OrderBy(s => s.submitDate))
                {
                    byte[]? signatureImageBytes = null;

                    var staffSign = _centralDbContext.Staffsign
                                                .FirstOrDefault(ss => ss.UserId == stage.approverId.Value);

                    approvedSignatures.Add(new ApprovalSignatureData
                    {
                        ApproverName = stage.approverUser.FullName,
                        SignatureImage = signatureImageBytes,
                        ApprovedDate = stage.submitDate
                    });
                }
            }

            var pdfGenerator = new OvertimePDF(_centralDbContext);
            // Pass the new hideSalaryDetails flag to the PDF generator
            var stream = pdfGenerator.GenerateOvertimeTablePdf(otRecords, user, userRate, selectedMonth, logoImage, hideSalaryDetails, flexiHour, approvedSignatures);

            string fileName = $"OvertimeReport_{user.FullName}_{DateTime.Now:yyyyMMdd}.pdf";
            return File(stream.ToArray(), "application/pdf", fileName);
        }

        [HttpGet("GetUserOvertimePdf/{userId}/{month}/{year}")]
        public IActionResult GetUserOvertimePdf(int userId, int month, int year)
        {
            var user = _centralDbContext.Users
                .Include(u => u.Department)
                .FirstOrDefault(u => u.Id == userId);

            if (user == null)
                return NotFound("User not found.");

            var userRate = _centralDbContext.Rates
                .Where(r => r.UserId == user.Id)
                .OrderByDescending(r => r.LastUpdated)
                .FirstOrDefault()?.RateValue ?? 0m;

            var otRecords = _centralDbContext.Otregisters
                .Include(o => o.Stations)
                .Where(o => o.UserId == userId && o.OtDate.Month == month && o.OtDate.Year == year)
                .Select(o => new OtRegisterModel
                {
                    OtDate = o.OtDate,
                    OfficeFrom = o.OfficeFrom,
                    OfficeTo = o.OfficeTo,
                    OfficeBreak = o.OfficeBreak,
                    AfterFrom = o.AfterFrom,
                    AfterTo = o.AfterTo,
                    AfterBreak = o.AfterBreak,
                    StationId = o.StationId,
                    Stations = o.Stations,
                    OtDescription = o.OtDescription,
                    OtDays = o.OtDays
                })
                .ToList();

            DateTime? selectedMonth = new DateTime(year, month, 1);

            byte[]? logoImage = null;
            var logoPath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "images", "logo.jpg");
            if (System.IO.File.Exists(logoPath))
            {
                logoImage = System.IO.File.ReadAllBytes(logoPath);
            }

            var flexiHour = _centralDbContext.Hrusersetting
                .Include(us => us.FlexiHour)
                .FirstOrDefault(us => us.UserId == userId)?.FlexiHour?.FlexiHour;

            var pdfGenerator = new OvertimePDF(_centralDbContext);
            var stream = pdfGenerator.GenerateSimpleOvertimeTablePdf(otRecords, user, userRate, selectedMonth, logoImage, flexiHour);

            string fileName = $"OvertimeReport_{user.FullName}_{year}_{month}.pdf";
            return File(stream.ToArray(), "application/pdf", fileName);
        }

        [HttpGet("GetOvertimeExcelByStatusId/{statusId}")]
        public IActionResult GetOvertimeExcelByStatusId(int statusId)
        {
            var otStatus = _centralDbContext.Otstatus.FirstOrDefault(s => s.StatusId == statusId);
            if (otStatus == null)
                return NotFound("OT status not found.");

            var user = _centralDbContext.Users
                .Include(u => u.Department)
                .FirstOrDefault(u => u.Id == otStatus.UserId);
            if (user == null)
                return NotFound("User not found.");

            var userRate = _centralDbContext.Rates
                .Where(r => r.UserId == user.Id)
                .OrderByDescending(r => r.LastUpdated)
                .FirstOrDefault()?.RateValue ?? 0m;

            var otRecords = _centralDbContext.Otregisters
                .Include(o => o.Stations)
                .Where(o => o.StatusId == statusId)
                .ToList();

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

            var currentLoggedInUserId = GetCurrentLoggedInUserId();

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

            bool isHoU = false;
            bool isHoD = false; // Initialize isHoD
            bool isManager = false; // Initialize isManager

            if (userSetting?.Approvalflow != null)
            {
                if (userSetting.Approvalflow.HoU == currentLoggedInUserId)
                {
                    isHoU = true;
                }
                if (userSetting.Approvalflow.HoD == currentLoggedInUserId) // Check if current user is HoD
                {
                    isHoD = true;
                }
                if (userSetting.Approvalflow.Manager == currentLoggedInUserId) // Check if current user is Manager
                {
                    isManager = true;
                }
            }

            string? flexiHour = userSetting?.FlexiHour?.FlexiHour;

            var excelGenerator = new OvertimeExcel(_centralDbContext, _env);

            var logoPath = Path.Combine(_env.WebRootPath, "images", "logo.jpg");
            byte[]? logoImage = System.IO.File.Exists(logoPath) ? System.IO.File.ReadAllBytes(logoPath) : null;

            var stream = excelGenerator.GenerateOvertimeExcel(
                otRecords,
                user,
                userRate,
                selectedMonth,
                isHoU,
                isHoD,     // Pass isHoD
                isManager, // Pass isManager
                flexiHour,
                logoImage,
                isSimplifiedExport: false,
                otStatus
            );

            string fileName = $"OvertimeReport_{user.FullName}_{DateTime.Now:yyyyMMdd}.xlsx";
            return File(stream.ToArray(), "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", fileName);
        }

        [HttpGet("GenerateUserOvertimeExcel/{userId}/{month}/{year}")]
        public IActionResult GenerateUserOvertimeExcel(int userId, int month, int year)
        {
            try
            {
                var user = _centralDbContext.Users
                    .Include(u => u.Department)
                    .FirstOrDefault(u => u.Id == userId);

                if (user == null)
                    return NotFound("User not found.");

                var userRate = _centralDbContext.Rates
                    .Where(r => r.UserId == user.Id)
                    .OrderByDescending(r => r.LastUpdated)
                    .FirstOrDefault()?.RateValue ?? 0m;

                var userSetting = _centralDbContext.Hrusersetting
                    .Include(us => us.FlexiHour)
                    .Include(us => us.Approvalflow) // Include Approvalflow to check roles
                    .FirstOrDefault(us => us.UserId == userId);

                string flexiHour = userSetting?.FlexiHour?.FlexiHour;

                var startDate = new DateTime(year, month, 1);
                var endDate = startDate.AddMonths(1);

                var otRecords = _centralDbContext.Otregisters
                    .Include(o => o.Stations)
                    .Where(o => o.UserId == userId && o.OtDate >= startDate && o.OtDate < endDate)
                    .ToList();

                var currentLoggedInUserId = GetCurrentLoggedInUserId();

                bool isHoU = false;
                bool isHoD = false; // Initialize isHoD
                bool isManager = false; // Initialize isManager

                if (userSetting?.Approvalflow != null)
                {
                    if (userSetting.Approvalflow.HoU == currentLoggedInUserId)
                    {
                        isHoU = true;
                    }
                    if (userSetting.Approvalflow.HoD == currentLoggedInUserId) // Check if current user is HoD
                    {
                        isHoD = true;
                    }
                    if (userSetting.Approvalflow.Manager == currentLoggedInUserId) // Check if current user is Manager
                    {
                        isManager = true;
                    }
                }

                var excelGenerator = new OvertimeExcel(_centralDbContext, _env);

                var logoPath = Path.Combine(_env.WebRootPath, "images", "logo.jpg");
                byte[]? logoImage = System.IO.File.Exists(logoPath) ? System.IO.File.ReadAllBytes(logoPath) : null;

                var stream = excelGenerator.GenerateOvertimeExcel(
                    otRecords,
                    user,
                    userRate,
                    startDate,
                    isHoU,
                    isHoD,     // Pass isHoD
                    isManager, // Pass isManager
                    flexiHour: flexiHour,
                    logoImage: logoImage,
                    isSimplifiedExport: true 
                );

                string fileName = $"OvertimeReport_{user.FullName}_{month}_{year}.xlsx";
                return File(stream.ToArray(), "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", fileName);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error generating user overtime Excel");
                return StatusCode(500, "Error generating Excel file");
            }
        }
        #endregion
    }
}