/*
 * File: D:\shadowed-realms-mobile\ShadowedRealmsMobile\src\server\ShadowedRealms.Admin\Program.cs
 * Created: 2025-10-30
 * Last Modified: 2025-11-04
 * Description: PRODUCTION-READY Admin Dashboard - Works for Dev/Prod databases on same server
 * Last Edit Notes: Added KingdomManagementService registration for database-integrated Kingdom Management
 */

using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using ShadowedRealms.Admin.Data;
using ShadowedRealms.Admin.Services;
using ShadowedRealms.Admin.Services.Interfaces;
using ShadowedRealms.API.Services;
using ShadowedRealms.Core.Interfaces;
using ShadowedRealms.Core.Interfaces.Repositories;
using ShadowedRealms.Core.Interfaces.Services;
using ShadowedRealms.Data;
using ShadowedRealms.Data.Contexts;
using ShadowedRealms.Data.Repositories;
using ShadowedRealms.Data.Repositories.Alliance;
using ShadowedRealms.Data.Repositories.Combat;
using ShadowedRealms.Data.Repositories.Kingdom;
using ShadowedRealms.Data.Repositories.Player;
using ShadowedRealms.Data.Repositories.Purchase;

// Resolve ApplicationUser ambiguity
using AdminUser = ShadowedRealms.Admin.Data.ApplicationUser;

var builder = WebApplication.CreateBuilder(args);

// ===============================
// ENVIRONMENT-AWARE DATABASE CONFIGURATION
// ===============================

// Determine environment and database names
var environment = builder.Environment.EnvironmentName.ToLower();
var isProduction = builder.Environment.IsProduction();

// Same server, different databases based on environment
string adminDbName = isProduction ? "ShadowedRealmsAdmin_Prod" : "ShadowedRealmsAdmin_Dev";
string gameDbName = isProduction ? "ShadowedRealms_Prod" : "ShadowedRealms_Dev";

// Base connection info (same server for both environments)
var dbHost = "209.25.140.218";
var dbPort = "5432";
var dbUser = "admin";
var dbPassword = "EWV+UMbQNMJLY5tAIKLZIJvn0Nx40k3PJLcO4Tmkns0=";

// Build connection strings
var adminConnectionString = $"Host={dbHost};Port={dbPort};Database={adminDbName};Username={dbUser};Password={dbPassword};SSL Mode=Prefer;Trust Server Certificate=true";
var gameConnectionString = $"Host={dbHost};Port={dbPort};Database={gameDbName};Username={dbUser};Password={dbPassword};SSL Mode=Prefer;Trust Server Certificate=true";

Console.WriteLine($"Environment: {environment}");
Console.WriteLine($"Admin Database: {adminDbName}");
Console.WriteLine($"Game Database: {gameDbName}");

// IDENTITY Database (for admin users and roles)
builder.Services.AddDbContext<ApplicationDbContext>(options =>
{
    options.UseNpgsql(adminConnectionString);

    if (builder.Environment.IsDevelopment())
    {
        options.EnableSensitiveDataLogging();
        options.EnableDetailedErrors();
    }
});

// GAME Database (for game data - read-only access)
builder.Services.AddDbContext<GameDbContext>(options =>
{
    options.UseNpgsql(gameConnectionString);

    if (builder.Environment.IsDevelopment())
    {
        options.EnableSensitiveDataLogging();
        options.EnableDetailedErrors();
    }
});

builder.Services.AddDatabaseDeveloperPageExceptionFilter();

// ===============================
// GAME SERVICES & REPOSITORIES REGISTRATION
// ===============================

// Register UnitOfWork pattern
builder.Services.AddScoped<IUnitOfWork, UnitOfWork>();

// Register all game repositories
builder.Services.AddScoped<IKingdomRepository, KingdomRepository>();
builder.Services.AddScoped<IPlayerRepository, PlayerRepository>();
builder.Services.AddScoped<IAllianceRepository, AllianceRepository>();
builder.Services.AddScoped<ICombatLogRepository, CombatLogRepository>();
builder.Services.AddScoped<IPurchaseLogRepository, PurchaseLogRepository>();

// Register combat engines and calculation services
builder.Services.AddScoped<ShadowedRealms.API.Services.CombatCalculationEngine>();
builder.Services.AddScoped<ShadowedRealms.API.Services.MarchSpeedEngine>();

// Register all game services from ShadowedRealms.API.Services
builder.Services.AddScoped<IKingdomService, KingdomService>();
builder.Services.AddScoped<IPlayerService, PlayerService>();
builder.Services.AddScoped<IAllianceService, AllianceService>();
builder.Services.AddScoped<ICombatService, CombatService>();
builder.Services.AddScoped<IPurchaseService, PurchaseService>();

// ===============================
// IDENTITY & AUTHENTICATION
// ===============================
builder.Services.AddDefaultIdentity<AdminUser>(options =>
{
    // Admin-specific identity options
    options.SignIn.RequireConfirmedAccount = false;
    options.Password.RequiredLength = 12;
    options.Password.RequireNonAlphanumeric = true;
    options.Password.RequireDigit = true;
    options.Password.RequireUppercase = true;
    options.Password.RequireLowercase = true;
    options.Lockout.MaxFailedAccessAttempts = 3;
    options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(30);
})
    .AddRoles<IdentityRole<int>>()
    .AddEntityFrameworkStores<ApplicationDbContext>();

// Authorization policies with Moderator role
builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("AdminOnly", policy => policy.RequireRole("Admin", "SuperAdmin", "GameMaster", "Moderator"));
    options.AddPolicy("SuperAdminOnly", policy => policy.RequireRole("SuperAdmin"));
    options.AddPolicy("GameMasterOnly", policy => policy.RequireRole("GameMaster", "SuperAdmin"));
    options.AddPolicy("ModeratorAccess", policy => policy.RequireRole("Moderator", "GameMaster", "SuperAdmin"));
    options.AddPolicy("PlayerManagement", policy => policy.RequireRole("PlayerManager", "GameMaster", "SuperAdmin"));
    options.AddPolicy("SystemMonitoring", policy => policy.RequireRole("SystemAdmin", "SuperAdmin"));
    options.AddPolicy("KingdomManagement", policy => policy.RequireRole("GameMaster", "SuperAdmin"));
    options.AddPolicy("KingdomMonitoring", policy => policy.RequireRole("Moderator", "GameMaster", "SuperAdmin")); // Mods can monitor kingdoms
    options.AddPolicy("AllianceManagement", policy => policy.RequireRole("GameMaster", "SuperAdmin"));
    options.AddPolicy("AllianceMonitoring", policy => policy.RequireRole("Moderator", "GameMaster", "SuperAdmin")); // Mods can monitor alliances
});

// ===============================
// ADMIN-SPECIFIC SERVICES
// ===============================
builder.Services.AddScoped<IAdminAnalyticsService, AdminAnalyticsService>();
builder.Services.AddScoped<IKingdomManagementService, KingdomManagementService>(); // NEW: Database-integrated Kingdom Management

// ===============================
// ADDITIONAL SERVICES
// ===============================
builder.Services.AddControllersWithViews();
builder.Services.AddHttpClient();
builder.Services.AddMemoryCache();

// ===============================
// LOGGING CONFIGURATION
// ===============================
builder.Logging.ClearProviders();
builder.Logging.AddConsole();
builder.Logging.AddDebug();

if (builder.Environment.IsDevelopment())
{
    builder.Logging.SetMinimumLevel(LogLevel.Debug);
}
else
{
    builder.Logging.SetMinimumLevel(LogLevel.Information);
}

var app = builder.Build();

// ===============================
// MIDDLEWARE PIPELINE
// ===============================

if (app.Environment.IsDevelopment())
{
    app.UseMigrationsEndPoint();
    app.UseDeveloperExceptionPage();
}
else
{
    app.UseExceptionHandler("/Home/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();

app.UseAuthentication();
app.UseAuthorization();

// ===============================
// ROUTING CONFIGURATION
// ===============================

// Kingdom Management routes
app.MapControllerRoute(
    name: "kingdom_management",
    pattern: "Admin/Kingdom/{action=Index}/{id?}",
    defaults: new { controller = "KingdomManagement" });

// Admin dashboard as default home
app.MapControllerRoute(
    name: "admin_dashboard_explicit",
    pattern: "Admin/AdminDashboard/{action=Index}/{id?}",
    defaults: new { controller = "AdminDashboard" });

// Root path goes to admin dashboard
app.MapControllerRoute(
    name: "default",
    pattern: "{controller=AdminDashboard}/{action=Index}/{id?}");

app.MapRazorPages();

// ===============================
// DATABASE INITIALIZATION - PRODUCTION READY
// ===============================
using (var scope = app.Services.CreateScope())
{
    var logger = scope.ServiceProvider.GetRequiredService<ILogger<Program>>();

    try
    {
        // *** ADMIN DATABASE SETUP ***
        logger.LogInformation($"Initializing admin database: {adminDbName}");
        var adminContext = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();

        // Create admin database if it doesn't exist
        var adminDbCreated = await adminContext.Database.EnsureCreatedAsync();
        if (adminDbCreated)
        {
            logger.LogInformation($"Created new admin database: {adminDbName}");
        }
        else
        {
            logger.LogInformation($"Admin database {adminDbName} already exists");
        }

        // *** GAME DATABASE VERIFICATION ***
        logger.LogInformation($"Connecting to game database: {gameDbName}");
        var gameContext = scope.ServiceProvider.GetRequiredService<GameDbContext>();
        var canConnect = await gameContext.Database.CanConnectAsync();

        if (canConnect)
        {
            // Verify key tables exist
            var playersExist = await gameContext.Set<ShadowedRealms.Core.Models.Player.Player>().AnyAsync();
            var kingdomsExist = await gameContext.Set<ShadowedRealms.Core.Models.Kingdom.Kingdom>().AnyAsync();

            logger.LogInformation($"Game database connection successful. Players exist: {playersExist}, Kingdoms exist: {kingdomsExist}");
        }
        else
        {
            logger.LogError($"Cannot connect to game database: {gameDbName}");
            throw new InvalidOperationException($"Game database {gameDbName} connection failed");
        }

    }
    catch (Exception ex)
    {
        logger.LogError(ex, "CRITICAL: Database initialization failed");
        throw; // Don't start the app if databases aren't working
    }
}

// ===============================
// SAFE ROLE & USER INITIALIZATION
// ===============================
using (var scope = app.Services.CreateScope())
{
    var logger = scope.ServiceProvider.GetRequiredService<ILogger<Program>>();

    try
    {
        var roleManager = scope.ServiceProvider.GetRequiredService<RoleManager<IdentityRole<int>>>();
        var userManager = scope.ServiceProvider.GetRequiredService<UserManager<AdminUser>>();

        // Fix sequence issues FIRST to prevent primary key conflicts
        logger.LogInformation("Synchronizing database sequences...");
        using var adminContext = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();

        await adminContext.Database.ExecuteSqlRawAsync(@"
            DO $$
            DECLARE
                max_id INTEGER;
            BEGIN
                -- Fix Roles sequence
                SELECT COALESCE(MAX(""Id""), 0) INTO max_id FROM ""AspNetRoles"";
                IF max_id > 0 THEN
                    PERFORM setval('""AspNetRoles_Id_seq""', max_id + 1);
                END IF;
                
                -- Fix Users sequence  
                SELECT COALESCE(MAX(""Id""), 0) INTO max_id FROM ""AspNetUsers"";
                IF max_id > 0 THEN
                    PERFORM setval('""AspNetUsers_Id_seq""', max_id + 1);
                END IF;
            EXCEPTION
                WHEN others THEN
                    NULL; -- Ignore errors
            END $$;
        ");

        logger.LogInformation("Database sequences synchronized successfully");

        // Define required admin roles (including Moderator for in-game monitoring)
        string[] adminRoles = { "SuperAdmin", "Admin", "GameMaster", "PlayerManager", "SystemAdmin", "Moderator" };

        // SAFELY create roles only if they don't exist
        foreach (string roleName in adminRoles)
        {
            try
            {
                if (!await roleManager.RoleExistsAsync(roleName))
                {
                    var result = await roleManager.CreateAsync(new IdentityRole<int>(roleName));
                    if (result.Succeeded)
                    {
                        logger.LogInformation($"Created admin role: {roleName}");
                    }
                    else
                    {
                        logger.LogWarning($"Failed to create role {roleName}: {string.Join(", ", result.Errors.Select(e => e.Description))}");
                    }
                }
                else
                {
                    logger.LogDebug($"Role {roleName} already exists - skipping");
                }
            }
            catch (Exception ex)
            {
                logger.LogError(ex, $"Error creating role {roleName} - continuing with next role");
            }
        }

        // Create default super admin if configured
        var defaultAdminEmail = builder.Configuration["DefaultAdmin:Email"];
        var defaultAdminPassword = builder.Configuration["DefaultAdmin:Password"];

        if (!string.IsNullOrEmpty(defaultAdminEmail) && !string.IsNullOrEmpty(defaultAdminPassword))
        {
            try
            {
                var adminUser = await userManager.FindByEmailAsync(defaultAdminEmail);
                if (adminUser == null)
                {
                    adminUser = new AdminUser
                    {
                        UserName = defaultAdminEmail,
                        Email = defaultAdminEmail,
                        EmailConfirmed = true
                    };

                    var createResult = await userManager.CreateAsync(adminUser, defaultAdminPassword);
                    if (createResult.Succeeded)
                    {
                        await userManager.AddToRoleAsync(adminUser, "SuperAdmin");
                        logger.LogInformation($"Created default SuperAdmin user: {defaultAdminEmail}");
                    }
                    else
                    {
                        logger.LogError($"Failed to create default admin: {string.Join(", ", createResult.Errors.Select(e => e.Description))}");
                    }
                }
                else
                {
                    logger.LogDebug("Default admin user already exists - skipping creation");
                }
            }
            catch (Exception ex)
            {
                logger.LogError(ex, "Error creating default admin user");
            }
        }
    }
    catch (Exception ex)
    {
        logger.LogError(ex, "Error during role/user initialization - application will continue but admin features may be limited");
    }
}

// ===============================
// STARTUP COMPLETE
// ===============================
var startupLogger = app.Services.GetRequiredService<ILogger<Program>>();
startupLogger.LogInformation("=================================================");
startupLogger.LogInformation("SHADOWED REALMS ADMIN DASHBOARD READY");
startupLogger.LogInformation($"Environment: {environment}");
startupLogger.LogInformation($"Admin Database: {adminDbName}");
startupLogger.LogInformation($"Game Database: {gameDbName}");
startupLogger.LogInformation("Admin dashboard configured for kingdom management");
startupLogger.LogInformation("Kingdom Management now using real database integration");
startupLogger.LogInformation("Field Interception Combat System monitoring enabled");
startupLogger.LogInformation("=================================================");

app.Run();