using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using SolutionErp.Application.Common.Interfaces;
using SolutionErp.Application.Contracts.Services;
using SolutionErp.Application.ContractSigningPlans.Services;
using SolutionErp.Application.Forms.Services;
using SolutionErp.Application.Hrm.Services;
using SolutionErp.Application.Master.Suppliers.Import;
using SolutionErp.Application.Notifications;
using SolutionErp.Application.PurchaseEvaluations.Services;
using SolutionErp.Application.Reports.Services;
using SolutionErp.Domain.Identity;
using SolutionErp.Infrastructure.Forms;
using SolutionErp.Infrastructure.HostedServices;
using SolutionErp.Infrastructure.Identity;
using SolutionErp.Infrastructure.Persistence;
using SolutionErp.Infrastructure.Persistence.Interceptors;
using SolutionErp.Infrastructure.Reports;
using SolutionErp.Infrastructure.Services;
using SolutionErp.Infrastructure.Storage;

namespace SolutionErp.Infrastructure;

public static class DependencyInjection
{
    public static IServiceCollection AddInfrastructure(this IServiceCollection services, IConfiguration configuration)
    {
        services.AddSingleton<IDateTime, DateTimeService>();

        services.Configure<JwtSettings>(configuration.GetSection(JwtSettings.SectionName));
        services.AddScoped<IJwtTokenService, JwtTokenService>();

        services.AddSingleton<IFormRenderer, FormRenderer>();
        services.AddSingleton<IDocumentConverter, LibreOfficeDocumentConverter>();
        services.AddScoped<IContractCodeGenerator, ContractCodeGenerator>();
        services.AddScoped<IContractWorkflowService, ContractWorkflowService>();
        services.AddScoped<IPurchaseEvaluationWorkflowService, PurchaseEvaluationWorkflowService>();
        services.AddScoped<IPurchaseEvaluationCodeGenerator, PurchaseEvaluationCodeGenerator>();
        // [W1 Mig 69 — S161] mã phiếu KHKK/{YYYY}/{Seq:D3} qua WorkflowAppCodeSequences dùng chung.
        services.AddScoped<IContractSigningPlanCodeGenerator, ContractSigningPlanCodeGenerator>();
        // [W3 đợt-1 — S161] workflow duyệt 3 trạm KHKK. Đợt-1 = SKELETON (mọi nhánh ném
        // NotImplementedException); đăng ký sẵn để endpoint + test resolve được đúng chữ ký.
        services.AddScoped<IContractSigningPlanWorkflowService, ContractSigningPlanWorkflowService>();
        services.AddScoped<IEmployeeCodeGenerator, EmployeeCodeGenerator>();
        services.AddScoped<IContractExcelExporter, ContractExcelExporter>();
        services.AddScoped<IAttendanceReportExcelExporter, AttendanceReportExcelExporter>();
        services.AddScoped<INotificationService, NotificationService>();
        services.AddScoped<IChangelogService, ChangelogService>();
        services.AddScoped<ISupplierExcelImportService, SupplierExcelImportService>();
        services.AddSingleton<IFileStorage, LocalFileStorage>();

        // Phase 3 iteration 2 — SLA auto-approve background service
        services.AddHostedService<SlaExpiryJob>();
        // Phase 11 P11-D — IT ticket SLA timer (warning ≤20% + breach, no auto-transition)
        services.AddHostedService<ItTicketSlaJob>();

        services.AddScoped<AuditingInterceptor>();
        services.AddScoped<NotificationPushInterceptor>();

        services.AddDbContext<ApplicationDbContext>((sp, options) =>
        {
            var connectionString = configuration.GetConnectionString("Default")
                ?? throw new InvalidOperationException("Missing ConnectionStrings:Default");
            options.UseSqlServer(connectionString, sql => sql.MigrationsAssembly(typeof(ApplicationDbContext).Assembly.FullName));
            options.AddInterceptors(
                sp.GetRequiredService<AuditingInterceptor>(),
                sp.GetRequiredService<NotificationPushInterceptor>());
        });

        services.AddScoped<IApplicationDbContext>(sp => sp.GetRequiredService<ApplicationDbContext>());

        // Password policy + lockout — override prod qua appsettings.Production.json Identity section
        var minLen = configuration.GetValue<int?>("Identity:Password:RequiredLength") ?? 8;
        var lockoutMinutes = configuration.GetValue<int?>("Identity:Lockout:Minutes") ?? 15;
        var lockoutMaxFail = configuration.GetValue<int?>("Identity:Lockout:MaxFailedAttempts") ?? 5;

        services.AddIdentityCore<User>(options =>
            {
                options.Password.RequireDigit = true;
                options.Password.RequireLowercase = true;
                options.Password.RequireUppercase = true;
                options.Password.RequireNonAlphanumeric = true;
                options.Password.RequiredLength = minLen;
                options.User.RequireUniqueEmail = true;

                options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(lockoutMinutes);
                options.Lockout.MaxFailedAccessAttempts = lockoutMaxFail;
                options.Lockout.AllowedForNewUsers = true;
            })
            .AddRoles<Role>()
            .AddEntityFrameworkStores<ApplicationDbContext>();

        return services;
    }
}
