using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;

namespace SpaceGame.Api.Auth.Simulation;

public sealed class JwtTokenService(
    IOptions<JwtOptions> jwtOptions,
    RefreshTokenFactory refreshTokenFactory) : ITokenService
{
    public (string Token, DateTimeOffset ExpiresAtUtc) CreateAccessToken(UserAccount user)
    {
        var options = jwtOptions.Value;
        var expiresAtUtc = DateTimeOffset.UtcNow.AddMinutes(Math.Max(options.AccessTokenLifetimeMinutes, 5));
        var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(options.SigningKey));
        var credentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
        var claims = new[]
        {
            new Claim(JwtRegisteredClaimNames.Sub, user.Id.ToString()),
            new Claim(JwtRegisteredClaimNames.Email, user.Email),
            new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
            new Claim(ClaimTypes.Email, user.Email),
        }.ToList();

        foreach (var role in user.Roles)
        {
            claims.Add(new Claim(ClaimTypes.Role, role));
            claims.Add(new Claim("role", role));
        }

        var token = new JwtSecurityToken(
          issuer: options.Issuer,
          audience: options.Audience,
          claims: claims,
          notBefore: DateTime.UtcNow,
          expires: expiresAtUtc.UtcDateTime,
          signingCredentials: credentials);

        return (new JwtSecurityTokenHandler().WriteToken(token), expiresAtUtc);
    }

    public (string Token, string TokenHash, DateTimeOffset ExpiresAtUtc) CreateRefreshToken()
    {
        var token = refreshTokenFactory.CreateToken();
        var tokenHash = refreshTokenFactory.HashToken(token);
        var expiresAtUtc = DateTimeOffset.UtcNow.AddDays(Math.Max(jwtOptions.Value.RefreshTokenLifetimeDays, 1));
        return (token, tokenHash, expiresAtUtc);
    }
}
