using Microsoft.EntityFrameworkCore; // 引入 Entity Framework Core，用于数据库操作
using iyixiGames.Infrastructure.Data; // 引入应用程序的数据库上下文
using iyixiGames.Application.Services; // 引入应用层服务接口
using iyixiGames.Infrastructure.Services; // 引入基础设施层服务实现
using Serilog; // 引入 Serilog 日志框架
using Microsoft.AspNetCore.Authentication.JwtBearer; // 引入 JWT Bearer 认证
using Microsoft.IdentityModel.Tokens; // 引入安全令牌（如 SymmetricSecurityKey）
using System.Text; // 引入文本编码（如 Encoding.ASCII）
using Microsoft.AspNetCore.Authentication.Cookies; // 引入 Cookie 认证，用于 MVC 登录
using System; // 引入 DateTime 等基础类型
using Microsoft.Extensions.DependencyInjection; // 引入扩展方法，例如 GetRequiredService
using Microsoft.Extensions.Hosting; // 引入 Host 构建器
using iyixiGames.AI.Configurations; // 引入 DeepSeek 配置
using iyixiGames.AI.Services; // 引入 DeepSeek 服务

var builder = WebApplication.CreateBuilder(args); // 创建一个新的 Web 应用程序构建器实例

// --- Serilog 日志配置 ---
// 配置 Serilog 作为应用程序的日志框架。
// 日志将从配置文件 (appsettings.json) 读取配置，并集成到服务中。
// 日志会丰富上下文信息，输出到控制台，并按天滚动写入到 'logs' 文件夹下的文件中。
builder.Host.UseSerilog((context, services, configuration) => configuration
    .ReadFrom.Configuration(context.Configuration) // 从 appsettings.json 读取 Serilog 配置
    .ReadFrom.Services(services) // 允许 Serilog 从 DI 容器中获取服务（例如，用于上下文丰富器）
    .Enrich.FromLogContext() // 丰富日志上下文信息（如 HttpContext 信息）
    .WriteTo.Console() // 将日志输出到控制台
    .WriteTo.File("logs/log-.txt", // 将日志写入文件
                  rollingInterval: RollingInterval.Day, // 日志文件按天滚动（每天生成一个新文件）
                  retainedFileCountLimit: 7)); // 最多保留7天的日志文件

// --- 服务添加到容器 (Dependency Injection) ---
// 所有的服务都在这里注册，以便在应用程序的其他部分通过依赖注入使用。

// 添加对 MVC 控制器和视图的支持。
// 这使得应用程序可以处理基于视图的 HTTP 请求，并渲染 Razor 视图。
builder.Services.AddControllersWithViews();

// 添加对 API 控制器的支持。
// 这使得应用程序可以处理基于属性路由的 HTTP 请求，通常用于 RESTful API。
builder.Services.AddControllers();

// 配置 Swagger/OpenAPI 用于 API 文档生成。
// Swagger 是一个工具集，可以帮助设计、构建、文档化和使用 RESTful Web 服务。
builder.Services.AddEndpointsApiExplorer(); // 发现 API 接口
builder.Services.AddSwaggerGen(); // 注册 Swagger 文档生成器

// 获取数据库连接字符串。
// 连接字符串通常存储在 appsettings.json 中。
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");

// 添加 ApplicationDbContext 到服务容器。
// 配置使用 MySQL 数据库，并指定迁移所在的程序集。
builder.Services.AddDbContext<ApplicationDbContext>(options =>
{
    options.UseMySql(connectionString, // 使用 MySql 数据库
        ServerVersion.AutoDetect(connectionString), // 自动检测 MySql 服务器版本
        mySqlOptions => mySqlOptions.MigrationsAssembly(typeof(ApplicationDbContext).Assembly.FullName)); // 指定包含迁移的程序集
});

// --- 注册应用层服务和仓储 ---
// 注册自定义的应用服务和数据仓储，遵循依赖倒置原则。

// 注册用户服务：将 IUserService 接口映射到 UserService 实现类。
builder.Services.AddScoped<IUserService, UserService>();
// 注册认证服务：将 IAuthService 接口映射到 AuthService 实现类。
// 注意：AuthService 依赖于 IUserService，因此 IUserService 必须在此之前注册。
builder.Services.AddScoped<IAuthService, AuthService>();

// **注册网站管理相关服务和仓储**
// 注册网站数据仓储：将 ISiteRepository 接口映射到 SiteRepository 实现类。
builder.Services.AddScoped<ISiteRepository, SiteRepository>();
builder.Services.AddScoped<ISiteService, SiteService>();

// **新增：注册游戏管理相关服务和仓储**
builder.Services.AddScoped<IGameRepository, GameRepository>();
builder.Services.AddScoped<IGameService, GameService>();

// **新增：注册 DeepSeek AI 服务**
builder.Services.Configure<DeepSeekConfig>(builder.Configuration.GetSection(DeepSeekConfig.Position));
builder.Services.AddHttpClient<IDeepSeekService, DeepSeekService>(); // 注册 HttpClient 和服务
// --------------------------------------------------

// --- 认证配置 ---
// 配置应用程序的认证方案，包括 Cookie 认证和 JWT Bearer 认证。

// 添加认证服务。
// 配置默认认证方案为 Cookie 认证，这对于基于浏览器的 MVC 应用程序是常见的选择。
builder.Services.AddAuthentication(options =>
{
    // 默认认证方案：用于验证用户身份的方案（例如，从 Cookie 或 JWT 读取凭据）
    options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    // 默认登录方案：用于登录用户（如创建 Cookie）
    options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    // 默认挑战方案：当用户未认证或权限不足时，用于引导用户进行认证的方案（如重定向到登录页）
    options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
})
.AddCookie(options => // 添加 Cookie 认证方案。默认方案名为 "Cookies"。
{
    options.LoginPath = "/Account/Login";     // 当用户未认证时，重定向到此路径进行登录
    options.LogoutPath = "/Account/Logout";   // 用户注销时请求的路径
    options.AccessDeniedPath = "/Account/AccessDenied"; // 用户无权访问某资源时，重定向到此路径
    options.SlidingExpiration = true;         // 启用滑动过期：如果用户在有效期内发出请求，Cookie 的过期时间会被延长
    options.ExpireTimeSpan = TimeSpan.FromDays(7); // Cookie 的有效期限为 7 天
    // 可以添加更多 Cookie 属性，如 Domain, SecurePolicy 等。
})
.AddJwtBearer(options => // 添加 JWT Bearer 认证方案，通常用于无状态 API 认证。
{
    // 从配置中获取 JWT 设置（如 appsettings.json 中的 "Jwt" 部分）。
    var jwtSettings = builder.Configuration.GetSection("Jwt");
    // 获取 JWT 密钥，用于签名和验证令牌。
    var key = Encoding.ASCII.GetBytes(jwtSettings["Key"] ?? throw new InvalidOperationException("JWT Key not configured."));

    options.RequireHttpsMetadata = false; // 在开发环境可以设为 false，生产环境应始终设为 true 以确保安全
    options.SaveToken = true; // 在 HttpContext 中保存接收到的令牌
    options.TokenValidationParameters = new TokenValidationParameters // 配置令牌验证参数
    {
        ValidateIssuerSigningKey = true, // 验证发行者签名密钥
        IssuerSigningKey = new SymmetricSecurityKey(key), // 设置签名密钥
        ValidateIssuer = true, // 验证发行者
        ValidIssuer = jwtSettings["Issuer"], // 有效的发行者
        ValidateAudience = true, // 验证受众
        ValidAudience = jwtSettings["Audience"], // 有效的受众
        ValidateLifetime = true, // 验证令牌的生命周期（过期时间）
        ClockSkew = TimeSpan.Zero // 允许的时间偏移，设置为零表示严格验证时间
    };
});

// 添加授权服务。
// 授权在认证之后进行，用于检查用户是否有权访问特定资源或执行特定操作。
builder.Services.AddAuthorization();

var app = builder.Build(); // 构建 WebApplication 实例

// --- HTTP 请求管道配置 ---
// 定义 HTTP 请求的处理顺序，中间件按其添加的顺序执行。

// 启用 Serilog 请求日志记录中间件，记录传入的 HTTP 请求。
app.UseSerilogRequestLogging();

// 根据环境配置中间件。
if (app.Environment.IsDevelopment()) // 如果是开发环境
{
    app.UseSwagger(); // 启用 Swagger UI 文档生成
    app.UseSwaggerUI(); // 启用 Swagger UI 界面
    // 仅在开发环境中自动应用数据库迁移。
    // 在生产环境中，应通过命令行或专门的部署脚本来运行迁移。
    using (var scope = app.Services.CreateScope())
    {
        var dbContext = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
        // 确保数据库存在并应用所有挂起的迁移。
        dbContext.Database.Migrate();
    }
}

app.UseHttpsRedirection(); // 强制将 HTTP 请求重定向到 HTTPS

app.UseStaticFiles(); // 启用静态文件服务（如 CSS、JavaScript、图片等）

app.UseRouting(); // 启用路由中间件，根据请求 URL 匹配路由

// **重要：认证 (UseAuthentication) 和授权 (UseAuthorization) 中间件的顺序至关重要！**
// 认证必须在授权之前执行，因为授权依赖于认证结果（即用户的身份）。
app.UseAuthentication(); // 启用认证中间件，负责识别用户身份（通过 Cookie 或 JWT 等）
app.UseAuthorization();  // 启用授权中间件，根据用户身份和策略检查访问权限

// 配置 MVC 路由。
// 定义默认的路由模式，通常用于传统的 MVC 应用程序。
app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

// 映射控制器。
// 这将映射所有带有 [ApiController] 和 [Route] 特性的控制器，通常用于 Web API。
app.MapControllers();

app.Run(); // 运行应用程序，开始监听 HTTP 请求