using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Security.Cryptography;
using System.Text;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using SolutionErp.Application.Common.Interfaces;
using SolutionErp.Domain.Identity;

namespace SolutionErp.Infrastructure.Identity;

public class JwtTokenService : IJwtTokenService
{
    private readonly JwtSettings _settings;
    private readonly IDateTime _dateTime;

    public JwtTokenService(IOptions<JwtSettings> options, IDateTime dateTime)
    {
        _settings = options.Value;
        _dateTime = dateTime;
    }

    public Task<(string AccessToken, string RefreshToken, DateTime RefreshTokenExpiresAt)> GenerateTokensAsync(User user, IList<string> roles)
    {
        var claims = new List<Claim>
        {
            new(JwtRegisteredClaimNames.Sub, user.Id.ToString()),
            new(JwtRegisteredClaimNames.Email, user.Email ?? string.Empty),
            new(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
            new("fullName", user.FullName),
        };
        claims.AddRange(roles.Select(r => new Claim(ClaimTypes.Role, r)));

        var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_settings.Secret));
        var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

        var token = new JwtSecurityToken(
            issuer: _settings.Issuer,
            audience: _settings.Audience,
            claims: claims,
            expires: _dateTime.UtcNow.AddMinutes(_settings.AccessTokenExpiryMinutes),
            signingCredentials: creds);

        var accessToken = new JwtSecurityTokenHandler().WriteToken(token);
        var refreshToken = GenerateRefreshToken();
        var refreshExpires = _dateTime.UtcNow.AddDays(_settings.RefreshTokenExpiryDays);

        return Task.FromResult((accessToken, refreshToken, refreshExpires));
    }

    public Task<Guid?> ValidateRefreshTokenAsync(string userId, string refreshToken)
    {
        return Task.FromResult<Guid?>(null);
    }

    private static string GenerateRefreshToken()
    {
        var bytes = new byte[64];
        using var rng = RandomNumberGenerator.Create();
        rng.GetBytes(bytes);
        return Convert.ToBase64String(bytes);
    }
}
