using CMSMicroservice.Application.Common.Interfaces;
using CMSMicroservice.Application.DayaLoanCQ.Services;
using CMSMicroservice.Infrastructure.Persistence;
using CMSMicroservice.Infrastructure.Persistence.Interceptors;
using CMSMicroservice.Infrastructure.BackgroundJobs;
using CMSMicroservice.Infrastructure.Services.Monitoring;
using CMSMicroservice.Infrastructure.Configuration;
using CMSMicroservice.Infrastructure.Services.Payment;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Http;
using System.Diagnostics;
using Microsoft.IdentityModel.Tokens;
using System.Text;
using CMSMicroservice.Infrastructure.Services;

namespace Microsoft.Extensions.DependencyInjection;

public static class ConfigureServices
{
    public static IServiceCollection AddInfrastructureServices(this IServiceCollection services, IConfiguration configuration)
    {
        // Configuration Settings
        services.Configure<EmailSettings>(configuration.GetSection(EmailSettings.SectionName));
        services.Configure<SmsSettings>(configuration.GetSection(SmsSettings.SectionName));
        
        services.AddScoped<AuditableEntitySaveChangesInterceptor>();
        services.AddScoped<ApplicationDbContextInitialiser>();
        services.AddScoped<IGenerateJwtToken, GenerateJwtTokenService>();
        services.AddScoped<IHashService, HashService>();
        services.AddScoped<INetworkPlacementService, NetworkPlacementService>();
        services.AddScoped<IAlertService, AlertService>();
        services.AddScoped<IUserNotificationService, UserNotificationService>();
        services.AddScoped<IDayaLoanApiService, MockDayaLoanApiService>(); // Mock - جایگزین با Real برای Production
        
        // Payment Gateway Service - فقط Daya (درگاه اینترنتی از Gateway میاد نه CMS)
        var useRealPaymentGateway = configuration.GetValue<bool>("UseRealPaymentGateway", false);
        
        if (useRealPaymentGateway)
        {
            // فقط Daya برای پرداخت به کاربران (Payout)
            services.AddHttpClient<IPaymentGatewayService, DayaPaymentService>()
                .SetHandlerLifetime(TimeSpan.FromMinutes(5));
        }
        else
        {
            // Mock برای Development و Testing
            services.AddScoped<IPaymentGatewayService, MockPaymentGatewayService>();
        }
        
        services.AddScoped<IApplicationDbContext>(p => p.GetRequiredService<ApplicationDbContext>());
        
        // Background Workers - Deprecated: Using Hangfire instead
        // services.AddHostedService<WeeklyNetworkCommissionWorker>();
        services.AddScoped<WeeklyCommissionJob>(); // Hangfire Job (Scoped for DI)
        
        if (configuration.GetValue<bool>("UseInMemoryDatabase"))
        {
            services.AddDbContext<ApplicationDbContext>(options =>
                options.UseInMemoryDatabase("MyMemoryDb"));
        }
        else
        {
            services.AddDbContext<ApplicationDbContext>(options =>
                options.UseSqlServer(configuration.GetConnectionString("DefaultConnection"),
                    builder => builder.MigrationsAssembly(typeof(ApplicationDbContext).Assembly.FullName)));
        }
        #region AddAuthentication

        var message = "";
        services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
            .AddJwtBearer(jwtBearerOptions =>
            {
                //jwtBearerOptions.Authority = configuration["Authentication:Authority"];
                //jwtBearerOptions.Audience = configuration["Authentication:Audience"];
                //jwtBearerOptions.TokenValidationParameters.ValidateAudience = false;                
                //jwtBearerOptions.TokenValidationParameters.ValidateIssuer = true;
                //jwtBearerOptions.TokenValidationParameters.ValidateIssuerSigningKey = false;

                jwtBearerOptions.SaveToken = true;
                jwtBearerOptions.RequireHttpsMetadata = false;
                jwtBearerOptions.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateIssuer = true,
                    ValidateAudience = true,
                    ValidateLifetime = true,
                    ValidateIssuerSigningKey = true,
                    ValidIssuer = configuration["JwtIssuer"],
                    ValidAudience = configuration["JwtAudience"],
                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(configuration["JwtSecurityKey"]))
                };
                try
                {
                    jwtBearerOptions.Events = new JwtBearerEvents
                    {
                        OnAuthenticationFailed = ctx =>
                        {
                            ctx.Response.StatusCode = StatusCodes.Status401Unauthorized;
                            message += "From OnAuthenticationFailed:\n";
                            message += ctx.Exception.Message;
                            return Task.CompletedTask;
                        },

                        OnChallenge = ctx =>
                        {
                            message += "From OnChallenge:\n";
                            ctx.Response.StatusCode = StatusCodes.Status401Unauthorized;
                            ctx.Response.ContentType = "text/plain";
                            return ctx.Response.WriteAsync(message);
                        },

                        OnMessageReceived = ctx =>
                        {
                            message = "From OnMessageReceived:\n";
                            ctx.Request.Headers.TryGetValue("Authorization", out var BearerToken);
                            if (BearerToken.Count == 0)
                                BearerToken = "no Bearer token sent\n";
                            message += "Authorization Header sent: " + BearerToken + "\n";
                            return Task.CompletedTask;
                        },

                        OnTokenValidated = ctx =>
                        {
                            Debug.WriteLine("token: " + ctx.SecurityToken.ToString());
                            return Task.CompletedTask;
                        }
                    };
                }
                catch (Exception e)
                {
                    Console.WriteLine(e);
                    throw;
                }
            });

        services.AddAuthorization();

        #endregion


        return services;
    }
}