using RutasDBUS.Servicios.Importacion;
using RutasDBUS.Servicios.RedBus;

namespace RutasDBUS.Servicios.Planificacion;

/// <summary>
/// Proporciona un indice temporal compartido y cacheado para toda la app.
/// </summary>
public sealed class ServicioIndiceTransitoDbus
{
    private readonly IRedBusServicio _redBusServicio;
    private readonly IServicioArchivoImportacionDbus _servicioArchivoImportacion;
    private readonly CreadorIndiceTransitoDbus _creadorIndice;
    private readonly SemaphoreSlim _semaforo = new(1, 1);
    private IndiceTransitoDbus? _indice;
    private object? _archivoCargado;

    /// <summary>
    /// Inicializa una nueva instancia del servicio.
    /// </summary>
    public ServicioIndiceTransitoDbus(
        IRedBusServicio redBusServicio,
        IServicioArchivoImportacionDbus servicioArchivoImportacion,
        CreadorIndiceTransitoDbus creadorIndice)
    {
        _redBusServicio = redBusServicio;
        _servicioArchivoImportacion = servicioArchivoImportacion;
        _creadorIndice = creadorIndice;
    }

    /// <summary>
    /// Devuelve el indice temporal, construyendolo una sola vez.
    /// </summary>
    public async Task<IndiceTransitoDbus> ObtenerAsync(CancellationToken cancellationToken = default)
    {
        var archivo = await _servicioArchivoImportacion.ObtenerAsync(cancellationToken);
        if (_indice is not null && ReferenceEquals(_archivoCargado, archivo))
            return _indice;

        await _semaforo.WaitAsync(cancellationToken);
        try
        {
            if (_indice is not null && ReferenceEquals(_archivoCargado, archivo))
                return _indice;

            await _redBusServicio.CargarRedAsync(cancellationToken);
            _indice = _creadorIndice.Crear(_redBusServicio, archivo);
            _archivoCargado = archivo;
            return _indice;
        }
        finally
        {
            _semaforo.Release();
        }
    }
}
