using Microsoft.EntityFrameworkCore;
using System.Data;
using FluentValidation;
using Hellang.Middleware.ProblemDetails;
using Microsoft.AspNetCore.SignalR;
using Npgsql;
using OrderService.API.Application.Behaviors;
using OrderService.API.Application.Strategies;
using OrderService.API.Hubs;
using OrderService.API.Infrastructure.HttpClients;
using OrderService.API.Infrastructure.Tenant;
using OrderService.API.Middleware;
using OrderService.Domain.Strategies;
using OrderService.Infrastructure;
using Polly;
using Polly.Extensions.Http;
using Serilog;
using StackExchange.Redis;

// EN: Configure Serilog early / VI: Cấu hình Serilog sớm
Log.Logger = new LoggerConfiguration()
    .WriteTo.Console()
    .CreateBootstrapLogger();

try
{
    Log.Information("Starting OrderService API / Khởi động OrderService API");

    var builder = WebApplication.CreateBuilder(args);

    // EN: Configure Serilog / VI: Cấu hình Serilog
    builder.Host.UseSerilog((context, services, configuration) => configuration
        .ReadFrom.Configuration(context.Configuration)
        .ReadFrom.Services(services)
        .Enrich.FromLogContext()
        .WriteTo.Console());

    // EN: Add Infrastructure services / VI: Thêm Infrastructure services
    builder.Services.AddInfrastructure(builder.Configuration);

    // EN: Register multi-tenant services for row-level security
    // VI: Đăng ký multi-tenant services cho bảo mật row-level
    builder.Services.AddHttpContextAccessor();
    builder.Services.AddScoped<ITenantProvider, HttpContextTenantProvider>();
    builder.Services.AddScoped<IOrderTenantProvider, OrderTenantProviderAdapter>();

    // EN: Add Dapper IDbConnection / VI: Thêm Dapper IDbConnection
    builder.Services.AddTransient<IDbConnection>(sp =>
    {
        var connectionString = builder.Configuration.GetConnectionString("DefaultConnection")
            ?? builder.Configuration["DATABASE_URL"]
            ?? throw new InvalidOperationException("Database connection string is required");
        return new NpgsqlConnection(connectionString);
    });

    // EN: Add HTTP Clients with Polly / VI: Thêm HTTP Clients với Polly
    var retryPolicy = HttpPolicyExtensions
        .HandleTransientHttpError()
        .WaitAndRetryAsync(3, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)));

    var circuitBreakerPolicy = HttpPolicyExtensions
        .HandleTransientHttpError()
        .CircuitBreakerAsync(5, TimeSpan.FromSeconds(30));

    builder.Services.AddHttpClient<CatalogServiceClient>(client =>
        {
            client.BaseAddress = new Uri(builder.Configuration["Services:CatalogService"] ?? "http://catalog-service-net:8080");
            client.Timeout = TimeSpan.FromSeconds(10);
        })
        .AddPolicyHandler(retryPolicy)
        .AddPolicyHandler(circuitBreakerPolicy);

    builder.Services.AddHttpClient<InventoryServiceClient>(client =>
        {
            client.BaseAddress = new Uri(builder.Configuration["Services:InventoryService"] ?? "http://inventory-service-net:8080");
            client.Timeout = TimeSpan.FromSeconds(10);
        })
        .AddPolicyHandler(retryPolicy)
        .AddPolicyHandler(circuitBreakerPolicy);

    builder.Services.AddHttpClient<BookingServiceClient>(client =>
        {
            client.BaseAddress = new Uri(builder.Configuration["Services:BookingService"] ?? "http://booking-service-net:8080");
            client.Timeout = TimeSpan.FromSeconds(10);
        })
        .AddPolicyHandler(retryPolicy)
        .AddPolicyHandler(circuitBreakerPolicy);

    builder.Services.AddHttpClient<FnbEngineClient>(client =>
        {
            client.BaseAddress = new Uri(builder.Configuration["Services:FnbEngine"] ?? "http://fnb-engine-net:8080");
            client.Timeout = TimeSpan.FromSeconds(10);
        })
        .AddPolicyHandler(retryPolicy)
        .AddPolicyHandler(circuitBreakerPolicy);

    builder.Services.AddHttpClient<OrderService.Infrastructure.ExternalServices.WalletServiceClient>(client =>
        {
            client.BaseAddress = new Uri(builder.Configuration["Services:WalletService"] ?? "http://wallet-service-net:8080");
            client.Timeout = TimeSpan.FromSeconds(15);
        })
        .AddPolicyHandler(retryPolicy)
        .AddPolicyHandler(circuitBreakerPolicy);

    // EN: Register Strategies / VI: Đăng ký Strategies
    builder.Services.AddTransient<ILineItemStrategy, RetailStrategy>();
    builder.Services.AddTransient<ILineItemStrategy, ServiceStrategy>();
    builder.Services.AddTransient<ILineItemStrategy, FnbStrategy>();
    builder.Services.AddSingleton<StrategyFactory>();

    // EN: Add MediatR with behaviors / VI: Thêm MediatR với behaviors
    builder.Services.AddMediatR(cfg =>
    {
        cfg.RegisterServicesFromAssemblyContaining<Program>();
        cfg.AddOpenBehavior(typeof(LoggingBehavior<,>));
        cfg.AddOpenBehavior(typeof(ValidatorBehavior<,>));
        cfg.AddOpenBehavior(typeof(TransactionBehavior<,>));
    });

    // EN: Add FluentValidation / VI: Thêm FluentValidation
    builder.Services.AddValidatorsFromAssemblyContaining<Program>();

    // EN: Add SignalR with Redis Backplane and MessagePack for POS/KDS real-time updates
    // VI: Thêm SignalR với Redis Backplane và MessagePack cho POS/KDS real-time updates
    var redisConnection = builder.Configuration.GetConnectionString("Redis")
        ?? builder.Configuration["Redis:ConnectionString"]
        ?? "localhost:6379";
    var signalRBuilder = builder.Services.AddSignalR(options =>
    {
        options.EnableDetailedErrors = builder.Environment.IsDevelopment();
        options.KeepAliveInterval = TimeSpan.FromSeconds(
            builder.Configuration.GetValue("SignalR:KeepAliveInterval", 15));
        options.ClientTimeoutInterval = TimeSpan.FromSeconds(
            builder.Configuration.GetValue("SignalR:ClientTimeoutInterval", 30));

        // EN: Enable Stateful Reconnect (.NET 8+) / VI: Bật Stateful Reconnect
        options.StatefulReconnectBufferSize =
            builder.Configuration.GetValue("SignalR:StatefulReconnectBufferSize", 32768);
    });

    // EN: Add Redis Backplane for scaling / VI: Thêm Redis Backplane để scale
    signalRBuilder.AddStackExchangeRedis(redisConnection, options =>
    {
        options.Configuration.ChannelPrefix = RedisChannel.Literal("OrderService");
        options.Configuration.AbortOnConnectFail = false;
    });

    // EN: Add MessagePack protocol for better performance / VI: Thêm MessagePack cho hiệu năng tốt hơn
    if (builder.Configuration.GetValue("SignalR:EnableMessagePack", true))
    {
        signalRBuilder.AddMessagePackProtocol();
    }

    // EN: Add custom User ID provider / VI: Thêm custom User ID provider
    builder.Services.AddSingleton<IUserIdProvider, ClaimsUserIdProvider>();

    // EN: Register POS notification service and connection manager
    // VI: Đăng ký POS notification service và connection manager
    builder.Services.AddSingleton<PosConnectionManager>();
    builder.Services.AddScoped<IPosNotificationService, PosNotificationService>();

    // EN: Add controllers / VI: Thêm controllers
    builder.Services.AddControllers();

    // EN: Add ProblemDetails middleware (RFC 7807) / VI: Thêm ProblemDetails middleware
    builder.Services.AddProblemDetails(options =>
    {
        options.IncludeExceptionDetails = (ctx, ex) =>
            builder.Environment.IsDevelopment();
    });

    // EN: Add Swagger / VI: Thêm Swagger
    builder.Services.AddEndpointsApiExplorer();
    builder.Services.AddSwaggerGen(options =>
    {
        options.SwaggerDoc("v1", new()
        {
            Title = "OrderService API",
            Version = "v1",
            Description = "OrderService microservice API / API microservice OrderService"
        });
    });

    // EN: Add health checks / VI: Thêm health checks
    builder.Services.AddHealthChecks()
        .AddNpgSql(
            builder.Configuration.GetConnectionString("DefaultConnection")
                ?? builder.Configuration["DATABASE_URL"]
                ?? "",
            name: "postgresql",
            tags: ["db", "postgresql"])
        .AddRedis(
            redisConnection,
            name: "redis",
            tags: ["cache", "redis"]);

    // EN: Add JWT Bearer authentication via IAM IdentityServer OIDC discovery
    // VI: Thêm JWT Bearer authentication qua IAM IdentityServer OIDC discovery
    var jwtAuthority = builder.Configuration["Jwt:Authority"] ?? "http://localhost:5001";
    builder.Services.AddAuthentication(Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerDefaults.AuthenticationScheme)
        .AddJwtBearer(options =>
        {
            options.Authority = jwtAuthority;
            options.RequireHttpsMetadata = false;
            options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
            {
                ValidateIssuer = false,
                ValidateAudience = false,
                ValidateLifetime = true,
            };

            // EN: Allow SignalR to receive JWT from query string (WebSocket can't use headers)
            // VI: Cho phép SignalR nhận JWT từ query string (WebSocket không thể dùng headers)
            options.Events = new Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerEvents
            {
                OnMessageReceived = context =>
                {
                    var accessToken = context.Request.Query["access_token"];
                    var path = context.HttpContext.Request.Path;
                    if (!string.IsNullOrEmpty(accessToken) && path.StartsWithSegments("/hubs"))
                    {
                        context.Token = accessToken;
                    }
                    return Task.CompletedTask;
                }
            };
        });
    builder.Services.AddAuthorization();

    // EN: Add CORS (AllowCredentials required for SignalR WebSocket)
    // VI: Thêm CORS (AllowCredentials bắt buộc cho SignalR WebSocket)
    builder.Services.AddCors(options =>
    {
        options.AddDefaultPolicy(policy =>
        {
            policy.WithOrigins(
                    builder.Configuration.GetSection("AllowedOrigins").Get<string[]>()
                    ?? ["http://localhost:3000", "http://localhost:5173", "http://localhost:5000"])
                  .AllowAnyMethod()
                  .AllowAnyHeader()
                  .AllowCredentials(); // EN: Required for SignalR / VI: Bắt buộc cho SignalR
        });
    });

    var app = builder.Build();

    // EN: Configure middleware pipeline / VI: Cấu hình middleware pipeline
    app.UseSerilogRequestLogging();
    app.UseProblemDetails();

    if (app.Environment.IsDevelopment())
    {
        app.UseSwagger();
        app.UseSwaggerUI(c =>
        {
            c.SwaggerEndpoint("/swagger/v1/swagger.json", "OrderService API v1");
            c.RoutePrefix = "swagger";
        });
    }

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

    // EN: Set tenant context for row-level security (must be after auth)
    // VI: Đặt tenant context cho bảo mật row-level (phải sau auth)
    app.UseTenantMiddleware();

    // EN: Map health check endpoints / VI: Map health check endpoints
    app.MapHealthChecks("/health");
    app.MapHealthChecks("/health/live", new()
    {
        Predicate = _ => false // EN: Just checks app is running / VI: Chỉ kiểm tra app đang chạy
    });
    app.MapHealthChecks("/health/ready");

    // EN: Map controllers / VI: Map controllers
    app.MapControllers();

    // EN: Map SignalR POS Hub / VI: Map SignalR POS Hub
    app.MapHub<PosHub>("/hubs/pos", options =>
    {
        options.AllowStatefulReconnects = true;
    });

    // EN: Run the application / VI: Chạy ứng dụng
    // EN: Auto-apply EF Core migrations on startup
    // VI: Tự động áp dụng EF Core migrations khi khởi động
    try
    {
        using (var scope = app.Services.CreateScope())
        {
            var dbContext = scope.ServiceProvider.GetRequiredService<OrderContext>();
            await dbContext.Database.MigrateAsync();
        }
    }
    catch (Exception ex)
    {
        // EN: Log migration errors but don't crash the app (e.g. PendingModelChangesWarning in EF Core 10)
        // VI: Log lỗi migration nhưng không crash app
        Console.WriteLine($"Warning: EF Core migration issue: {ex.Message}");
    }

    app.Run();
}
catch (Exception ex)
{
    Log.Fatal(ex, "Application terminated unexpectedly / Ứng dụng kết thúc bất ngờ");
    throw;
}
finally
{
    Log.CloseAndFlush();
}

// EN: Make Program class accessible for integration tests
// VI: Làm cho class Program có thể truy cập cho integration tests
public partial class Program { }
