using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using Microsoft.IdentityModel.JsonWebTokens;
using Microsoft.IdentityModel.Tokens;
using Modules.User.Application.Settings;
using Modules.User.Domain.Gateways;
using System.Security.Cryptography;
using System.Text;

namespace Modules.User.Application;

public class TokenGenerator : IRefreshTokenGateway
{
    public const string RefreshTokenName = "rTok";
    private readonly ushort _length = 128;

    public string GenerateRefreshToken()
    {
        var randomBytes = new byte[_length];
        using var rng = RandomNumberGenerator.Create();
        rng.GetBytes(randomBytes);
        return Convert.ToBase64String(randomBytes);
    }

    public static void SetRefreshTokenInCookie(HttpResponse response, string? cookiePath, string refreshToken, DateTime expiredDate)
    {
        var cookieOptions = new CookieOptions
        {
            HttpOnly = true,
            //Expires = DateTime.UtcNow.AddDays(10),
            //Expires = expiredDate,
            MaxAge = expiredDate - DateTime.UtcNow,
            //SameSite = SameSiteMode.Strict,
            //SameSite = SameSiteMode.Unspecified,
            //Secure = true,
            Secure = false,
        };
        if (!string.IsNullOrWhiteSpace(cookiePath?.TrimStart('/')))
        {
            //cookieOptions.Path = string.Join(';', cookiePaths.Select(q => string.Concat("/", q.TrimStart('/'))));
            cookieOptions.Path = string.Concat("/", cookiePath.TrimStart('/'));
        }

        response.Cookies.Append(RefreshTokenName, refreshToken, cookieOptions);
        //response.Cookies.Append("refreshToken", refreshToken, cookieOptions);
    }

    internal string GenerateAccessToken(Domain.Entities.User.User user, Domain.Entities.Account.Session session, JwtSettings jwtSettings)
    {
        if (jwtSettings.AccessTokenExpireTime < TimeSpan.FromSeconds(10)) throw new Exception("AccessTokenExpireTime must be greater than 10 seconds");

        var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSettings.SecurityKey));
        var signingCredentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);


        var claims = new Dictionary<string, object>
        {
            { Constants.AccountIdKey, user.Account.Id.ToString() ?? "" },
            { Constants.SessionIdKey, session.Id.ToString() ?? "" },
        };

        var descriptor = new SecurityTokenDescriptor
        {
            Issuer = jwtSettings.Issuer,
            Audience = jwtSettings.Audience,
            Claims = claims,
            //IssuedAt = DateTime.UtcNow,
            IssuedAt = null,
            Expires = DateTime.UtcNow.Add(jwtSettings.AccessTokenExpireTime),
            SigningCredentials = signingCredentials
        };

        var handler = new JsonWebTokenHandler();
        handler.SetDefaultTimesOnTokenCreation = false;
        var token = handler.CreateToken(descriptor);

        return token;
    }
}