using Domain.Dtos;
using Domain.Dtos.Stock;
using Domain.Entities;
using Domain.Generics;
using Microsoft.JSInterop;
using System.Net.Http.Json;
using System.Reflection;
using System.Text;
using System.Text.Json;

namespace phronCare.UIBlazor.Services.Stock.Expeditions
{
    public class ExpeditionService: IExpeditionService
    {
        private readonly IJSRuntime _js; //Todavia no se utiliza pero eventualmente para exportaciones seguramente./
        private readonly HttpClient _http;
        public ExpeditionService(HttpClient http, IJSRuntime js)
        {
            _js = js;
            _http = http;
        }

        /// <summary>
        /// Búsqueda de expediciones con filtros y paginación.
        /// Filtros típicos: número, estado, fechas, ubicación (opcional).
        /// </summary>
        /// <summary>Buscar expediciones (simétrico a QuoteService.SearchAsync)</summary>
        public async Task<PagedResult<ExpeditionDto>> SearchAsync(
            string? expeditionNumber = null,
            string? status = null,
            DateTime? issueDateFrom = null,
            DateTime? issueDateTo = null,
            int? locationId = null,
            int page = 1,
            int pageSize = 10)
        {
            var query = new List<string>();
            void Add(string key, string? val)
            {
                if (!string.IsNullOrWhiteSpace(val))
                    query.Add($"{key}={Uri.EscapeDataString(val)}");
            }

            Add("expeditionNumber", expeditionNumber);
            Add("status", status);
            Add("issueDateFrom", issueDateFrom?.ToString("o"));
            Add("issueDateTo", issueDateTo?.ToString("o"));
            Add("locationId", locationId?.ToString());
            Add("page", page.ToString());
            Add("pageSize", pageSize.ToString());

            // FIX: controller es singular => /api/expedition/search
            var url = "/api/expedition/search";
            if (query.Any()) url += "?" + string.Join("&", query);

            var result = await _http.GetFromJsonAsync<PagedResult<ExpeditionDto>>(url);
            return result!;
        }
        
        /// <summary>
        /// Obtiene un presupuesto por QuoteNumber.
        /// </summary>
        public async Task<QuoteDto?> GetQuoteByNumberAsync(string quoteNumber)
        {
            try
            {
                var result = await _http.GetFromJsonAsync<QuoteDto?>($"api/quote/summary/{quoteNumber}");
                return result;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error al obtener QuoteDto por QuoteNumber: {ex.Message}");
                return null;
            }
        }
        
        /// <summary>
        /// Envía el header + details de la expedición junto con el formSeriesId
        /// y recibe el número de expedición generado o un mensaje de error.
        /// </summary>
        public async Task<CreateExpeditionResult> CreateAndIssueAsync(
            ELSExpeditionHeader header,
            IEnumerable<ELSExpeditionDetail> details,
            int formSeriesId)
        {
            // 1) Poner los ítems dentro del header
            header.PhLsmExpeditionDetails = details?.ToList() ?? new List<ELSExpeditionDetail>();

            var request = new CreateFullExpeditionRequest
            {
                Expedition = header,
                FormSeriesId = formSeriesId
            };

            var response = await _http.PostAsJsonAsync("/api/expedition/createfull", request);

            if (!response.IsSuccessStatusCode)
            {
                var serverMessage = await response.Content.ReadAsStringAsync();
                return new CreateExpeditionResult
                {
                    Success = false,
                    ErrorMessage = serverMessage
                };
            }

            var result = await response.Content.ReadFromJsonAsync<CreateExpeditionResult>();
            return result ?? new CreateExpeditionResult { Success = false, ErrorMessage = "Respuesta vacía del servidor." };
        }

        /// <summary>
        /// Obtiene la expedición completa por ID para visualización (drawer/pantalla de detalle).
        /// </summary>
        public async Task<ExpeditionDto?> GetDtoByIdAsync(int id)
        {
            try
            {
                var dto = await _http.GetFromJsonAsync<ExpeditionDto>($"/api/expedition/{id}");
                return dto;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error al obtener ExpeditionDto por ID: {ex.Message}");
                return null;
            }
        }

        /// <summary>
        /// Descarga el PDF de la expedición en el navegador usando saveAsFile (base64).
        /// </summary>
        public async Task ExportPdfAsync(int expeditionId, string expeditionNumber)
        {
            try
            {
                var response = await _http.GetAsync($"/api/expedition/{expeditionId}/pdf");

                if (!response.IsSuccessStatusCode)
                {
                    var error = await response.Content.ReadAsStringAsync();
                    throw new Exception($"Error al generar PDF: {error}");
                }

                var bytes = await response.Content.ReadAsByteArrayAsync();
                var base64 = Convert.ToBase64String(bytes);
                var fileName = $"{expeditionNumber}.pdf";

                await _js.InvokeVoidAsync("saveAsFile", fileName, base64);
            }
            catch (Exception ex)
            {
                var message = ex.Message ?? "No message";
                throw new Exception($"ExportPdfAsync: {message}", ex);
            }
        }

        public async Task ExportFilteredAsync(LSProductSearchParams searchParams)
        {
            try
            {
                var content = new StringContent(JsonSerializer.Serialize(searchParams), Encoding.UTF8, "application/json");
                var response = await _http.PostAsync("api/Expedition/exportfiltered", content);

                //response.EnsureSuccessStatusCode();
                if (!response.IsSuccessStatusCode)
                {
                    var errorContent = await response.Content.ReadAsStringAsync();
                    throw new Exception(errorContent);
                }
                var bytes = await response.Content.ReadAsByteArrayAsync();
                var base64 = Convert.ToBase64String(bytes);
                var timestamp = DateTime.Now.ToString("yyyyMMddHHmm");
                var fileName = $"{timestamp}_expeditions.xlsx";
                await _js.InvokeVoidAsync("saveAsFile", fileName, base64);
            }
            catch (Exception ex)
            {
                var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
                var message = ex.Message ?? "No message provided";
                throw new Exception($"{message}", ex);
            }
        }
        public async Task MarkInTransitAsync(int expeditionId)
        {
            if (expeditionId <= 0)
                throw new ArgumentException("El identificador de la expedición no es válido.");

            var response = await _http.PostAsync($"api/expedition/{expeditionId}/mark-in-transit", null);

            if (!response.IsSuccessStatusCode)
            {
                var message = await response.Content.ReadAsStringAsync();

                if (string.IsNullOrWhiteSpace(message))
                    message = "No se pudo pasar la expedición a 'En tránsito'.";

                throw new Exception(message);
            }
        }
    }

    /// <summary>
    /// Contrato de request.
    /// </summary>
    public class CreateFullExpeditionRequest
    {
        public ELSExpeditionHeader Expedition { get; set; } = default!;
        public int FormSeriesId { get; set; }
    }

    /// <summary>
    /// Resultado del create/issue.
    /// </summary>
    public class CreateExpeditionResult
    {
        public bool Success { get; set; }
        public int Id { get; set; }
        public string ExpeditionNumber { get; set; } = string.Empty;
        public string ErrorMessage { get; set; } = string.Empty;
    }

}