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));
        }
        /// <summary>
        /// Busca expediciones con filtros y paginación.
        /// Filtros: número, estado, fechas de emisión, ubicación (opcional).
        /// </summary>
        [HttpGet("search")]
        public async Task<ActionResult<PagedResult<ExpeditionDto>>> 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}");
            }
        }

        // GET /api/expedition/{id}
        [HttpGet("{id:int}")]
        [ProducesResponseType(typeof(ExpeditionDto), StatusCodes.Status200OK)]
        [ProducesResponseType(StatusCodes.Status404NotFound)]
        public async Task<ActionResult<ExpeditionDto>> GetById(int id)
        {
            var dto = await _expeditionService.GetDtoByIdAsync(id);
            if (dto is null) return NotFound($"Expedición con ID {id} no encontrada.");
            return Ok(dto);
        }

        // (opcional) GET /api/expedition/summary/{expeditionNumber}
        [HttpGet("summary/{expeditionNumber}")]
        [ProducesResponseType(typeof(ExpeditionDto), StatusCodes.Status200OK)]
        [ProducesResponseType(StatusCodes.Status404NotFound)]
        public async Task<ActionResult<ExpeditionDto>> GetByNumber(string expeditionNumber)
        {
            var dto = await _expeditionService.GetDtoByExpeditionNumberAsync(expeditionNumber);
            if (dto is null) return NotFound($"No se encontró expedición {expeditionNumber}.");
            return Ok(dto);
        }
        #region Endpoint de emision de expedicion (encabezado + detalles)
        [HttpPost("createfull")]
        public async Task<IActionResult> 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
        /// <summary>  
        /// Genera y devuelve un archivo PDF correspondiente al presupuesto especificado por su ID.  
        /// </summary>
        [HttpGet("{id}/pdf")]
        public async Task<IActionResult> 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");
        }
        
        [HttpPost("exportfiltered")]
        public async Task<IActionResult> ExportFiltered([FromBody] ExpeditionSearchParams searchParams)
        {
            try
            {
                var file = await _expeditionService.ExportFilteredToExcelAsync(searchParams);
                return File(file,
                    "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
                    "Expediciones.xlsx");
            }
            catch (Exception ex)
            {
                return BadRequest(ex.Message);
            }
        }
        
        [HttpPost("{id:int}/mark-in-transit")]
        public async Task<IActionResult> MarkInTransit(int id)
        {
            try
            {
                await _expeditionService.MarkInTransitAsync(id);
                return Ok(new { Success = true, Message = "La expedición pasó a estado 'En tránsito' correctamente." });
            }
            catch (KeyNotFoundException ex)
            {
                return NotFound(ex.Message);
            }
            catch (InvalidOperationException ex)
            {
                return BadRequest(ex.Message);
            }
            catch (ArgumentException ex)
            {
                return BadRequest(ex.Message);
            }
            catch (Exception ex)
            {
                return StatusCode(500, $"Ocurrió un error interno: {ex.Message}");
            }
        }
    }
    public class CreateFullExpeditionRequest
    {
        public ELSExpeditionHeader Expedition { get; set; } = default!;
        public int FormSeriesId { get; set; }
    }
}
