using Serilog;
using Yuna.Website.Server.API;
using Yuna.Website.Server.Infrastructure;
using Yuna.Website.Server.Services.DeviceService;
using Yuna.Website.Server.Services.DeviceSkillService;
using Yuna.Website.Server.Services.OpenAuthService;
using Yuna.Website.Server.Services.TokenService;
using Yuna.Website.Server.Services.UserService;
using Yuna.Website.Server.Storage;
using Yuna.Website.Server.Storage.Repositories.Device;
using Yuna.Website.Server.Storage.Repositories.Prop;
using Yuna.Website.Server.Storage.Repositories.User;
using Yuna.Website.Server.Storage.Repositories.UserBindings;

namespace Yuna.Website.Server
{
    public class Starter
    {
        public static void LoadConfigs(WebApplicationBuilder builder)
        {
            Settings.Init();
        }

        /// <summary>
        /// Логгирование через Serilog: логгирует все в консоль
        /// </summary>
        /// <param name="builder"></param>
        private static void DefineLogger(WebApplicationBuilder builder)
        {
            builder.Logging.ClearProviders();
            var logger = new LoggerConfiguration()
            .WriteTo.Console()
            /* .WriteTo.File($"{DateTime.Now.ToString("dd_MM_yyyy_HH_mm_ss_f")}.txt") */
            //.Filter.ByIncludingOnly(x => x.Level == Serilog.Events.LogEventLevel.Error)
            .CreateLogger();

            builder.Logging.AddSerilog(logger);
        }

        private static void DefineDb(WebApplicationBuilder builder)
        {
            builder.Services.AddSingleton<DapperContext>();
            Console.ForegroundColor = ConsoleColor.DarkGreen;
            Console.WriteLine($"Added Db host: {Settings.DbConnectionStr}");
            Console.ResetColor();
        }

        public static void ApplyMigrations(WebApplication app)
        {
            //using var scope = app.Services.CreateScope();
            //var services = scope.ServiceProvider;

            //var context = services.GetRequiredService<AppDbContext>();
            //if (context.Database.GetPendingMigrations().Any())
            //{
            //    Console.ForegroundColor = ConsoleColor.DarkGreen;
            //    Console.WriteLine($"Applying migrations...");
            //    Console.ResetColor();
            //    context.Database.Migrate();
            //}
        }

        public static void DefineEndpoints(WebApplication app)
        {
            new OpenAuthEndpoints().Define(app);
            new AuthEndpoints().Define(app);
            new SkillsEndpoints().Define(app);
            new DeviceEndpoints().Define(app);
            //new FacadeEndpoints().Define(app);

            Console.ForegroundColor = ConsoleColor.DarkGreen;
            Console.WriteLine("Endpoints registered");
            Console.ResetColor();
        }

        public static void DefineHttpClient(WebApplicationBuilder builder)
        {
            builder.Services.AddHttpClient();
        }


        /// <summary>
        /// Подключение кеша для журнала состояний
        /// </summary>
        /// <param name="builder"></param>
        public static void DefineCache(WebApplicationBuilder builder)
        {
            //builder.Services.AddStackExchangeRedisCache(x =>
            //{
            //    x.Configuration = builder.Configuration.GetConnectionString("Redis")
            //    ?? throw new Exception("no redis str");
            //    x.InstanceName = "api_";
            //});

            //Console.ForegroundColor = ConsoleColor.DarkGreen;
            //Console.WriteLine($"Added redis host: {builder.Configuration.GetConnectionString("Redis")}");
            //Console.ResetColor();
        }

        public static void DefineMessaging(WebApplicationBuilder builder)
        {
            //builder.Services.RegisterEasyNetQ(Settings.RabbitMQHost, s => s.EnableSystemTextJson());
            //DefineQueuePublishers(builder);
            //DefineQueueSubscribers(builder);
            //DefineRpcClients(builder);
            //DefineRpcServers(builder);
        }

        public static void DefineQueuePublishers(WebApplicationBuilder builder)
        {
            //builder.Services.AddSingleton<ITimeEventPublisher, TimeEventPublisher>();
        }

        public static void DefineQueueSubscribers(WebApplicationBuilder builder)
        {
            //builder.Services.AddSingleton<ApiRpcConsumer>();
        }

        public static void DefineRpcServers(WebApplicationBuilder builder)
        {
            //builder.Services.AddHostedService<TelegramReplier>();
        }

        public static void DefineRpcClients(WebApplicationBuilder builder)
        {

        }

        public static void DefineCustomServices(WebApplicationBuilder builder)
        {
            builder.Services.AddScoped<IUserService, UserService>();
            builder.Services.AddScoped<IPropService, PropService>();
            builder.Services.AddScoped<ITokenService, TokenService>();
            builder.Services.AddScoped<IDeviceService, DeviceService>();
            builder.Services.AddScoped<IOpenAuthService, OpenAuthService>();


            builder.Services.AddScoped<IDeviceRepository, DeviceRepository>();
            builder.Services.AddScoped<IPropRepository, PropRepository>();
            builder.Services.AddScoped<IUserRepository, UserRepository>();
            builder.Services.AddScoped<IUserBindingsRepository, UserBindingRepository>();
        }

        public static void DefineAuth(WebApplicationBuilder builder)
        {
            builder.Services.AddAuthorization();
            builder.Services
                .AddAuthentication()
                .AddCookie(options =>
                {
                    options.Cookie = new()
                    {
                        SameSite = SameSiteMode.None,
                        SecurePolicy = CookieSecurePolicy.Always,
                        HttpOnly = true,
                        IsEssential = true,
                        Name = "access_token",
                        MaxAge = TimeSpan.FromDays(180),
                    };
                    options.SlidingExpiration = false;
                    options.ExpireTimeSpan = Settings.RefreshTokenLifeTime;
                    options.Events = new()
                    {
                        OnRedirectToAccessDenied = HttpHelper.BypassWithStatusCode(403),
                        OnRedirectToLogin = HttpHelper.BypassWithStatusCode(401)
                    };
                }
                );
        }

        public static void RegisterServices(WebApplicationBuilder builder)
        {
            LoadConfigs(builder);

            DefineMessaging(builder);

            DefineCustomServices(builder);

            DefineDb(builder);

            DefineLogger(builder);

            DefineCache(builder);

            DefineHttpClient(builder);

            DefineAuth(builder);

            builder.Services.AddEndpointsApiExplorer();

            builder.Services.AddSwaggerGen();

            builder.Services.AddCors();
            

            //builder.Services.AddAutoMapper(typeof(ApplicationProfile));
        }


        public static void Configure(WebApplication app)
        {
            if (app.Environment.IsDevelopment())
            {
                app.UseCors(x =>
                x.WithOrigins("https://localhost:5173", "http://localhost:5173", "https://192.168.1.2:5227")
                .AllowAnyMethod()
                .AllowAnyHeader()
                .AllowCredentials()
                 .SetIsOriginAllowed(origin => true) // Разрешить все источники
                          .WithExposedHeaders("Location")); // Разрешить заголовок Location)
                
            }

            else
            {
                app.UseCors(x => x.AllowAnyMethod().AllowAnyHeader().AllowCredentials());
            }
            app.UseAuthentication();
            app.UseAuthorization();
            app.UseDefaultFiles();
            app.UseStaticFiles();



            app.Use(async (context, next) =>
            {
                var isLoggedIn = context.User?.Identity?.IsAuthenticated ?? false;
                if (context.Request.Path.StartsWithSegments("/login") && isLoggedIn)
                {
                    context.Response.Redirect("/");
                    return;
                }

                await next();
            });

            // Configure the HTTP request pipeline.
            if (app.Environment.IsDevelopment())
            {
                app.UseSwagger();
                app.UseSwaggerUI();
            }

            //app.UseHttpsRedirection();

            app.MapFallbackToFile("/index.html");

        }
    }
}
