using Api.SeaHavenIndustries.DTOs; using Data.SeaHavenIndustries; using Data.SeaHavenIndustries.Enums; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using SeaHaven.Services.DTOs; using SeaHaven.Services.Exceptions; using SeaHaven.Services.Interfaces; using System.Security.Claims; namespace Api.SeaHavenIndustries.Controllers { [Authorize] [ApiController] [Route("api/WorkOrder")] [Route("api/workorders")] public class WorkOrderCompletionController : Controller { private readonly IWorkOrderCompletionService _workOrderCompletionService; private readonly IFileStoragePort _fileStorage; public WorkOrderCompletionController( IWorkOrderCompletionService workOrderCompletionService, IFileStoragePort fileStorage) { _workOrderCompletionService = workOrderCompletionService; _fileStorage = fileStorage; } [HttpGet("completion-templates")] public async Task GetCompletionTemplates( [FromQuery] string? serviceKey = null, [FromQuery] WorkOrderType? workOrderType = null) { var templates = await _workOrderCompletionService.GetTemplatesAsync(serviceKey, workOrderType); return Ok(templates); } [HttpGet("completion-templates/{id:int}")] public async Task GetCompletionTemplate(int id) { var template = await _workOrderCompletionService.GetTemplateByIdAsync(id); if (template == null) return NotFound(new Response { Status = "Error", Message = "Template not found." }); return Ok(template); } [Authorize(Roles = "Admin")] [HttpPost("completion-templates")] public async Task CreateCompletionTemplate([FromBody] CompletionDocTemplateCreateDto request) { try { var created = await _workOrderCompletionService.CreateTemplateAsync(request); return Ok(created); } catch (WorkOrderBoardValidationException ex) { return UnprocessableEntity(new WorkOrderBoardValidationErrorDto { Code = ex.Code, Message = ex.Message }); } } [Authorize(Roles = "Admin")] [HttpPut("completion-templates/{id:int}")] public async Task UpdateCompletionTemplate(int id, [FromBody] CompletionDocTemplateCreateDto request) { try { var updated = await _workOrderCompletionService.UpdateTemplateAsync(id, request); return Ok(updated); } catch (WorkOrderBoardValidationException ex) when (ex.Code == "NotFound") { return NotFound(new WorkOrderBoardValidationErrorDto { Code = ex.Code, Message = ex.Message }); } catch (WorkOrderBoardValidationException ex) { return UnprocessableEntity(new WorkOrderBoardValidationErrorDto { Code = ex.Code, Message = ex.Message }); } } [Authorize(Roles = "Admin")] [HttpDelete("completion-templates/{id:int}")] public async Task DeleteCompletionTemplate(int id) { try { await _workOrderCompletionService.DeleteTemplateAsync(id); return NoContent(); } catch (WorkOrderBoardValidationException ex) when (ex.Code == "NotFound") { return NotFound(new WorkOrderBoardValidationErrorDto { Code = ex.Code, Message = ex.Message }); } } [HttpPost("{id:int}/completion-doc")] [RequestSizeLimit(30_000_000)] public async Task UploadCompletionDoc( int id, [FromForm] IFormFile file, [FromForm] string? signOffName = null, [FromForm] string? signOffSignature = null, [FromForm] string? workOrderVersion = null) { if (file == null || file.Length == 0) return BadRequest(new Response { Status = "Error", Message = "file is required." }); string? fileUrl = null; try { var actorId = User.FindFirstValue(ClaimTypes.NameIdentifier); await _workOrderCompletionService.EnsureCanUploadCompletionDocAsync(id, User, actorId); fileUrl = await _fileStorage.SaveFileAsync(file); var result = await _workOrderCompletionService.UploadCompletionDocAsync( id, new WorkOrderCompletionDocUploadDto { SignOffName = signOffName, SignOffSignature = signOffSignature, WorkOrderVersion = workOrderVersion }, fileUrl, User, actorId); return Ok(result); } catch (WorkOrderBoardValidationException ex) when (ex.Code is "NotFound") { TryCompensateUpload(fileUrl); return NotFound(new WorkOrderBoardValidationErrorDto { Code = ex.Code, Message = ex.Message }); } catch (WorkOrderBoardValidationException ex) when (ex.Code is "Forbidden") { TryCompensateUpload(fileUrl); return StatusCode(StatusCodes.Status403Forbidden, new WorkOrderBoardValidationErrorDto { Code = ex.Code, Message = ex.Message }); } catch (WorkOrderBoardValidationException ex) when (ex.Code is "ConcurrencyConflict") { TryCompensateUpload(fileUrl); return Conflict(new WorkOrderBoardValidationErrorDto { Code = ex.Code, Message = ex.Message }); } catch (WorkOrderBoardValidationException ex) { TryCompensateUpload(fileUrl); return UnprocessableEntity(new WorkOrderBoardValidationErrorDto { Code = ex.Code, Message = ex.Message }); } } private void TryCompensateUpload(string? fileUrl) { if (!string.IsNullOrWhiteSpace(fileUrl)) _fileStorage.TryDelete(fileUrl); } } }