using System.Globalization;
using Microsoft.AspNetCore.Components.Forms;
using Microsoft.JSInterop;
using RutasDBUS.Modelos.Importacion;

namespace RutasDBUS.Components.Pages;

public partial class PlanificadorRutas
{
    private const long MaxModeloHorarioUploadBytes = 250L * 1024 * 1024;

    private IReadOnlyList<ModeloHorarioDbusInfo> _modelosHorarios = Array.Empty<ModeloHorarioDbusInfo>();
    private string _modeloHorarioSeleccionadoId = "";
    private string _mensajeModelosHorarios = "";
    private bool _modelosHorariosCargando = false;
    private bool _mostrarModelosHorariosPanel = false;

    private ModeloHorarioDbusInfo? ModeloHorarioActivo =>
        _modelosHorarios.FirstOrDefault(modelo => modelo.Activo);

    private void AbrirModelosHorariosPanel()
    {
        _mostrarModelosHorariosPanel = true;
    }

    private void CerrarModelosHorariosPanel()
    {
        _mostrarModelosHorariosPanel = false;
    }

    private async Task CargarModelosHorariosAsync()
    {
        _modelosHorariosCargando = true;

        try
        {
            _modelosHorarios = await ArchivoImportacionDbus.ListarModelosAsync();
            var activo = ModeloHorarioActivo ?? _modelosHorarios.FirstOrDefault();
            _modeloHorarioSeleccionadoId = activo?.Id ?? "";
        }
        catch (Exception ex)
        {
            _modelosHorarios = Array.Empty<ModeloHorarioDbusInfo>();
            _modeloHorarioSeleccionadoId = "";
            _mensajeModelosHorarios = "No se han podido leer los modelos: " + ex.Message;
        }
        finally
        {
            _modelosHorariosCargando = false;
        }
    }

    private async Task ActualizarModelosHorariosAsync()
    {
        _mensajeModelosHorarios = "";
        await CargarModelosHorariosAsync();
        if (string.IsNullOrWhiteSpace(_mensajeModelosHorarios))
            _mensajeModelosHorarios = _modelosHorarios.Count == 0
                ? "No hay ZIPs disponibles."
                : "Lista actualizada.";
    }

    private async Task SeleccionarModeloHorarioAsync()
    {
        if (string.IsNullOrWhiteSpace(_modeloHorarioSeleccionadoId))
        {
            _mensajeModelosHorarios = "Selecciona un ZIP.";
            return;
        }

        var seleccionado = _modelosHorarios
            .FirstOrDefault(modelo => string.Equals(modelo.Id, _modeloHorarioSeleccionadoId, StringComparison.OrdinalIgnoreCase));

        if (seleccionado?.Activo == true)
        {
            _mensajeModelosHorarios = "Ese modelo ya esta cargado.";
            return;
        }

        _modelosHorariosCargando = true;
        _mensajeModelosHorarios = "Cargando modelo...";

        try
        {
            await ArchivoImportacionDbus.SeleccionarModeloAsync(_modeloHorarioSeleccionadoId);
            await RecargarModeloHorarioActivoAsync();
            await CargarModelosHorariosAsync();

            var activo = ModeloHorarioActivo;
            _mensajeModelosHorarios = activo is null
                ? "Modelo cargado."
                : "Cargado: " + activo.NombreArchivo;
        }
        catch (Exception ex)
        {
            _mensajeModelosHorarios = "No se ha podido cargar el modelo: " + ex.Message;
        }
        finally
        {
            _modelosHorariosCargando = false;
        }
    }

    private async Task SubirModeloHorarioAsync(InputFileChangeEventArgs e)
    {
        var archivo = e.File;
        if (archivo is null)
            return;

        if (!archivo.Name.EndsWith(".zip", StringComparison.OrdinalIgnoreCase))
        {
            _mensajeModelosHorarios = "Solo se pueden subir archivos .zip.";
            return;
        }

        _modelosHorariosCargando = true;
        _mensajeModelosHorarios = "Subiendo ZIP...";

        try
        {
            await using var stream = archivo.OpenReadStream(MaxModeloHorarioUploadBytes);
            var modelo = await ArchivoImportacionDbus.GuardarModeloSubidoAsync(archivo.Name, stream);

            _modeloHorarioSeleccionadoId = modelo.Id;
            await RecargarModeloHorarioActivoAsync();
            await CargarModelosHorariosAsync();
            _mensajeModelosHorarios = "Subido y cargado: " + modelo.NombreArchivo;
        }
        catch (Exception ex)
        {
            _mensajeModelosHorarios = "No se ha podido subir el ZIP: " + ex.Message;
        }
        finally
        {
            _modelosHorariosCargando = false;
        }
    }

    private async Task LimpiarDatosLocalesAsync()
    {
        bool confirmado;
        try
        {
            confirmado = await JS.InvokeAsync<bool>(
                "confirm",
                "¿Seguro que quieres limpiar los datos locales de este navegador? Se borrarán historial, configuración guardada, cachés y datos locales de este sitio.");
        }
        catch (JSException)
        {
            return;
        }

        if (!confirmado)
            return;

        _modelosHorariosCargando = true;
        _mensajeModelosHorarios = "Limpiando datos locales...";

        try
        {
            await JS.InvokeVoidAsync("rt.clearLocalBrowserData");
            _mensajeModelosHorarios = "Datos locales borrados. Recargando...";
            await InvokeAsync(StateHasChanged);
            await Task.Delay(250);
            await JS.InvokeVoidAsync("rt.reloadPage");
        }
        catch (Exception ex)
        {
            _mensajeModelosHorarios = "No se han podido limpiar los datos locales: " + ex.Message;
        }
        finally
        {
            _modelosHorariosCargando = false;
        }
    }

    private async Task RecargarModeloHorarioActivoAsync()
    {
        _ctsCalculo?.Cancel();
        IniciarNuevaVersionPintadoRuta();

        await CerrarTodasLasPreviewsAsync();
        await CerrarPopupsAsync();

        if (_mapa is not null)
        {
            await ClearRoutesJsAsync();
            try { await _mapa.Geometric.DisplayPolylinesFromArray.deleteConnectors(); } catch { }
        }

        ResetEstadoRuta(limpiarOpciones: true);
        PlanificadorRutasServicio.InvalidarCachesModelo();
        _busFilteredCache.Clear();
        InvalidarBusIndex();

        _itItems.Clear();
        _itSeleccionadoId = null;
        _itFiltro = "";
        _selectItKey++;
        _nextDeps.Clear();
        _horariosOk = false;
        _horariosError = null;

        _tareaCargaRed = RedBusServicio.CargarRedAsync();
        await _tareaCargaRed;

        if (_usarHorariosTeoricos)
            await EnsureHorariosLoadedAsync();

        if (RedBusServicio.Paradas.Count > 0)
        {
            EnsureBusIndexBuilt();
            BuildItinerariosDropdown();
            SincronizarSeleccionItinerarioConFiltro();
        }

        _paradasPintadas = false;
        if (_mapa is not null)
        {
            if (_mostrarParadas)
                await DibujarParadasAsync();
            else
                await OcultarParadasAsync();

            await SincronizarMarcadoresOrigenDestinoJsAsync();
            _paradasPintadas = _mostrarParadas;
        }

        StateHasChanged();
    }

    private static string FormatearTamanoModelo(long bytes)
    {
        if (bytes >= 1024L * 1024L)
            return (bytes / 1024d / 1024d).ToString("0.0", CultureInfo.InvariantCulture) + " MB";

        if (bytes >= 1024L)
            return (bytes / 1024d).ToString("0", CultureInfo.InvariantCulture) + " KB";

        return bytes.ToString(CultureInfo.InvariantCulture) + " B";
    }

    private static string FormatearFechaModelo(DateTime fechaUtc)
        => fechaUtc.ToLocalTime().ToString("dd/MM/yyyy HH:mm", CultureInfo.InvariantCulture);
}
