using Core.Interfaces;
using Domain.Dtos.Sales;
using Domain.Generics;
using Microsoft.AspNetCore.Mvc;
using System.Reflection;

namespace phronCare.API.Controllers.Sales
{
    [Route("api/[controller]")]
    [ApiController]
    public class SalesDocumentController : ControllerBase
    {
        private readonly ISalesDocumentDom _salesDocumentService;

        public SalesDocumentController(ISalesDocumentDom salesDocumentService)
        {
            _salesDocumentService = salesDocumentService ?? throw new ArgumentNullException(nameof(salesDocumentService));
        }

        [HttpGet("search")]
        public async Task<ActionResult<PagedResult<SalesDocumentSummaryDto>>> Search(
            [FromQuery] int? customerId,
            [FromQuery] string? customerText,
            [FromQuery] int? quoteId,
            [FromQuery] int? documentType,
            [FromQuery] int? status,
            [FromQuery] DateTime? issueDateFrom,
            [FromQuery] DateTime? issueDateTo,
            [FromQuery] int page = 1,
            [FromQuery] int pageSize = 50)
        {
            try
            {
                var result = await _salesDocumentService.SearchAsync(
                    customerId,
                    customerText,
                    quoteId,
                    documentType,
                    status,
                    issueDateFrom,
                    issueDateTo,
                    page,
                    pageSize);

                return Ok(result);
            }
            catch (Exception ex)
            {
                var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
                return StatusCode(500, $"{methodName} Message: {ex.Message}");
            }
        }

        [HttpGet("{id:int}")]
        public async Task<ActionResult<SalesDocumentDto>> GetById(int id)
        {
            try
            {
                var salesDocument = await _salesDocumentService.GetDtoByIdAsync(id);
                if (salesDocument == null)
                    return NotFound($"Sales Document con ID {id} no encontrado.");

                return Ok(salesDocument);
            }
            catch (Exception ex)
            {
                var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
                return StatusCode(500, $"{methodName} Message: {ex.Message}");
            }
        }

        [HttpGet("{id:int}/draft-preview")]
        public async Task<ActionResult<SalesDocumentDraftPreviewDto>> GetDraftPreview(int id)
        {
            try
            {
                var preview = await _salesDocumentService.GetDraftPreviewAsync(id);
                if (preview == null)
                    return NotFound($"Sales Document con ID {id} no encontrado.");

                return Ok(preview);
            }
            catch (Exception ex)
            {
                var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
                return StatusCode(500, $"{methodName} Message: {ex.Message}");
            }
        }

        [HttpPut("{id:int}/draft-review")]
        public async Task<ActionResult<SalesDocumentDraftPreviewDto>> UpdateDraftReview(int id, [FromBody] SalesDocumentDraftReviewDto request)
        {
            try
            {
                if (request == null)
                    return BadRequest("El payload no puede ser nulo.");

                var preview = await _salesDocumentService.UpdateDraftReviewAsync(id, request);
                if (preview == null)
                    return NotFound($"Sales Document con ID {id} no encontrado.");

                return Ok(preview);
            }
            catch (ArgumentException ex)
            {
                return BadRequest(ex.Message);
            }
            catch (InvalidOperationException ex)
            {
                return BadRequest(ex.Message);
            }
            catch (Exception ex)
            {
                var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
                return StatusCode(500, $"{methodName} Message: {ex.Message}");
            }
        }

        [HttpPost("{id:int}/validate")]
        public async Task<ActionResult<SalesDocumentDraftPreviewDto>> ValidateDraft(int id)
        {
            try
            {
                var preview = await _salesDocumentService.ValidateDraftAsync(id);
                if (preview == null)
                    return NotFound($"Sales Document con ID {id} no encontrado.");

                return Ok(preview);
            }
            catch (ArgumentException ex)
            {
                return BadRequest(ex.Message);
            }
            catch (InvalidOperationException ex)
            {
                return BadRequest(ex.Message);
            }
            catch (Exception ex)
            {
                var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
                return StatusCode(500, $"{methodName} Message: {ex.Message}");
            }
        }


        [HttpGet("delivery-note-candidates")]
        public async Task<ActionResult<PagedResult<SalesDocumentDeliveryNoteCandidateDto>>> SearchDeliveryNoteCandidates(
            [FromQuery] int? customerId,
            [FromQuery] string? customerText,
            [FromQuery] string? deliveryNoteNumber,
            [FromQuery] int? quoteId,
            [FromQuery] DateTime? issueDateFrom,
            [FromQuery] DateTime? issueDateTo,
            [FromQuery] int page = 1,
            [FromQuery] int pageSize = 50)
        {
            try
            {
                var result = await _salesDocumentService.SearchDeliveryNoteCandidatesAsync(
                    customerId,
                    customerText,
                    deliveryNoteNumber,
                    quoteId,
                    issueDateFrom,
                    issueDateTo,
                    page,
                    pageSize);

                return Ok(result);
            }
            catch (Exception ex)
            {
                var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
                return StatusCode(500, $"{methodName} Message: {ex.Message}");
            }
        }

        [HttpGet("delivery-note-item-candidates")]
        public async Task<ActionResult<List<SalesDocumentDeliveryNoteItemCandidateDto>>> GetDeliveryNoteItemCandidates(
            [FromQuery] List<int> deliveryNoteIds)
        {
            try
            {
                var result = await _salesDocumentService.GetDeliveryNoteItemCandidatesForSalesDocumentAsync(deliveryNoteIds);
                return Ok(result);
            }
            catch (ArgumentException ex)
            {
                return BadRequest(ex.Message);
            }
            catch (InvalidOperationException ex)
            {
                return BadRequest(ex.Message);
            }
            catch (Exception ex)
            {
                var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
                return StatusCode(500, $"{methodName} Message: {ex.Message}");
            }
        }

        [HttpPost("from-delivery-note-items")]
        public async Task<ActionResult<SalesDocumentDto>> CreateFromDeliveryNoteItems([FromBody] SalesDocumentCreateFromDeliveryNoteItemsRequest request)
        {
            try
            {
                if (request == null)
                    return BadRequest("El payload no puede ser nulo.");

                var created = await _salesDocumentService.CreateFromDeliveryNoteItemsAsync(request);
                var salesDocument = await _salesDocumentService.GetDtoByIdAsync(created.Id);

                if (salesDocument == null)
                    return StatusCode(500, $"No se pudo recuperar el Sales Document creado con ID {created.Id}.");

                return CreatedAtAction(nameof(GetById), new { id = salesDocument.Id }, salesDocument);
            }
            catch (ArgumentException ex)
            {
                return BadRequest(ex.Message);
            }
            catch (InvalidOperationException ex)
            {
                return BadRequest(ex.Message);
            }
            catch (Exception ex)
            {
                var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
                return StatusCode(500, $"{methodName} Message: {ex.Message}");
            }
        }

        [HttpPost("from-delivery-notes")]
        public async Task<ActionResult<SalesDocumentDto>> CreateFromDeliveryNotes([FromBody] SalesDocumentCreateFromDeliveryNotesRequest request)
        {
            try
            {
                if (request == null)
                    return BadRequest("El payload no puede ser nulo.");

                var created = await _salesDocumentService.CreateFromDeliveryNotesAsync(request);
                var salesDocument = await _salesDocumentService.GetDtoByIdAsync(created.Id);

                if (salesDocument == null)
                    return StatusCode(500, $"No se pudo recuperar el Sales Document creado con ID {created.Id}.");

                return CreatedAtAction(nameof(GetById), new { id = salesDocument.Id }, salesDocument);
            }
            catch (ArgumentException ex)
            {
                return BadRequest(ex.Message);
            }
            catch (InvalidOperationException ex)
            {
                return BadRequest(ex.Message);
            }
            catch (Exception ex)
            {
                var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
                return StatusCode(500, $"{methodName} Message: {ex.Message}");
            }
        }

        [HttpPost]
        public async Task<ActionResult<SalesDocumentDto>> Create([FromBody] SalesDocumentCreateRequest request)
        {
            try
            {
                if (request == null)
                    return BadRequest("El payload no puede ser nulo.");

                var created = await _salesDocumentService.CreateAsync(request);
                var salesDocument = await _salesDocumentService.GetDtoByIdAsync(created.Id);

                if (salesDocument == null)
                    return StatusCode(500, $"No se pudo recuperar el Sales Document creado con ID {created.Id}.");

                return CreatedAtAction(nameof(GetById), new { id = salesDocument.Id }, salesDocument);
            }
            catch (ArgumentException ex)
            {
                return BadRequest(ex.Message);
            }
            catch (InvalidOperationException ex)
            {
                return BadRequest(ex.Message);
            }
            catch (Exception ex)
            {
                var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
                return StatusCode(500, $"{methodName} Message: {ex.Message}");
            }
        }
    }
}
