using CMSMicroservice.Infrastructure.Persistence;
using CMSMicroservice.Infrastructure.Data.Seeding;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Logging;
using Serilog.Core;
using Serilog;
using System.Reflection;
using Microsoft.OpenApi.Models;
using CMSMicroservice.WebApi.Common.Behaviours;
using Hangfire;
using Hangfire.SqlServer;

var builder = WebApplication.CreateBuilder(args);
var levelSwitch = new LoggingLevelSwitch();
var logger = new LoggerConfiguration()
     //.WriteTo.Console()
     //.WriteTo.MSSqlServer(builder.Configuration.GetConnectionString("LogConnection"),
     //    sinkOptions: new MSSqlServerSinkOptions
     //    {
     //        TableName = "LogCMSEvents",
     //        SchemaName = "Log",
     //        AutoCreateSqlTable = true
     //    })
     .WriteTo.Seq("https://seq.afrino.co",
                  apiKey: "oxpvpUzU1pZxMS4s3Fqq",
                  controlLevelSwitch: levelSwitch)
    .CreateLogger();
builder.Logging.AddSerilog(logger);
#if DEBUG
Serilog.Debugging.SelfLog.Enable(msg => Console.WriteLine(msg));
#endif

// Additional configuration is required to successfully run gRPC on macOS.
// For instructions on how to configure Kestrel and gRPC clients on macOS, visit https://go.microsoft.com/fwlink/?linkid=2099682

// Add services to the container.

builder.Services.AddGrpc(options =>
{
    options.Interceptors.Add<LoggingBehaviour>();
    options.Interceptors.Add<PerformanceBehaviour>();
    //options.Interceptors.Add<ExceptionHandlingBehaviour>();
    options.EnableDetailedErrors = true;
    options.MaxReceiveMessageSize = 1000 * 1024 * 1024; // 1 GB
    options.MaxSendMessageSize = 1000 * 1024 * 1024; // 1 GB
}).AddJsonTranscoding();
builder.Services.AddApplicationServices();
builder.Services.AddInfrastructureServices(builder.Configuration);
builder.Services.AddPresentationServices(builder.Configuration);
builder.Services.AddProtobufServices();

#region Configure Hangfire
builder.Services.AddHangfire(config => config
    .SetDataCompatibilityLevel(CompatibilityLevel.Version_180)
    .UseSimpleAssemblyNameTypeSerializer()
    .UseRecommendedSerializerSettings()
    .UseSqlServerStorage(builder.Configuration["ConnectionStrings:DefaultConnection"]));
builder.Services.AddHangfireServer();
#endregion

#region Configure Health Checks
builder.Services.AddHealthChecks()
    .AddDbContextCheck<ApplicationDbContext>("database");
#endregion

// Add Controllers for REST APIs
builder.Services.AddControllers();

#region Configure Cors

builder.Services.AddCors(options =>
{
    options.AddPolicy("AllowAll",
        builder => builder.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader().WithExposedHeaders("Grpc-Status",
            "Grpc-Message", "Grpc-Encoding", "Grpc-Accept-Encoding", "validation-errors-text"));
});

#endregion
builder.Services.AddGrpcSwagger();
builder.Services.AddSwaggerGen(c =>
{
    c.SwaggerDoc("v1", new OpenApiInfo { Title = "gRPC transcoding", Version = "v1" });
    c.CustomSchemaIds(type=>type.ToString());
    c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
    {
        In = ParameterLocation.Header,
        Description = "Please insert JWT with Bearer into field",
        Name = "Authorization",
        Type = SecuritySchemeType.ApiKey
    });
    c.AddSecurityRequirement(new OpenApiSecurityRequirement
    {
        {
            new OpenApiSecurityScheme
            {
                Reference = new OpenApiReference
                {
                    Type = ReferenceType.SecurityScheme,
                    Id = "Bearer"
                }
            },
            new string[] { }
        }
    });
});
var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
    app.UseMigrationsEndPoint();

    // Initialise and seed database
    using (var scope = app.Services.CreateScope())
    {
        var initialiser = scope.ServiceProvider.GetRequiredService<ApplicationDbContextInitialiser>();
        await initialiser.InitialiseAsync();
        await initialiser.SeedAsync();
        
        // Run Migration: ParentId → NetworkParentId (فقط یکبار اجرا می‌شود)
        var migrationLogger = scope.ServiceProvider.GetRequiredService<ILogger<NetworkParentIdMigrationSeeder>>();
        var dbContext = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
        var migrationSeeder = new NetworkParentIdMigrationSeeder(dbContext, migrationLogger);
        await migrationSeeder.SeedAsync();
    }
}
else
{
    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
    app.UseHsts();
}


app.UseRouting();
app.UseCors("AllowAll");
app.UseAuthentication();
app.UseAuthorization();

// Map Health Check endpoints
app.MapHealthChecks("/health");
app.MapHealthChecks("/health/ready", new Microsoft.AspNetCore.Diagnostics.HealthChecks.HealthCheckOptions
{
    Predicate = check => check.Tags.Contains("ready")
});
app.MapHealthChecks("/health/live", new Microsoft.AspNetCore.Diagnostics.HealthChecks.HealthCheckOptions
{
    Predicate = _ => false
});
app.MapControllers();
app.UseGrpcWeb(new GrpcWebOptions { DefaultEnabled = true }); // Configure the HTTP request pipeline.
app.ConfigureGrpcEndpoints(Assembly.GetExecutingAssembly(), endpoints =>
{
    // endpoints.MapGrpcService<ExampleService>();
});

app.MapGet("/", () => "Communication with gRPC endpoints must be made through a gRPC client. To learn how to create a client, visit: https://go.microsoft.com/fwlink/?linkid=2086909");
app.UseSwagger();
app.UseSwaggerUI(c =>
{
    c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
});

// Configure Hangfire Dashboard
app.UseHangfireDashboard("/hangfire", new Hangfire.DashboardOptions
{
    // TODO: برای production از Authorization filter استفاده کنید
    Authorization = Array.Empty<Hangfire.Dashboard.IDashboardAuthorizationFilter>()
});

// Configure Recurring Jobs
using (var scope = app.Services.CreateScope())
{
    var recurringJobManager = scope.ServiceProvider.GetRequiredService<IRecurringJobManager>();
    
    // Weekly Commission Calculation: Every Sunday at 00:05 (UTC)
    recurringJobManager.AddOrUpdate<CMSMicroservice.Infrastructure.BackgroundJobs.WeeklyCommissionJob>(
        recurringJobId: "weekly-commission-calculation",
        methodCall: job => job.ExecuteAsync(CancellationToken.None),
        cronExpression: "5 0 * * 0", // Sunday at 00:05
        options: new RecurringJobOptions
        {
            TimeZone = TimeZoneInfo.Utc
        });
    
    app.Logger.LogInformation("✅ Hangfire recurring job 'weekly-commission-calculation' registered (Cron: 5 0 * * 0 - Sunday 00:05 UTC)");
    
    // Daya Loan Check: Every 15 minutes
    CMSMicroservice.WebApi.Workers.DayaLoanCheckWorker.Schedule(recurringJobManager);
    app.Logger.LogInformation("✅ Hangfire recurring job 'daya-loan-check' registered (Cron: */15 * * * * - Every 15 minutes)");
}

app.Run();
