using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using System.Text;
using GestionIntegral.Api.Data;
using GestionIntegral.Api.Services.Contables;
using GestionIntegral.Api.Services.Distribucion;
using GestionIntegral.Api.Services.Radios;
using GestionIntegral.Api.Data.Repositories.Contables;
using GestionIntegral.Api.Data.Repositories.Distribucion;
using GestionIntegral.Api.Data.Repositories.Impresion;
using GestionIntegral.Api.Data.Repositories.Radios;
using GestionIntegral.Api.Services.Impresion;
using GestionIntegral.Api.Services.Usuarios;
using GestionIntegral.Api.Data.Repositories.Usuarios;
using Microsoft.OpenApi.Models;
using GestionIntegral.Api.Data.Repositories.Reportes;
using GestionIntegral.Api.Services.Reportes;
using GestionIntegral.Api.Services.Pdf;
using Microsoft.Extensions.Diagnostics.HealthChecks;
using GestionIntegral.Api.Services.Anomalia;
using GestionIntegral.Api.Data.Repositories.Suscripciones;
using GestionIntegral.Api.Services.Suscripciones;
using GestionIntegral.Api.Models.Comunicaciones;
using GestionIntegral.Api.Services.Comunicaciones;
using GestionIntegral.Api.Data.Repositories.Comunicaciones;
using GestionIntegral.Api.Middleware;

var builder = WebApplication.CreateBuilder(args);

// --- Registros de Servicios ---
builder.Services.AddSingleton<DbConnectionFactory>();
builder.Services.AddScoped<PasswordHasherService>();
builder.Services.AddScoped<IAuthRepository, AuthRepository>();
builder.Services.AddScoped<IAuthService, AuthService>();
builder.Services.AddScoped<ITipoPagoRepository, TipoPagoRepository>();
builder.Services.AddScoped<ITipoPagoService, TipoPagoService>();
builder.Services.AddScoped<IZonaRepository, ZonaRepository>();
builder.Services.AddScoped<IZonaService, ZonaService>();
builder.Services.AddScoped<IEmpresaRepository, EmpresaRepository>();
builder.Services.AddScoped<IEmpresaService, EmpresaService>();
builder.Services.AddScoped<ISaldoRepository, SaldoRepository>();
builder.Services.AddScoped<IPlantaRepository, PlantaRepository>();
builder.Services.AddScoped<IPlantaService, PlantaService>();
builder.Services.AddScoped<ITipoBobinaRepository, TipoBobinaRepository>();
builder.Services.AddScoped<ITipoBobinaService, TipoBobinaService>();
builder.Services.AddScoped<IEstadoBobinaRepository, EstadoBobinaRepository>();
builder.Services.AddScoped<IEstadoBobinaService, EstadoBobinaService>();
builder.Services.AddScoped<IOtroDestinoRepository, OtroDestinoRepository>();
builder.Services.AddScoped<IOtroDestinoService, OtroDestinoService>();
builder.Services.AddScoped<IPerfilRepository, PerfilRepository>();
builder.Services.AddScoped<IPerfilService, PerfilService>();
builder.Services.AddScoped<IPermisoRepository, PermisoRepository>();
builder.Services.AddScoped<IPermisoService, PermisoService>();
builder.Services.AddScoped<IUsuarioRepository, UsuarioRepository>();
builder.Services.AddScoped<IUsuarioService, UsuarioService>();
builder.Services.AddScoped<ICanillaRepository, CanillaRepository>();
builder.Services.AddScoped<ICanillaService, CanillaService>();
builder.Services.AddScoped<IDistribuidorRepository, DistribuidorRepository>();
builder.Services.AddScoped<IDistribuidorService, DistribuidorService>();
builder.Services.AddScoped<IPublicacionRepository, PublicacionRepository>();
builder.Services.AddScoped<IPublicacionService, PublicacionService>();
builder.Services.AddScoped<IRecargoZonaRepository, RecargoZonaRepository>();
builder.Services.AddScoped<IRecargoZonaService, RecargoZonaService>();
builder.Services.AddScoped<IPorcPagoRepository, PorcPagoRepository>();
builder.Services.AddScoped<IPorcPagoService, PorcPagoService>();
builder.Services.AddScoped<IPorcMonCanillaRepository, PorcMonCanillaRepository>();
builder.Services.AddScoped<IPorcMonCanillaService, PorcMonCanillaService>();
builder.Services.AddScoped<IPubliSeccionRepository, PubliSeccionRepository>();
builder.Services.AddScoped<IPubliSeccionService, PubliSeccionService>();
builder.Services.AddScoped<IPrecioRepository, PrecioRepository>();
builder.Services.AddScoped<IPrecioService, PrecioService>();
builder.Services.AddScoped<IStockBobinaRepository, StockBobinaRepository>();
builder.Services.AddScoped<IStockBobinaService, StockBobinaService>();
builder.Services.AddScoped<IRegTiradaRepository, RegTiradaRepository>();
builder.Services.AddScoped<IRegPublicacionSeccionRepository, RegPublicacionSeccionRepository>();
builder.Services.AddScoped<ITiradaService, TiradaService>();
builder.Services.AddScoped<ISalidaOtroDestinoRepository, SalidaOtroDestinoRepository>();
builder.Services.AddScoped<ISalidaOtroDestinoService, SalidaOtroDestinoService>();
builder.Services.AddScoped<IEntradaSalidaDistRepository, EntradaSalidaDistRepository>();
builder.Services.AddScoped<IEntradaSalidaDistService, EntradaSalidaDistService>();
builder.Services.AddScoped<IEntradaSalidaCanillaRepository, EntradaSalidaCanillaRepository>();
builder.Services.AddScoped<IEntradaSalidaCanillaService, EntradaSalidaCanillaService>();
builder.Services.AddScoped<IControlDevolucionesRepository, ControlDevolucionesRepository>();
builder.Services.AddScoped<IControlDevolucionesService, ControlDevolucionesService>();
builder.Services.AddScoped<IPagoDistribuidorRepository, PagoDistribuidorRepository>();
builder.Services.AddScoped<IPagoDistribuidorService, PagoDistribuidorService>();
builder.Services.AddScoped<INotaCreditoDebitoRepository, NotaCreditoDebitoRepository>();
builder.Services.AddScoped<INotaCreditoDebitoService, NotaCreditoDebitoService>();
builder.Services.AddScoped<IRitmoRepository, RitmoRepository>();
builder.Services.AddScoped<IRitmoService, RitmoService>();
builder.Services.AddScoped<ICancionRepository, CancionRepository>();
builder.Services.AddScoped<ICancionService, CancionService>();
builder.Services.AddScoped<IRadioListaService, RadioListaService>();
builder.Services.AddScoped<INovedadCanillaRepository, NovedadCanillaRepository>();
builder.Services.AddScoped<INovedadCanillaService, NovedadCanillaService>();
builder.Services.AddScoped<ICambioParadaRepository, CambioParadaRepository>();
builder.Services.AddScoped<ICambioParadaService, CambioParadaService>();
// Servicio de Saldos
builder.Services.AddScoped<ISaldoService, SaldoService>();
// Cierre de Cuenta Corriente de Distribuidor
builder.Services.AddMemoryCache();
builder.Services.AddScoped<ICierreCuentaCorrienteRepository, CierreCuentaCorrienteRepository>();
builder.Services.AddScoped<ICierreCuentaCorrienteService, CierreCuentaCorrienteService>();
// Validador de período cerrado: SINGLETON porque mantiene cache en memoria de IMemoryCache que debe ser compartido entre requests.
builder.Services.AddSingleton<IPeriodoCerradoValidator, PeriodoCerradoValidator>();
// Repositorios de Reportes
builder.Services.AddScoped<IReportesRepository, ReportesRepository>();
// Servicios de Reportes
builder.Services.AddScoped<IReportesService, ReportesService>();
// QuestPDF
builder.Services.AddScoped<IQuestPdfGenerator, QuestPdfGenerator>();
// Servicio de Alertas
builder.Services.AddScoped<IAlertaService, AlertaService>();

// --- Suscripciones ---
builder.Services.AddScoped<IFormaPagoRepository, FormaPagoRepository>();
builder.Services.AddScoped<ISuscriptorRepository, SuscriptorRepository>();
builder.Services.AddScoped<ISuscripcionRepository, SuscripcionRepository>();
builder.Services.AddScoped<IFacturaRepository, FacturaRepository>();
builder.Services.AddScoped<ILoteDebitoRepository, LoteDebitoRepository>();
builder.Services.AddScoped<IPagoRepository, PagoRepository>();
builder.Services.AddScoped<IPromocionRepository, PromocionRepository>();
builder.Services.AddScoped<IAjusteRepository, AjusteRepository>();
builder.Services.AddScoped<IFacturaDetalleRepository, FacturaDetalleRepository>();

builder.Services.AddScoped<IFormaPagoService, FormaPagoService>();
builder.Services.AddScoped<ISuscriptorService, SuscriptorService>();
builder.Services.AddScoped<ISuscripcionService, SuscripcionService>();
builder.Services.AddScoped<IFacturacionService, FacturacionService>();
builder.Services.AddScoped<IDebitoAutomaticoService, DebitoAutomaticoService>();
builder.Services.AddScoped<IPagoService, PagoService>();
builder.Services.AddScoped<IPromocionService, PromocionService>();
builder.Services.AddScoped<IAjusteService, AjusteService>();

// --- Comunicaciones ---
builder.Services.Configure<MailSettings>(builder.Configuration.GetSection("MailSettings"));
builder.Services.AddTransient<IEmailService, EmailService>();
builder.Services.AddScoped<IEmailLogRepository, EmailLogRepository>();
builder.Services.AddScoped<IEmailLogService, EmailLogService>();
builder.Services.AddScoped<ILoteDeEnvioRepository, LoteDeEnvioRepository>();

// --- SERVICIO DE HEALTH CHECKS ---
// Añadimos una comprobación específica para SQL Server.
// El sistema usará la cadena de conexión configurada en appsettings.json o variables de entorno.
builder.Services.AddHealthChecks()
    .AddSqlServer(
        connectionString: builder.Configuration.GetConnectionString("DefaultConnection") ?? "",
        healthQuery: "SELECT 1;",
        name: "sql-server",
        failureStatus: HealthStatus.Unhealthy,
        tags: new string[] { "database" }
    );

// --- Configuración de Autenticación JWT ---
var jwtSettings = builder.Configuration.GetSection("Jwt");

// Le decimos que busque la clave JWT en la raíz de la configuración (donde están las variables de entorno).
// Si no la encuentra, como respaldo, busca en la sección "Jwt" del appsettings.
var jwtKey = builder.Configuration["JWT_KEY"] ?? jwtSettings["Key"] ?? throw new ArgumentNullException("JWT_KEY or Jwt:Key not configured");

var keyBytes = Encoding.ASCII.GetBytes(jwtKey);

builder.Services.AddAuthentication(options =>
{
    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
    options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
    options.RequireHttpsMetadata = builder.Environment.IsProduction();
    options.SaveToken = true;
    options.TokenValidationParameters = new TokenValidationParameters
    {
        ValidateIssuerSigningKey = true,
        IssuerSigningKey = new SymmetricSecurityKey(keyBytes),
        ValidateIssuer = true,
        ValidIssuer = jwtSettings["Issuer"],
        ValidateAudience = true,
        ValidAudience = jwtSettings["Audience"],
        ValidateLifetime = true,
        ClockSkew = TimeSpan.Zero
    };
});

// --- Configuración de Autorización ---
builder.Services.AddAuthorization();

// --- Configuración de CORS --- //
var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
builder.Services.AddCors(options =>
{
    options.AddPolicy(name: MyAllowSpecificOrigins,
                      policy =>
                      {
                          policy.WithOrigins(
                              "http://localhost:5173", // Para desarrollo local
                              "https://gestion.eldiaservicios.com"  // Para producción
                          ) 
                          .AllowAnyHeader()
                          .AllowAnyMethod();
                      });
});
// --- Fin CORS ---

// --- Servicios del Contenedor ---
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();

// --- Configuración Avanzada de Swagger/OpenAPI ---
builder.Services.AddSwaggerGen(options =>
{
    // Definición general del documento Swagger
    options.SwaggerDoc("v1", new OpenApiInfo
    {
        Version = "v1",
        Title = "GestionIntegral API",
        Description = "API para el sistema de Gestión Integral (Migración VB.NET)",
        // Puedes añadir TermsOfService, Contact, License si lo deseas
    });

    // (Opcional) Incluir comentarios XML si los usas en tus controladores/DTOs
    // var xmlFilename = $"{System.Reflection.Assembly.GetExecutingAssembly().GetName().Name}.xml";
    // options.IncludeXmlComments(System.IO.Path.Combine(AppContext.BaseDirectory, xmlFilename));

    // Definición de Seguridad para JWT en Swagger UI
    // Esto añade el botón "Authorize" en la UI de Swagger para poder pegar el token Bearer
    options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
    {
        In = ParameterLocation.Header,
        Description = "Por favor, introduce 'Bearer' seguido de un espacio y luego tu token JWT.",
        Name = "Authorization",
        Type = SecuritySchemeType.ApiKey, // Usar ApiKey para el formato Bearer simple
        Scheme = "Bearer" // Esquema a usar
    });

    options.AddSecurityRequirement(new OpenApiSecurityRequirement
    {
        {
            new OpenApiSecurityScheme
            {
                Reference = new OpenApiReference
                {
                    Type = ReferenceType.SecurityScheme,
                    Id = "Bearer" // Debe coincidir con el Id definido en AddSecurityDefinition
                },
                Scheme = "oauth2", // Aunque el scheme sea ApiKey, a veces se usa oauth2 aquí para la UI
                Name = "Bearer",
                In = ParameterLocation.Header,
            },
            new List<string>() // Lista de scopes (vacía si no usas scopes OAuth2 complejos)
        }
    });
});
// --- Fin Configuración Swagger ---

var app = builder.Build();

// Habilitamos Swagger SIEMPRE, sin importar el entorno.
app.UseSwagger(); // Habilita el middleware para servir el JSON de Swagger
app.UseSwaggerUI(options => // Habilita el middleware para servir la UI de Swagger
{
    options.SwaggerEndpoint("/swagger/v1/swagger.json", "GestionIntegral API v1");
    // Opcional: Para que Swagger aparezca en la raíz de la API (ej: http://192.168.4.128:8081/)
    options.RoutePrefix = string.Empty; 
});


// Mantenemos esta lógica solo para la página de error de desarrollo, si quieres.
if (app.Environment.IsDevelopment())
{
    // Aquí puedes dejar otras herramientas solo para desarrollo si las tuvieras.
}

// ¡¡¡NO USAR UseHttpsRedirection si la API corre en HTTP!!!
// Comenta o elimina la siguiente línea si SÓLO usas http://localhost:5183
//app.UseHttpsRedirection();

// Middleware global de excepciones — debe ir TEMPRANO en el pipeline para catchear cualquier excepción
// que escape de los controllers/services. Mapea BloqueoPorPeriodoCerradoException → 409 con cuerpo JSON estandarizado.
app.UseMiddleware<ExceptionHandlerMiddleware>();

app.UseCors(MyAllowSpecificOrigins);

app.UseAuthentication(); // Debe ir ANTES de UseAuthorization
app.UseAuthorization();

// Mapeamos la ruta "/health". Cuando se acceda a ella, se ejecutarán todas las comprobaciones registradas.
// Esto va ANTES de app.MapControllers().
app.MapHealthChecks("/health");

app.MapControllers();

app.Run();