using System.Net.Http.Headers;
using System.Security.Claims;
using System.Text;
using SatelliteProvider.TestSupport;

namespace SatelliteProvider.IntegrationTests;

public static class JwtTestHelpers
{
    public const string JwtSecretEnvVar = "JWT_SECRET";
    public const string JwtIssuerEnvVar = "JWT_ISSUER";
    public const string JwtAudienceEnvVar = "JWT_AUDIENCE";
    public const string DefaultSubject = "integration-tests";

    public static string ResolveSecretOrThrow()
    {
        var secret = Environment.GetEnvironmentVariable(JwtSecretEnvVar);
        if (string.IsNullOrWhiteSpace(secret))
        {
            throw new InvalidOperationException(
                $"{JwtSecretEnvVar} is not set in the integration test environment. " +
                "It must match the JWT_SECRET configured for the API container.");
        }

        var byteLength = Encoding.UTF8.GetByteCount(secret);
        if (byteLength < 32)
        {
            throw new InvalidOperationException(
                $"{JwtSecretEnvVar} is {byteLength} bytes; the test runner requires at least 32 bytes to match API validation.");
        }

        return secret;
    }

    // AZ-494: runner-side resolvers for the iss / aud values the API enforces.
    // Both MUST be present and match the API container's values, or the API
    // will reject every minted token at validation time.
    public static string ResolveIssuerOrThrow()
    {
        var issuer = Environment.GetEnvironmentVariable(JwtIssuerEnvVar);
        if (string.IsNullOrWhiteSpace(issuer))
        {
            throw new InvalidOperationException(
                $"{JwtIssuerEnvVar} is not set in the integration test environment. " +
                "It must match the JWT_ISSUER configured for the API container (AZ-494).");
        }
        return issuer;
    }

    public static string ResolveAudienceOrThrow()
    {
        var audience = Environment.GetEnvironmentVariable(JwtAudienceEnvVar);
        if (string.IsNullOrWhiteSpace(audience))
        {
            throw new InvalidOperationException(
                $"{JwtAudienceEnvVar} is not set in the integration test environment. " +
                "It must match the JWT_AUDIENCE configured for the API container (AZ-494).");
        }
        return audience;
    }

    public static void AttachDefaultAuthorization(HttpClient httpClient, string token)
    {
        httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
    }

    // AZ-494: convenience wrapper. Reads JWT_ISSUER / JWT_AUDIENCE from env
    // (cached for the runner's lifetime via resolve calls) and delegates to
    // the canonical JwtTokenFactory.Create. Test scenarios that need WRONG
    // iss/aud (e.g. negative AC tests) pass overrides explicitly.
    public static string MintAuthenticated(
        string secret,
        string? subject = null,
        IEnumerable<Claim>? extraClaims = null,
        TimeSpan? lifetime = null,
        string? overrideIssuer = null,
        string? overrideAudience = null)
    {
        return JwtTokenFactory.Create(
            secret,
            subject ?? DefaultSubject,
            lifetime,
            extraClaims,
            issuer: overrideIssuer ?? ResolveIssuerOrThrow(),
            audience: overrideAudience ?? ResolveAudienceOrThrow());
    }

    public static string MintExpired(string secret, string? subject = null)
    {
        return JwtTokenFactory.CreateExpired(
            secret,
            subject ?? DefaultSubject,
            issuer: ResolveIssuerOrThrow(),
            audience: ResolveAudienceOrThrow());
    }
}
