using System.Security.Claims;
using iyixiGames.Infrastructure.Data;
using iyixiGames.Infrastructure.Services;
using Microsoft.EntityFrameworkCore;
// 引入 DateTime.UtcNow
// 引入 ClaimsPrincipal 和 Claim
// 引入 Task
// 引入 List<T>
// 引入 Entity Framework Core，用于数据库操作（Include, SingleOrDefaultAsync 等）
// 引入 ApplicationDbContext
// 引入你的领域实体（如 User, Role, Permission 等）

// 引入 IUserService 接口

namespace iyixiGames.Application.Services
{
    /// <summary>
    /// 认证服务实现类，负责处理用户认证的核心逻辑，包括用户凭据验证、ClaimsPrincipal 构建和最后登录时间更新。
    /// </summary>
    public class AuthService : IAuthService
    {
        private readonly ApplicationDbContext _dbContext; // 数据库上下文实例
        private readonly IUserService _userService;       // 用户服务接口，用于执行密码验证等用户相关操作

        /// <summary>
        /// AuthService 类的构造函数。
        /// 通过依赖注入获取 ApplicationDbContext 和 IUserService 实例。
        /// </summary>
        /// <param name="dbContext">应用程序的数据库上下文。</param>
        /// <param name="userService">用户服务接口，用于密码验证等。</param>
        public AuthService(ApplicationDbContext dbContext, IUserService userService)
        {
            _dbContext = dbContext;
            _userService = userService; // 注入 IUserService
        }

        /// <summary>
        /// 异步验证用户凭据并构建 ClaimsPrincipal。
        /// </summary>
        /// <param name="username">用户输入的用户名。</param>
        /// <param name="password">用户输入的明文密码。</param>
        /// <returns>
        /// 如果认证成功，返回包含用户声明的 <see cref="ClaimsPrincipal"/> 对象；
        /// 否则返回 null。
        /// </returns>
        public async Task<ClaimsPrincipal?> AuthenticateUserAsync(string username, string password)
        {
            // 1. 根据用户名从数据库获取用户及其相关的角色和权限信息。
            // 使用 Include 和 ThenInclude 预加载关联数据，避免 N+1 查询问题。
            var user = await _dbContext.Users
                .Include(u => u.UserRoles) // 包含用户关联的角色 (UserRole 中间表)
                    .ThenInclude(ur => ur.Role) // 进一步包含角色实体本身
                        .ThenInclude(r => r.RolePermissions) // 再进一步包含角色关联的权限 (RolePermission 中间表)
                            .ThenInclude(rp => rp.Permission) // 最后包含权限实体本身
                .SingleOrDefaultAsync(u => u.Username == username && u.IsActive); // 查找指定用户名且为激活状态的用户

            // 如果用户不存在或未激活，认证失败。
            if (user == null)
            {
                return null;
            }

            // 2. 验证密码。
            // 调用 IUserService 中实现的 VerifyPasswordAsync 方法来验证密码。
            // 这里的实现将与你在 UserService 中定义的 HMACSHA512 逻辑匹配。
            var isPasswordValid = await _userService.VerifyPasswordAsync(user, password);

            // 如果密码不匹配，认证失败。
            if (!isPasswordValid)
            {
                return null;
            }

            // 3. 构建用户声明 (Claims)。
            // ClaimsPrincipal 是表示当前用户的身份和所拥有声明（如姓名、角色、权限）的对象。
            var claims = new List<Claim>
            {
                new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()), // 用户的唯一标识符
                new Claim(ClaimTypes.Name, user.Username),               // 用户名
                new Claim(ClaimTypes.Email, user.Email),                 // 用户电子邮件
                new Claim("FullName", user.FullName)                     // 自定义声明：用户全名
            };

            // 4. 添加用户的角色声明。
            // 遍历用户所属的所有角色，并将每个角色名添加为 ClaimTypes.Role 声明。
            foreach (var userRole in user.UserRoles)
            {
                claims.Add(new Claim(ClaimTypes.Role, userRole.Role.Name));

                // 5. 添加用户的权限声明（可选）。
                // 如果需要将用户的具体权限也作为声明添加到身份中，可以在此遍历角色关联的权限。
                // 这样在后续的授权策略中可以直接检查这些权限声明。
                foreach (var rolePermission in userRole.Role.RolePermissions)
                {
                    claims.Add(new Claim("Permission", rolePermission.Permission.Name)); // 自定义声明：权限名称
                }
            }

            // 6. 创建 ClaimsIdentity 和 ClaimsPrincipal。
            // ClaimsIdentity 表示一个用户身份，它包含了一组声明和一个认证类型（如 "ApplicationCookie"）。
            var identity = new ClaimsIdentity(claims, "ApplicationCookie"); // "ApplicationCookie" 是认证方案的标识符
            // ClaimsPrincipal 是一个主体，它可以包含一个或多个 ClaimsIdentity，通常只包含一个。
            var principal = new ClaimsPrincipal(identity);

            return principal; // 返回构建好的 ClaimsPrincipal，表示认证成功
        }

        /// <summary>
        /// 异步更新用户的最后登录时间。
        /// </summary>
        /// <param name="userId">要更新的用户的 ID。</param>
        /// <returns>一个 <see cref="Task"/>，表示异步操作的完成。</returns>
        public async Task UpdateLastLoginTimeAsync(int userId)
        {
            // 通过用户 ID 查找用户实体。
            var user = await _dbContext.Users.FindAsync(userId);
            if (user != null)
            {
                // 更新用户的 LastLoginAt 属性为当前的 UTC 时间。
                user.LastLoginAt = DateTime.UtcNow;
                // 将更改保存到数据库。
                await _dbContext.SaveChangesAsync();
            }
        }
    }
}