using Core.Interfaces.Stock;
using Documents.Interfaces;
using Documents.Models;
using Domain.Dtos.Stock;
using Domain.Entities;
using Domain.Generics;
using Microsoft.AspNetCore.Mvc;
using System.Reflection;
namespace phronCare.API.Controllers.Stock
{
[Route("api/[controller]")]
[ApiController]
public class ExpeditionController : ControllerBase
{
private readonly IExpeditionDom _expeditionService; // ← este es _expeditionService
private readonly IDocumentTemplateService _documentTemplateService;
public ExpeditionController(
IDocumentTemplateService documentTemplateService,
IExpeditionDom expeditionService)
{
_documentTemplateService = documentTemplateService
?? throw new ArgumentNullException(nameof(documentTemplateService));
_expeditionService = expeditionService
?? throw new ArgumentNullException(nameof(expeditionService));
}
///
/// Busca expediciones con filtros y paginación.
/// Filtros: número, estado, fechas de emisión, ubicación (opcional).
///
[HttpGet("search")]
public async Task>> Search(
[FromQuery] string? expeditionNumber,
[FromQuery] string? status,
[FromQuery] DateTime? issueDateFrom,
[FromQuery] DateTime? issueDateTo,
[FromQuery] int? locationId,
[FromQuery] int page = 1,
[FromQuery] int pageSize = 50)
{
try
{
var result = await _expeditionService.SearchAsync(
expeditionNumber,
status,
issueDateFrom,
issueDateTo,
locationId,
page,
pageSize
);
return Ok(result);
}
catch (Exception ex)
{
var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
return StatusCode(500, $"{methodName} Message: {ex.Message}");
}
}
#region Endpoint de emision de expedicion (encabezado + detalles)
[HttpPost("createfull")]
public async Task CreateFullExpedition([FromBody] CreateFullExpeditionRequest request)
{
try
{
if (request == null || request.Expedition == null)
return BadRequest("El payload no puede contener elementos nulos.");
// Delegamos al service, que ahora arma el grafo y llama al repo atómico
var (id, number) = await _expeditionService.CreateAndIssueAsync(
request.Expedition,
request.Expedition.PhLsmExpeditionDetails, // detalles vienen dentro, igual que en Quotes
request.FormSeriesId);
// <<< Simetría absoluta con QuoteController: objeto anónimo >>>
return Ok(new { Success = true, Id = id, ExpeditionNumber = number });
}
catch (InvalidOperationException ex)
{
return BadRequest($"Error de negocio: {ex.Message}");
}
catch (Exception ex)
{
return StatusCode(500, $"Ocurrió un error interno: {ex.Message}");
}
}
#endregion
///
/// Genera y devuelve un archivo PDF correspondiente al presupuesto especificado por su ID.
///
[HttpGet("{id}/pdf")]
public async Task GetQuotePdf(int id)
{
var expedition = await _expeditionService.GetDtoByIdAsync(id);
if (expedition == null)
return NotFound($"Expedicion con ID {id} no encontrado.");
var pdfBytes = await _documentTemplateService.GenerateDocumentAsync(new DocumentGenerationRequest
{
Model = expedition,
DocumentType = DocumentType.Expedition
});
return File(pdfBytes, "application/pdf", $"Expedicion_{expedition.Expeditionnumber}.pdf");
}
}
public class CreateFullExpeditionRequest
{
public ELSExpeditionHeader Expedition { get; set; } = default!;
public int FormSeriesId { get; set; }
}
}