using Entities.Configuration;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Security.Cryptography;
using System.Text;
using Entities.DTO;

namespace TechHelper.Services.Beta
{
	/// <summary>
	/// 用户认证服务，实现 JWT 令牌生成、刷新令牌生成、过期令牌解析等功能。
	/// </summary>
	public class AuthenticationService : IAuthenticationService
	{
		private readonly JwtConfiguration _jwtSettings;
		private readonly JwtSecurityTokenHandler _jwtHandler;
		private readonly UserManager<Entities.Contracts.User> _userManager;
		private readonly IClassService _classService;

		/// <summary>
		/// 构造函数，注入 JWT 配置、用户管理器和班级服务。
		/// </summary>
		public AuthenticationService(IOptions<JwtConfiguration> jwtSettings, UserManager<Entities.Contracts.User> userManager, IClassService classService)
		{
			_jwtSettings = jwtSettings.Value;
			_jwtHandler = new JwtSecurityTokenHandler();
			_userManager = userManager;
			_classService = classService;
		}

		/// <summary>
		/// 生成指定用户的 JWT 访问令牌。
		/// </summary>
		/// <param name="user">用户实体</param>
		/// <returns>JWT 字符串</returns>
		public async Task<string> GetToken(Entities.Contracts.User user)
		{
			var signingCredentials = GetSigningCredentials();
			var claims = await GetClaims(user);
			var tokenOptions = GenerateTokenOptions(signingCredentials, claims);
			return _jwtHandler.WriteToken(tokenOptions);
		}

		/// <summary>
		/// 获取 JWT 签名凭证。
		/// </summary>
		/// <returns>签名凭证</returns>
		private SigningCredentials GetSigningCredentials()
		{
			var key = Encoding.UTF8.GetBytes(_jwtSettings.SecurityKey);
			var secret = new SymmetricSecurityKey(key);
			return new SigningCredentials(secret, SecurityAlgorithms.HmacSha256);
		}

		/// <summary>
		/// 获取用户的声明信息，包括角色和班级信息。
		/// </summary>
		/// <param name="user">用户实体</param>
		/// <returns>声明集合</returns>
		private async Task<IEnumerable<Claim>> GetClaims(Entities.Contracts.User user)
		{
			var claims = new List<Claim>
			{
				new Claim(ClaimTypes.Name, user.Email)
			};

			// 添加用户角色声明
			var roles = await _userManager.GetRolesAsync(user);
			foreach (var role in roles)
			{
				claims.Add(new Claim(ClaimTypes.Role, role));
			}

			#region ClassInfo
			// 添加用户班级信息声明
			var classInfo = await _classService.GetUserInjoinedClasses(user.Id);
			if (classInfo.Status)
			{
				var classs = classInfo.Result as UserClassDetailInfoDto;
				if (classs == null) return claims;
				foreach (var c in classs.UserClassInfos)
				{
					claims.Add(new Claim("Grade", c.Grade.ToString()));
					claims.Add(new Claim("Class", c.Class.ToString()));
				}
			}
			#endregion
			return claims;
		}

		/// <summary>
		/// 生成 JWT 令牌对象。
		/// </summary>
		/// <param name="signingCredentials">签名凭证</param>
		/// <param name="claims">声明集合</param>
		/// <returns>JWT 令牌对象</returns>
		private JwtSecurityToken GenerateTokenOptions(SigningCredentials signingCredentials, IEnumerable<Claim> claims)
		{
			var tokenOptions = new JwtSecurityToken(
				issuer: _jwtSettings.ValidIssuer,
				audience: _jwtSettings.ValidAudience,
				claims: claims,
				expires: DateTime.UtcNow.AddMinutes(Convert.ToDouble(
					_jwtSettings.ExpiryInMinutes)),
				signingCredentials: signingCredentials);

			return tokenOptions;
		}

		/// <summary>
		/// 生成安全的刷新令牌（Base64 字符串）。
		/// </summary>
		/// <returns>刷新令牌</returns>
		public string GenerateRefreshToken()
		{
			var randomNumber = new byte[32];
			using (var rng = RandomNumberGenerator.Create())
			{
				rng.GetBytes(randomNumber);
				return Convert.ToBase64String(randomNumber);
			}
		}

		/// <summary>
		/// 从过期的 JWT 令牌中获取声明主体（不验证过期时间）。
		/// </summary>
		/// <param name="token">过期的 JWT 令牌</param>
		/// <returns>声明主体</returns>
		/// <exception cref="SecurityTokenException">令牌无效时抛出</exception>
		public ClaimsPrincipal GetPrincipalFromExpiredToken(string token)
		{
			var tokenValidationParameters = new TokenValidationParameters
			{
				ValidateAudience = true,
				ValidateIssuer = true,
				ValidateIssuerSigningKey = true,
				IssuerSigningKey = new SymmetricSecurityKey(
					Encoding.UTF8.GetBytes(_jwtSettings.SecurityKey)),
				ValidateLifetime = false, // 不验证过期时间
				ValidIssuer = _jwtSettings.ValidIssuer,
				ValidAudience = _jwtSettings.ValidAudience,
			};

			var tokenHandler = new JwtSecurityTokenHandler();
			SecurityToken securityToken;

			var principal = tokenHandler.ValidateToken(token,
				tokenValidationParameters, out securityToken);

			var jwtSecurityToken = securityToken as JwtSecurityToken;
			if (jwtSecurityToken == null ||
				!jwtSecurityToken.Header.Alg.Equals(SecurityAlgorithms.HmacSha256,
				StringComparison.InvariantCultureIgnoreCase))
			{
				throw new SecurityTokenException("Invalid token");
			}

			return principal;
		}
	}
}
