using CMSMicroservice.Application.Common.Interfaces;
using CMSMicroservice.Application.Common.Authorization;
using CMSMicroservice.Application.DayaLoanCQ.Services;
using CMSMicroservice.Infrastructure.Persistence;
using CMSMicroservice.Infrastructure.Persistence.Interceptors;
using CMSMicroservice.Infrastructure.BackgroundJobs;
using CMSMicroservice.Infrastructure.BackgroundServices;
using CMSMicroservice.Infrastructure.Services.Monitoring;
using CMSMicroservice.Infrastructure.Services.Authorization;
using CMSMicroservice.Infrastructure.Configuration;
using CMSMicroservice.Infrastructure.Services.Payment;
using CMSMicroservice.Infrastructure.Services.Commission;
using CMSMicroservice.Infrastructure.Repositories;
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<HistoryTrackingSaveChangesInterceptor>();
        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<IKavenegarService, KavenegarService>();
        services.AddSingleton<IUserPaymentLock, UserPaymentLockService>();
        // Local file manager — files are saved to wwwroot/uploads/ on CMS disk
        services.AddSingleton<CMSMicroservice.Application.Common.FileManager.IFileManager, LocalFileManager>();
        services.AddScoped<IPermissionService, PermissionService>();
        
        // Daya Loan API Service - قابل تغییر بین Mock و Real
        var useMockDayaApi = configuration.GetValue<bool>("DayaApi:UseMock", false);
        
        if (useMockDayaApi)
        {
            // Mock برای Development/Testing
            services.AddScoped<IDayaLoanApiService, MockDayaLoanApiService>();
        }
        else
        {
            // Real Implementation با HttpClient
            services.AddHttpClient<IDayaLoanApiService, DayaLoanApiService>()
                .SetHandlerLifetime(TimeSpan.FromMinutes(5))
                .ConfigureHttpClient((sp, client) =>
                {
                    var config = sp.GetRequiredService<IConfiguration>();
                    
                    // Base Address
                    var baseAddress = config["DayaApi:BaseAddress"] ?? "https://testdaya.tadbirandishan.com";
                    client.BaseAddress = new Uri(baseAddress);
                    
                    // Merchant Permission Key
                    var permissionKey = config["DayaApi:MerchantPermissionKey"];
                    if (!string.IsNullOrEmpty(permissionKey))
                    {
                        client.DefaultRequestHeaders.Add("merchant-permission-key", permissionKey);
                    }
                    
                    // Timeout
                    client.Timeout = TimeSpan.FromSeconds(30);
                });
        }
        
        // Payment Gateway Service - Multi-Provider Architecture
        // پشتیبانی از درگاه‌های مختلف: ZarinPal, Daya, Mock
        var paymentProvider = configuration.GetValue<string>("PaymentProvider", "Mock")?.ToLowerInvariant();
        
        switch (paymentProvider)
        {
            case "zarinpal":
                services.AddHttpClient<IPaymentGatewayService, ZarinPalPaymentService>()
                    .SetHandlerLifetime(TimeSpan.FromMinutes(5));
                break;
            
            case "daya":
                services.AddHttpClient<IPaymentGatewayService, DayaPaymentService>()
                    .SetHandlerLifetime(TimeSpan.FromMinutes(5));
                break;
            
            case "mock":
            default:
                services.AddScoped<IPaymentGatewayService, MockPaymentGatewayService>();
                break;
        }
        
        services.AddScoped<IApplicationDbContext>(p => p.GetRequiredService<ApplicationDbContext>());
        
        // Week Definition Repository - کش در حافظه برای هفته‌ها (Singleton برای کش، با IServiceScopeFactory برای دسترسی به DbContext)
        services.AddSingleton<WeekDefinitionRepository>();
        services.AddSingleton<IWeekDefinitionRepository>(sp => sp.GetRequiredService<WeekDefinitionRepository>());
        
        // Commission Calculation Strategy Factory - برای سوییچ بین ORM و SP
        services.AddScoped<ICommissionCalculationStrategyFactory, CommissionCalculationStrategyFactory>();
        
        // Chatika API Service - سرویس ایجاد حساب چتیکا
        services.AddHttpClient<IChatikaApiService, ChatikaApiService>()
            .SetHandlerLifetime(TimeSpan.FromMinutes(5))
            .ConfigureHttpClient((sp, client) =>
            {
                var config = sp.GetRequiredService<IConfiguration>();
                client.Timeout = TimeSpan.FromSeconds(30);
            });
        
        // Background Workers - Deprecated: Using Hangfire instead
        // services.AddHostedService<WeeklyNetworkCommissionWorker>();
        services.AddScoped<WeeklyCommissionJob>(); // Hangfire Job (Scoped for DI)
        services.AddScoped<ChatikaAccountActivationJob>(); // Hangfire Job for Chatika activation
        
        // Expire pending discount orders after 30 minutes
        services.AddHostedService<ExpirePendingOrdersService>();
        
        // One-time: Initialize inventory records for existing products
        if (configuration.GetValue<bool>("SeedWorkers:InventoryInitializer:Enabled"))
            services.AddHostedService<InventoryInitializerService>();
        
        // One-time: Seed ClubMembershipCycle for existing active memberships
        if (configuration.GetValue<bool>("SeedWorkers:MagicWalletCycleSeed:Enabled"))
            services.AddHostedService<MagicWalletCycleSeedService>();
        
        // Q26: Auto-deploy stored procedures on startup (checksum-based)
        services.AddHostedService<StoredProcedureDeploymentService>();
        
        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)));
        }
        
        // Inventory Business Service
        services.AddScoped<IInventoryService, InventoryService>();
        
        #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;
    }
}