using Azure.Core; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using Mono.TextTemplating; using Newtonsoft.Json; using PSTW_CentralSystem.Areas.OTcalculate.Models; using PSTW_CentralSystem.Controllers.API; using PSTW_CentralSystem.Controllers.API.Inventory; using PSTW_CentralSystem.DBContext; using PSTW_CentralSystem.Models; using System.ComponentModel.Design; using System.Data; using System; using System.Threading.Tasks; using System.Diagnostics; using System.Reflection; using static System.Collections.Specialized.BitVector32; using System.Security.Claims; using Microsoft.VisualStudio.Web.CodeGenerators.Mvc.Templates.BlazorIdentity.Pages; using Microsoft.AspNetCore.Mvc.Rendering; using QuestPDF.Fluent; using QuestPDF.Helpers; using QuestPDF.Infrastructure; using PSTW_CentralSystem.Areas.OTcalculate.Services; namespace PSTW_CentralSystem.Controllers.API { [ApiController] [Route("[controller]")] public class OvertimeAPI : Controller { private readonly ILogger _logger; private readonly CentralSystemContext _centralDbContext; private readonly UserManager _userManager; private readonly OvertimePdfService _pdfService; public OvertimeAPI(ILogger logger, CentralSystemContext centralDbContext, UserManager userManager, OvertimePdfService pdfService) { _logger = logger; _centralDbContext = centralDbContext; _userManager = userManager; _pdfService = pdfService; } #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 updateDates = new { rateUpdateDate = latestRateUpdate.HasValue ? latestRateUpdate.Value.ToString("dd MMMM yyyy") : null, calendarUpdateDate = latestCalendarUpdate.HasValue ? latestCalendarUpdate.Value.ToString("dd MMMM yyyy") : null }; return Json(updateDates); } catch (Exception ex) { return BadRequest(ex.Message); } } #endregion #region Rate [HttpPost("UpdateRates")] public async Task UpdateRate([FromBody] List rates) { if (!ModelState.IsValid) { return BadRequest(ModelState); } try { foreach (var rate in rates) { 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 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 Calendar [HttpGet("GetStatesName")] public async Task 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 UpdateHoliday([FromBody] List 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 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 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 UpdateWeekend([FromBody] List 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) { // Corrected: Updating WeekendId existingState.WeekendId = state.WeekendId; _centralDbContext.States.Update(existingState); } else { // Ensure new states are added correctly _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 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 OtRegister [HttpGet("GetStationsByDepartment")] public IActionResult GetStationsByDepartment() { var stations = _centralDbContext.Stations .Where(s => s.DepartmentId == 2) .Select(s => new { s.StationId, StationName = s.StationName ?? "Unnamed Station" }) .ToList(); return Ok(stations); } [HttpPost("AddOvertime")] public async Task AddOvertimeAsync([FromBody] OtRegisterModel model) { _logger.LogInformation("AddOvertimeAsync called."); if (model == null) { _logger.LogError("Model is null."); return BadRequest("Invalid data."); } try { _logger.LogInformation($"Received model: {System.Text.Json.JsonSerializer.Serialize(model)}"); if (model.UserId == 0) { _logger.LogWarning("No user ID provided."); return BadRequest("User ID is required."); } // Convert string time values to TimeSpan before saving model.OfficeFrom = model.GetOfficeFrom(); model.OfficeTo = model.GetOfficeTo(); model.OutsideFrom = model.GetOutsideFrom(); model.OutsideTo = model.GetOutsideTo(); _logger.LogInformation($"Time spans parsed successfully."); _centralDbContext.Otregisters.Add(model); await _centralDbContext.SaveChangesAsync(); _logger.LogInformation("Overtime registered successfully."); return Ok(new { message = "Overtime registered successfully." }); } catch (Exception ex) { _logger.LogError(ex, "Error registering overtime."); return StatusCode(500, "An error occurred while saving overtime."); } } #endregion #region Ot Records [HttpGet("GetUserOvertimeRecords/{userId}")] public IActionResult GetUserOvertimeRecords(int userId) { try { var records = _centralDbContext.Otregisters .Where(o => o.UserId == userId) .Select(o => new { o.OvertimeId, o.OtDate, o.OfficeFrom, o.OfficeTo, o.OfficeBreak, o.OutsideFrom, o.OutsideTo, o.OutsideBreak, o.StationId, StationName = o.Stations != null ? o.Stations.StationName : "N/A", o.OtDescription, o.OtDays, o.PDFBase64, o.UserId }) .OrderByDescending(o => o.OtDate) .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) return NotFound("Overtime record not found."); _centralDbContext.Otregisters.Remove(record); _centralDbContext.SaveChanges(); 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."); } } [HttpPost("SaveOvertimeRecordsWithPdf")] public async Task SaveOvertimeRecordsWithPdf([FromBody] List records) { if (!ModelState.IsValid) { return BadRequest(ModelState); } try { _logger.LogInformation("SaveOvertimeRecordsWithPdf called with {RecordCount} records", records.Count); foreach (var record in records) { _logger.LogDebug("Processing record with OvertimeId: {OvertimeId}", record.OvertimeId); var existingRecord = await _centralDbContext.Otregisters.FindAsync(record.OvertimeId); if (existingRecord != null) { _logger.LogDebug("Updating existing record with OvertimeId: {OvertimeId}", record.OvertimeId); existingRecord.PDFBase64 = record.PDFBase64; _centralDbContext.Otregisters.Update(existingRecord); } else { _logger.LogWarning("Record with OvertimeId: {OvertimeId} not found, adding new", record.OvertimeId); _centralDbContext.Otregisters.Add(record); } } await _centralDbContext.SaveChangesAsync(); _logger.LogInformation("Successfully saved {RecordCount} overtime records with PDFs", records.Count); return Ok("Overtime records updated with PDFs."); } catch (Exception ex) { _logger.LogError(ex, "Error saving overtime records with PDFs"); return StatusCode(500, "An error occurred while saving records."); } } [HttpGet("GenerateOvertimePdf")] public IActionResult GenerateOvertimePdf(int month, int year) { var userIdString = User.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier)?.Value; if (string.IsNullOrEmpty(userIdString) || !int.TryParse(userIdString, out int userId)) { return Unauthorized(); } // Get user and department info var user = _centralDbContext.Users .Include(u => u.Department) .FirstOrDefault(u => u.Id == userId); if (user == null) return NotFound("User not found"); var userFullName = $"{user.FullName}"; var departmentId = user.departmentId ?? 0; var departmentName = user.Department?.DepartmentName ?? "N/A"; var records = _centralDbContext.Otregisters .Include(o => o.Stations) .Where(o => o.UserId == userId && o.OtDate.Month == month && o.OtDate.Year == year) .ToList(); // Optional: load logo image as byte array 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 stream = _pdfService.GenerateOvertimeTablePdf(records, departmentId, userFullName, departmentName, logoImage); return File(stream, "application/pdf", $"OvertimeRecords_{year}_{month}.pdf"); } #endregion } }