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

namespace ColaFlow.IntegrationTests.SignalR;

/// <summary>
/// Helper class for generating JWT tokens for SignalR integration tests
/// </summary>
public static class TestJwtHelper
{
    private const string SecretKey = "ColaFlow_Test_Secret_Key_For_SignalR_Integration_Tests_12345";
    private const string Issuer = "ColaFlow.Test";
    private const string Audience = "ColaFlow.Test.Client";

    public static string GenerateToken(Guid userId, Guid tenantId, int expirationMinutes = 60)
    {
        var claims = new[]
        {
            new Claim("sub", userId.ToString()),
            new Claim("user_id", userId.ToString()),
            new Claim("tenant_id", tenantId.ToString()),
            new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())
        };

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

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

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

    public static string GenerateExpiredToken(Guid userId, Guid tenantId)
    {
        var claims = new[]
        {
            new Claim("sub", userId.ToString()),
            new Claim("user_id", userId.ToString()),
            new Claim("tenant_id", tenantId.ToString()),
            new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())
        };

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

        var token = new JwtSecurityToken(
            issuer: Issuer,
            audience: Audience,
            claims: claims,
            expires: DateTime.UtcNow.AddMinutes(-10), // Expired 10 minutes ago
            signingCredentials: creds);

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

    public static string GenerateTokenWithoutTenantId(Guid userId)
    {
        var claims = new[]
        {
            new Claim("sub", userId.ToString()),
            new Claim("user_id", userId.ToString()),
            new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())
        };

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

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

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

    public static string GenerateTokenWithoutUserId(Guid tenantId)
    {
        var claims = new[]
        {
            new Claim("tenant_id", tenantId.ToString()),
            new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())
        };

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

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

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

    public static string GenerateTamperedToken(Guid userId, Guid tenantId)
    {
        var validToken = GenerateToken(userId, tenantId);

        // Tamper with the token by modifying the middle part
        var parts = validToken.Split('.');
        if (parts.Length == 3)
        {
            // Change a character in the payload
            var tamperedPayload = parts[1].Length > 10
                ? parts[1].Substring(0, parts[1].Length - 5) + "XXXXX"
                : parts[1] + "XXXXX";
            return $"{parts[0]}.{tamperedPayload}.{parts[2]}";
        }

        return validToken + "TAMPERED";
    }

    public static SecurityKey GetSecurityKey()
    {
        return new SymmetricSecurityKey(Encoding.UTF8.GetBytes(SecretKey));
    }

    public static string GetIssuer() => Issuer;
    public static string GetAudience() => Audience;
}
