using adas_core.Application.Repositories.Interfaces;
using adas_core.Application.Services;
using adas_core.Application.Services.Interfaces;
using adas_core.Application.Subscriptions;
using adas_core.Authentication.RegistrationExtensions;
using adas_core.Configurations;
using adas_core.Domain.Models;
using adas_core.Domain.Models.AppSettings;
using adas_core.Domain.Models.Masters;
using adas_core.Domain.Models.MongoModels;
using adas_core.Domain.Utils;
using adas_core.ErrorMiddleware;
using adas_core.Infrastructure.Repositories;
using adas_core.Infrastructure.Services;
using adas_core.Infrastructure.Utils;
using adas_core.LdapLogin.RegistrationExtension;
using adas_core.LocalLogin.RegistrationExtension;
using adas_core.Logging;
using adas_core.module.LightBeacons.Services;
using adas_core.WebSocket;
using adas_core.WebSocket.Hubs;
using audit_logs.Extensions;
using Microsoft.Extensions.Options;
using Microsoft.OpenApi;
using MongoDB.Bson;
using MongoDB.Driver;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
using Serilog;
using Serilog.Settings.Configuration;
using ServiceConfigService = adas_core.Domain.Models.MongoModels.ServiceConfigService;

var builder = WebApplication.CreateBuilder(args);

var configuration =
    new ConfigurationBuilder()
        .SetBasePath(Directory.GetCurrentDirectory())
        .AddJsonFile("appsettings.json", false)
        .AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production"}.json",
            true)
        .Build();


//SERILOG
builder.Host.UseSerilog((_, loggerConfig) =>
{
    if (configuration.GetSection("Serilog").Exists())
    {
        ConfigurationReaderOptions options = new() { SectionName = "Serilog" };
        loggerConfig.ReadFrom.Configuration(configuration, options);
    }
    else
    {
        loggerConfig.MinimumLevel.Information().WriteTo.Console();
    }

    LogExecutionContext.TrySetTraceIdentifier(Guid.NewGuid().ToString());


    loggerConfig.Enrich.WithDynamicProperty("TraceIdentifier", () => LogExecutionContext.TraceIdentifier);


});




builder.Services.AddSingleton(typeof(ILogger<>), typeof(Logger<>));


builder.Services.Configure<IISServerOptions>(options =>
{
    options.MaxRequestBodySize = int.MaxValue; // or your desired value
});

// Json
builder.Services
    .AddControllers(o => 
    {

        var policy = new Microsoft.AspNetCore.Authorization.AuthorizationPolicyBuilder()
                .RequireAuthenticatedUser()
                .Build();

        o.Filters.Add(new Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter(policy));


    })    
    .AddNewtonsoftJson(options =>
    {
        options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
        options.SerializerSettings.Converters.Add(new StringEnumConverter());
        options.SerializerSettings.Converters.Add(new ObjectIdConverter());
        options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
        options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
    });

// Configuraci�n de servicios de auditor�a
builder.Services.AddAuditServices(builder.Configuration);

// Registro de servicios generales
builder.Services.AddHttpContextAccessor();
builder.Services.AddSingleton<DatabaseSettings>();
builder.Services.AddSingleton<ApiSettings>();
builder.Services.AddSingleton<AuthSettings>();
builder.Services.AddSignalR();
builder.Services.AddEndpointsApiExplorer();


builder.Services.AddSwaggerGen(c =>
{
    c.SwaggerDoc("v1", new()
    {
        Title = "adas-core",
        Version = "v1"
    });

    c.CustomSchemaIds(type => type.FullName);

    c.MapType<ObjectId>(() => new OpenApiSchema
    {
        Type = JsonSchemaType.String,
        Format = "objectid"
    });
});

builder.Services.AddSwaggerGenNewtonsoftSupport();



// MongoDB
builder.Host.UseMongo();
// 1. Create the Client once
builder.Services.AddSingleton<IMongoClient>(sp => 
{
    var settings = sp.GetRequiredService<IOptions<DatabaseSettings>>().Value;
    // USAMOS EL NOMBRE COMPLETO PARA EVITAR TU CLASE
    var mongoSettings = MongoClientSettings.FromConnectionString(settings.ConnectionString);
    mongoSettings.MaxConnectionPoolSize = settings.MaxConnectionPoolSize;
    mongoSettings.MinConnectionPoolSize = settings.MinConnectionPoolSize;
    mongoSettings.MaxConnectionIdleTime = TimeSpan.FromSeconds(settings.MaxConnectionIdleTime);
    return new MongoClient(mongoSettings);
});

// 2. Register the Database once
builder.Services.AddSingleton<IMongoDatabase>(sp => 
{
    var client = sp.GetRequiredService<IMongoClient>();
    var settings = sp.GetRequiredService<IOptions<DatabaseSettings>>().Value;
    return client.GetDatabase(settings.DatabaseName);
});
builder.Services.AddAuth();
builder.Services.AddLocalLogin();
builder.Services.AddLdapAuth(configuration);
builder.ConfigureJwtAuthentication();
builder.UseProxyDevices();
builder.CreateConfigEntitiesFromAppSettingsSections();



// Cache
builder.Host.UseCache();

//First repos because dont have dependencies on construct
builder.Services.AddSingleton<IUserRepository, UserRepository>();
builder.Services.AddSingleton<IAppointmentArchiveRepository, AppointmentArchiveRepository>();
builder.Services.AddSingleton<IArchivePatientCarePlanRepository, ArchivePatientCarePlanRepository>();
builder.Services.AddSingleton<IAppointmentRepository, AppointmentRepository>();
builder.Services.AddSingleton<IConfigObservationRepository, ConfigObservationRepository>();
builder.Services.AddSingleton<IConfigUnitsRepository, ConfigUnitsRepository>();
builder.Services.AddSingleton<IConfigPumpsRepository, ConfigPumpsRepository>();
builder.Services.AddSingleton<IDiagnosisArchiveRepository, DiagnosisArchiveRepository>();
builder.Services.AddSingleton<IDeviceRepository, DeviceRepository>();
builder.Services.AddSingleton<IDiagnosisRepository, DiagnosisRepository>();
builder.Services.AddSingleton<IMedicineRepository, MedicineRepository>();
builder.Services.AddSingleton<IHistoricalConfigChangesRepository, HistoricalConfigChangesRepository>();
builder.Services.AddSingleton<IAlarmRepository, AlarmRepository>();
builder.Services.AddSingleton<IAuthService, AuthService>();
builder.Services.AddSingleton<IDisplayRepository, DisplayRepository>();
builder.Services.AddSingleton<IDisplayConfigRepository, DisplayConfigRepository>();
builder.Services.AddSingleton<IDisplayChartConfigRepository, DisplayChartConfigRepository>();
builder.Services.AddSingleton<IDisplayCardConfigRepository, DisplayCardConfigRepository>();
builder.Services.AddSingleton<IDisplayDetailConfigRepository, DisplayDetailConfigRepository>();
builder.Services.AddSingleton<IUnitRepository, UnitRepository>();
builder.Services.AddSingleton<ISubscribersService, SubscribersService>();
builder.Services.AddSingleton<ISubscriberGroupedService, SubscriberGroupedService>();
builder.Services.AddSingleton<IDischargeRepository, DischargeRepository>();
builder.Services.AddSingleton<IAdmissionRepository, AdmissionRepository>();
// Register MasterListRepository for each specific type
builder.Services.AddSingleton<IMasterListRepository<AltableOptionList>, MasterListRepository<AltableOptionList>>();
builder.Services.AddSingleton<IMasterListRepository<AllergyList>, MasterListRepository<AllergyList>>();
builder.Services.AddSingleton<IMasterListRepository<DestinationList>, MasterListRepository<DestinationList>>();
builder.Services.AddSingleton<IMasterListRepository<DiagnosisList>, MasterListRepository<DiagnosisList>>();
builder.Services.AddSingleton<IMasterListRepository<DischargeStatusList>, MasterListRepository<DischargeStatusList>>();
builder.Services.AddSingleton<IMasterListRepository<DoctorList>, MasterListRepository<DoctorList>>();
builder.Services.AddSingleton<IMasterListRepository<DoctorTypeList>, MasterListRepository<DoctorTypeList>>();
builder.Services
    .AddSingleton<IMasterListRepository<InternalDestinationList>, MasterListRepository<InternalDestinationList>>();
builder.Services.AddSingleton<IMasterListRepository<InsulationList>, MasterListRepository<InsulationList>>();
builder.Services.AddSingleton<IMasterListRepository<LanguageBarrierList>, MasterListRepository<LanguageBarrierList>>();
builder.Services.AddSingleton<IMasterListRepository<MasterList>, MasterListRepository<MasterList>>();
builder.Services.AddSingleton<IMasterListRepository<MobilityOptionList>, MasterListRepository<MobilityOptionList>>();
builder.Services.AddSingleton<IMasterListRepository<OriginList>, MasterListRepository<OriginList>>();
builder.Services.AddSingleton<IMasterListRepository<PatientStatusList>, MasterListRepository<PatientStatusList>>();
builder.Services.AddSingleton<IMasterListRepository<ProcedureList>, MasterListRepository<ProcedureList>>();
builder.Services.AddSingleton<IMasterListRepository<TestList>, MasterListRepository<TestList>>();
builder.Services.AddSingleton<IMasterListRepository<ServiceList>, MasterListRepository<ServiceList>>();
builder.Services
    .AddSingleton<IMasterListRepository<TherapeuticCeilingList>, MasterListRepository<TherapeuticCeilingList>>();
builder.Services.AddSingleton<IMasterListRepository<PassiveSittingList>, MasterListRepository<PassiveSittingList>>();
builder.Services.AddSingleton<IMasterListRepository<GenericList>, MasterListRepository<GenericList>>();
builder.Services.AddSingleton<IMasterListRepository<TreatmentList>, MasterListRepository<TreatmentList>>();
builder.Services.AddSingleton<IMasterListRepository<VisitOptionList>, MasterListRepository<VisitOptionList>>();
builder.Services.AddSingleton<IMasterListRepository<AccessControlList>, MasterListRepository<AccessControlList>>();


builder.Services.AddSingleton<IMongoRepository<PumpElement>>(serviceProvider =>
    serviceProvider.GetRequiredService<MongoRepository<PumpElement>>());
builder.Services.AddSingleton<IMongoRepository<Box>>(serviceProvider =>
    serviceProvider.GetRequiredService<MongoRepository<Box>>());
builder.Services.AddSingleton<IMongoRepository<ConfigObservation>>(serviceProvider =>
    serviceProvider.GetRequiredService<MongoRepository<ConfigObservation>>());
builder.Services.AddSingleton<IMongoRepository<ConfigUnits>>(serviceProvider =>
    serviceProvider.GetRequiredService<MongoRepository<ConfigUnits>>());
builder.Services.AddSingleton<IMongoRepository<ConfigPumps>>(serviceProvider =>
    serviceProvider.GetRequiredService<MongoRepository<ConfigPumps>>());
builder.Services.AddSingleton<IMongoRepository<Patient>>(serviceProvider =>
    serviceProvider.GetRequiredService<MongoRepository<Patient>>());
builder.Services.AddSingleton<IMongoRepository<PoCMapping>>(serviceProvider =>
    serviceProvider.GetRequiredService<MongoRepository<PoCMapping>>());
builder.Services.AddSingleton<IMongoRepository<Section>>(serviceProvider =>
    serviceProvider.GetRequiredService<MongoRepository<Section>>());

builder.Services.AddSingleton<IMongoRepository<ServiceConfig>>(serviceProvider =>
    serviceProvider.GetRequiredService<MongoRepository<ServiceConfig>>());
builder.Services.AddSingleton<IMongoRepository<ServiceConfigService>>(serviceProvider => serviceProvider
    .GetRequiredService<MongoRepository<ServiceConfigService>>());
builder.Services.AddSingleton<IMongoRepository<ServiceConfigTheme>>(serviceProvider =>
    serviceProvider.GetRequiredService<MongoRepository<ServiceConfigTheme>>());
builder.Services.AddSingleton<IMongoRepository<User>>(serviceProvider =>
    serviceProvider.GetRequiredService<MongoRepository<User>>());
builder.Services.AddSingleton<IMongoRepository<Authorization>>(serviceProvider =>
    serviceProvider.GetRequiredService<MongoRepository<Authorization>>());
builder.Services.AddSingleton<IMongoRepository<HistoricalConfigChanges>>(serviceProvider =>
    serviceProvider.GetRequiredService<MongoRepository<HistoricalConfigChanges>>());
builder.Services.AddSingleton<IMongoRepository<PatientObservationAlarm>>(serviceProvider =>
    serviceProvider.GetRequiredService<MongoRepository<PatientObservationAlarm>>());

builder.Services.AddSingleton<INoticeRepository, NoticeRepository>();
builder.Services.AddSingleton<IPointOfCareRepository, PointOfCareRepository>();
builder.Services.AddSingleton<IObservationArchiveRepository, ObservationArchiveRepository>();
builder.Services.AddSingleton<IObservationRepository, ObservationRepository>();
builder.Services.AddSingleton<IPatientCarePlanRepository, PatientCarePlanRepository>();
builder.Services.AddSingleton<IPatientArchiveRepository, PatientArchiveRepository>();
builder.Services.AddSingleton<IPatientRepository, PatientRepository>();
builder.Services.AddSingleton<IPoCMappingRepository, PoCMappingRepository>();
builder.Services.AddSingleton<IPumpArchiveRepository, PumpArchiveRepository>();

builder.Services.AddScoped<IPumpStateRepository, PumpStateRepository>();
builder.Services.AddScoped<IPumpObservationRepository, PumpObservationRepository>();
builder.Services.AddScoped<IPumpAlarmEventRepository, PumpAlarmEventRepository>();
builder.Services.AddScoped<IPumpAlarmStateRepository, PumpAlarmStateRepository>();


builder.Services.AddSingleton<IRelayRepository, RelayRepository>();
builder.Services.AddSingleton<ILightBeaconRepository, LightBeaconRepository>();
builder.Services.AddSingleton<ICameraRepository, CameraRepository>();
builder.Services.AddSingleton<IRecordingAlertArchiveRepository, RecordingAlertArchiveRepository>();
builder.Services.AddSingleton<IRecordingAlertRepository, RecordingAlertRepository>();
builder.Services.AddSingleton<ISectionRepository, SectionRepository>();
builder.Services.AddSingleton<IServiceConfigRepository, ServiceConfigRepository>();
builder.Services.AddSingleton<ITreatmentArchiveRepository, TreatmentArchiveRepository>();
builder.Services.AddSingleton<ITreatmentRepository, TreatmentRepository>();


builder.Services.AddSingleton<IPatientCarePlanService, PatientCarePlanService>();
builder.Services.AddSingleton<IArchivedPatientObservationService, ArchivePatientObservationsService>();
builder.Services.AddSingleton<IArchivedPatientService, ArchivedPatientService>();
builder.Services.AddSingleton<IArchivePatientCarePlanService, ArchivePatientCarePlanService>();
builder.Services.AddSingleton<IArchivedPatientTreatmentService, ArchivedPatientTreatmentService>();
builder.Services.AddSingleton<IAlertValuesService, AlertValuesService>();
builder.Services.AddSingleton<IAppointmentService, AppointmentService>();
// builder.Services.AddSingleton<IPoCSettingsService, PoCSettingsService>();
builder.Services.AddSingleton<ILightBeaconService, LightBeaconService>();
// builder.Services.AddSingleton<IBoxService, BoxService>();
builder.Services.AddSingleton<ICameraService, CameraService>();
builder.Services.AddSingleton<IConfigObservationService, ConfigObservationService>();
builder.Services.AddSingleton<IConfigUnitsService, ConfigUnitsService>();
builder.Services.AddSingleton<IConfigPumpsService, ConfigPumpsService>();
builder.Services.AddSingleton<IDiagnosisService, DiagnosisService>();
builder.Services.AddSingleton<IDeviceService, DeviceService>();
builder.Services.AddSingleton<IGroupedObservationService, GroupedObservationService>();
builder.Services.AddSingleton<IMedicineService, MedicineService>();
builder.Services.AddSingleton<IObservationService, ObservationService>();
builder.Services.AddSingleton<IObservationDemoService, ObservationDemoService>();
builder.Services.AddSingleton<IPatientService, PatientService>();
builder.Services.AddSingleton<IPumpService, PumpService>();
builder.Services.AddSingleton<IRecordingAlertService, RecordingAlertService>();
builder.Services.AddSingleton<IRecordingService, RecordingService>();
// builder.Services.AddSingleton<ISectionService, SectionService>();
builder.Services.AddSingleton<ISendAlertService, SendAlertService>();
builder.Services.AddSingleton<IServiceConfigService, adas_core.Application.Services.ServiceConfigService>();
builder.Services.AddSingleton<ITreatmentService, TreatmentService>();
builder.Services.AddSingleton<IPermissionService, PermissionService>();
builder.Services.AddSingleton<ILocalAuditService, LocalAuditService>();


builder.Services.AddSingleton<ICalculatedObservationsService, CalculatedObservationsService>();
builder.Services.AddSingleton<IFileService, FileService>();
builder.Services.AddSingleton<IAdminPanelService, AdminPanelService>();
builder.Services.AddSingleton<IPublisherService, PublisherService>();
builder.Services.AddSingleton<IHistoricalConfigChangesService, HistoricalConfigChangesService>();
builder.Services.AddSingleton<IAlarmService, AlarmService>();
builder.Services.AddSingleton<IUnitService, UnitService>();
builder.Services.AddSingleton<IDisplayConfigService, DisplayConfigService>();
builder.Services.AddSingleton<IDisplayService, DisplayService>();
builder.Services.AddSingleton<IAdmissionService, AdmissionService>();
builder.Services.AddSingleton<IDischargeService, DischargeService>();
builder.Services.AddSingleton<IPointOfCareService, PointOfCareService>();
builder.Services.AddSingleton<INoticeService, NoticeService>();

//MasterLists
builder.Services.AddSingleton<IServiceProvider>(provider => provider);
builder.Services.AddScoped<IMasterListService<AltableOptionList>, MasterListService<AltableOptionList>>();
builder.Services.AddScoped<IMasterListService<AllergyList>, MasterListService<AllergyList>>();
builder.Services.AddScoped<IMasterListService<DestinationList>, MasterListService<DestinationList>>();
builder.Services.AddScoped<IMasterListService<DiagnosisList>, MasterListService<DiagnosisList>>();
builder.Services.AddScoped<IMasterListService<DischargeStatusList>, MasterListService<DischargeStatusList>>();
builder.Services.AddScoped<IMasterListService<DoctorList>, MasterListService<DoctorList>>();
builder.Services.AddScoped<IMasterListService<DoctorTypeList>, MasterListService<DoctorTypeList>>();
builder.Services.AddScoped<IMasterListService<InternalDestinationList>, MasterListService<InternalDestinationList>>();
builder.Services.AddScoped<IMasterListService<InsulationList>, MasterListService<InsulationList>>();
builder.Services.AddScoped<IMasterListService<LanguageBarrierList>, MasterListService<LanguageBarrierList>>();
builder.Services.AddScoped<IMasterListService<MobilityOptionList>, MasterListService<MobilityOptionList>>();
builder.Services.AddScoped<IMasterListService<OriginList>, MasterListService<OriginList>>();
builder.Services.AddScoped<IMasterListService<PatientStatusList>, MasterListService<PatientStatusList>>();
builder.Services.AddScoped<IMasterListService<ProcedureList>, MasterListService<ProcedureList>>();
builder.Services.AddScoped<IMasterListService<TestList>, MasterListService<TestList>>();
builder.Services.AddScoped<IMasterListService<ServiceList>, MasterListService<ServiceList>>();
builder.Services.AddScoped<IMasterListService<TherapeuticCeilingList>, MasterListService<TherapeuticCeilingList>>();
builder.Services.AddScoped<IMasterListService<PassiveSittingList>, MasterListService<PassiveSittingList>>();
builder.Services.AddScoped<IMasterListService<GenericList>, MasterListService<GenericList>>();
builder.Services.AddScoped<IMasterListService<TreatmentList>, MasterListService<TreatmentList>>();
builder.Services.AddScoped<IMasterListService<VisitOptionList>, MasterListService<VisitOptionList>>();
builder.Services.AddScoped<IMasterListService<AccessControlList>, MasterListService<AccessControlList>>();
builder.Services.AddScoped(typeof(IMasterListService<>), typeof(MasterListService<>));

builder.Services.AddSingleton<IMasterListServiceFactory, MasterListServiceFactory>();

builder.Services.AddTransient(typeof(Lazy<>));
builder.Services.AddSingleton<Lazy<IClientMessageService>>(provider =>
    new Lazy<IClientMessageService>(provider.GetRequiredService<IClientMessageService>));
builder.Services.AddSingleton<Lazy<IAppointmentService>>(provider =>
    new Lazy<IAppointmentService>(provider.GetRequiredService<IAppointmentService>));
builder.Services.AddSingleton<Lazy<IObservationService>>(provider =>
    new Lazy<IObservationService>(provider.GetRequiredService<IObservationService>));
builder.Services.AddSingleton<Lazy<IRecordingAlertService>>(provider =>
    new Lazy<IRecordingAlertService>(provider.GetRequiredService<IRecordingAlertService>));
builder.Services.AddSingleton<Lazy<IRecordingService>>(provider =>
    new Lazy<IRecordingService>(provider.GetRequiredService<IRecordingService>));
builder.Services.AddSingleton<Lazy<IPatientService>>(provider =>
    new Lazy<IPatientService>(provider.GetRequiredService<IPatientService>));
builder.Services.AddSingleton<Lazy<ITreatmentService>>(provider =>
    new Lazy<ITreatmentService>(provider.GetRequiredService<ITreatmentService>));
builder.Services.AddSingleton<Lazy<IConfigObservationService>>(provider =>
    new Lazy<IConfigObservationService>(provider.GetRequiredService<IConfigObservationService>));
// builder.Services.AddSingleton<Lazy<ISectionService>>(provider =>
//     new Lazy<ISectionService>(provider.GetRequiredService<ISectionService>));
builder.Services.AddSingleton<Lazy<IMedicineService>>(provider =>
    new Lazy<IMedicineService>(provider.GetRequiredService<IMedicineService>));
builder.Services.AddSingleton<Lazy<IPumpService>>(provider =>
    new Lazy<IPumpService>(provider.GetRequiredService<IPumpService>));
builder.Services.AddSingleton<Lazy<ICalculatedObservationsService>>(provider =>
    new Lazy<ICalculatedObservationsService>(provider.GetRequiredService<ICalculatedObservationsService>));
builder.Services.AddSingleton<Lazy<IHistoricalConfigChangesService>>(provider =>
    new Lazy<IHistoricalConfigChangesService>(provider.GetRequiredService<IHistoricalConfigChangesService>));
builder.Services.AddSingleton<Lazy<IAlarmService>>(provider =>
    new Lazy<IAlarmService>(provider.GetRequiredService<IAlarmService>));
builder.Services.AddSingleton<Lazy<ILightBeaconService>>(provider =>
    new Lazy<ILightBeaconService>(provider.GetRequiredService<ILightBeaconService>));
builder.Services.AddSingleton<Lazy<IDiagnosisService>>(provider =>
    new Lazy<IDiagnosisService>(provider.GetRequiredService<IDiagnosisService>));
builder.Services.AddScoped<Lazy<IUnitService>>(provider =>
    new Lazy<IUnitService>(provider.GetRequiredService<IUnitService>));
builder.Services.AddScoped<Lazy<IDisplayService>>(provider =>
    new Lazy<IDisplayService>(provider.GetRequiredService<IDisplayService>));
builder.Services.AddScoped<Lazy<IAdmissionService>>(provider =>
    new Lazy<IAdmissionService>(provider.GetRequiredService<IAdmissionService>));
builder.Services.AddScoped<Lazy<INoticeService>>(provider =>
    new Lazy<INoticeService>(provider.GetRequiredService<INoticeService>));
builder.Services.AddScoped<Lazy<IDischargeService>>(provider =>
    new Lazy<IDischargeService>(provider.GetRequiredService<IDischargeService>));
builder.Services.AddSingleton<Lazy<IPatientCarePlanService>>(provider =>
    new Lazy<IPatientCarePlanService>(provider.GetRequiredService<IPatientCarePlanService>));

builder.Services.AddSingleton<IPoCSettingsRepository, PoCSettingsRepository>();
builder.Services.AddSingleton<Lazy<ISectionRepository>>(provider =>
    new Lazy<ISectionRepository>(provider.GetRequiredService<ISectionRepository>));
builder.Services.AddSingleton<Lazy<IObservationRepository>>(provider =>
    new Lazy<IObservationRepository>(provider.GetRequiredService<IObservationRepository>));
builder.Services.AddSingleton<Lazy<IPatientRepository>>(provider =>
    new Lazy<IPatientRepository>(provider.GetRequiredService<IPatientRepository>));
builder.Services.AddSingleton<Lazy<IAppointmentRepository>>(provider =>
    new Lazy<IAppointmentRepository>(provider.GetRequiredService<IAppointmentRepository>));
builder.Services.AddSingleton<Lazy<ITreatmentRepository>>(provider =>
    new Lazy<ITreatmentRepository>(provider.GetRequiredService<ITreatmentRepository>));
builder.Services.AddSingleton<Lazy<IMedicineRepository>>(provider =>
    new Lazy<IMedicineRepository>(provider.GetRequiredService<IMedicineRepository>));
builder.Services.AddSingleton<Lazy<IDiagnosisRepository>>(provider =>
    new Lazy<IDiagnosisRepository>(provider.GetRequiredService<IDiagnosisRepository>));
builder.Services.AddSingleton<Lazy<IConfigObservationRepository>>(provider =>
    new Lazy<IConfigObservationRepository>(provider.GetRequiredService<IConfigObservationRepository>));
builder.Services.AddSingleton<Lazy<IPumpArchiveRepository>>(provider =>
    new Lazy<IPumpArchiveRepository>(provider.GetRequiredService<IPumpArchiveRepository>));
builder.Services.AddSingleton<Lazy<IRecordingAlertArchiveRepository>>(provider =>
    new Lazy<IRecordingAlertArchiveRepository>(provider.GetRequiredService<IRecordingAlertArchiveRepository>));
builder.Services.AddSingleton<Lazy<IHistoricalConfigChangesRepository>>(provider =>
    new Lazy<IHistoricalConfigChangesRepository>(provider.GetRequiredService<IHistoricalConfigChangesRepository>));
builder.Services.AddSingleton<Lazy<IAlarmRepository>>(provider =>
    new Lazy<IAlarmRepository>(provider.GetRequiredService<IAlarmRepository>));
builder.Services.AddSingleton<Lazy<IPermissionService>>(provider =>
    new Lazy<IPermissionService>(provider.GetRequiredService<IPermissionService>));


//as singleton to cache mapping
builder.Services.AddSingleton<IPoCMappingService, PoCMappingService>();

builder.Services.AddSingleton<CalculatedObservationsService>();
builder.Services.AddSingleton<PublisherService>();
builder.Services.AddSingleton<ReceiverService>();
builder.Services.AddSingleton<SchedulerService>();
builder.Services.AddSingleton<AuthUtils>();
builder.Services.AddSingleton<SubscribersService>();
builder.Services.AddSingleton<SubscriberGroupedService>();
//builder.Services.AddSingleton<MongoClient>(x => new MongoClient(x.GetRequiredService<IOptions<DatabaseSettings>>()));
builder.Services.AddSingleton<IClientMessageService, WebSocketMessageService>();
builder.Services.AddSingleton<IRelayService, RelayService>();

builder.Services.AddHttpClient();

builder.Services.AddCors(options =>
{
    options.AddPolicy("OpenCors", policy =>
    {
        policy
            .AllowAnyOrigin()
            .AllowAnyMethod()
            .AllowAnyHeader();
    });
});

var app = builder.Build();

// MongoDB Migration
app.RunMongoMigrations();

app.Services.GetRequiredService<SubscribersService>();
app.Services.GetRequiredService<SubscriberGroupedService>();

app.Services.GetRequiredService<IClientMessageService>();
app.Services.GetRequiredService<IPublisherService>();
app.Services.GetRequiredService<ReceiverService>();
app.Services.GetRequiredService<SchedulerService>();
app.Services.GetRequiredService<ICalculatedObservationsService>();


app.UseSwagger();
app.UseSwaggerUI();


app.UseStaticFiles();

//ws config
var webSocketOptions = new WebSocketOptions
{
    KeepAliveInterval = TimeSpan.FromSeconds(120)
};
// Auth

app.UseAuthentication();
app.UseAuthorization();

// Websockets
app.UseWebSockets(webSocketOptions);
app.MapHub<UciHub>("/subscribe");
app.MapHub<UciHub>("/chatMessage");

//app.UseCors(c => c.AllowAnyMethod().AllowAnyHeader().SetIsOriginAllowed(_ => true).AllowCredentials());
app.UseCors("OpenCors");
app.UseMiddleware<ErrorHandlerMiddleware>();
app.MapControllers();

app.Run();