using adas_core.Application.Services.Caching;
using adas_core.Application.Services.Interfaces;
using adas_core.Domain.Models.AppSettings;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;

namespace adas_core.Infrastructure.Utils
{
    /// <summary>
    /// Provides extension methods for configuring or building cache host instances.
    /// </summary>
    public static class CacheHostBuilderExtension
    {
        public static IHostBuilder UseCache(this IHostBuilder hostBuilder)
        {
            return hostBuilder.ConfigureServices((context, services) =>
            {
                services.Configure<CacheSettings>(context.Configuration.GetSection("CacheSettings"));
                services.AddSingleton(sp => sp.GetRequiredService<IOptions<CacheSettings>>().Value);

                services.AddSingleton<InMemoryLockProvider>();
                services.AddSingleton<NoCacheService>();

                // RedisLockProvider obtiene IDatabase de forma lazy a través de una clausura,
                // ya que la conexión se establece de forma asíncrona dentro de RedisService.
                services.AddSingleton<RedisService>(sp => {
                    RedisService? svcRef = null;
                    var lockProvider = new RedisLockProvider(() => svcRef?.Database);
                    var lockMgr = new LockManagerService(
                        sp.GetRequiredService<ILogger<LockManagerService>>(),
                        lockProvider);
                    svcRef = new RedisService(
                        sp.GetRequiredService<IOptions<CacheSettings>>(),
                        sp.GetRequiredService<ILogger<RedisService>>(),
                        lockMgr);
                    return svcRef;
                });

                // Inyectamos LockManager con InMemoryLockProvider
                services.AddSingleton<CacheService>(sp => {
                    var lockMgr = new LockManagerService(
                        sp.GetRequiredService<ILogger<LockManagerService>>(),
                        sp.GetRequiredService<InMemoryLockProvider>());
                    return new CacheService(lockMgr);
                });

                services.AddSingleton<ICacheService, CacheDispatcher>();
            });
        }
    }
}