using System;
using System.Text.Json;

namespace ClaudeDo.Ui.Services;

/// <summary>
/// Minimal, dependency-free inspection of a Zitadel JWT access token. Used to warn early when
/// a freshly issued token lacks the "user" project role (the server otherwise rejects sync
/// with a 401). The server remains the source of truth — this check fails open.
/// </summary>
public static class ZitadelTokenInspector
{
    private const string ProjectRolesClaim = "urn:zitadel:iam:org:project:roles";
    private const string ProjectRolesClaimPrefix = "urn:zitadel:iam:org:project:";
    private const string ProjectRolesClaimSuffix = ":roles";
    private const string UserRole = "user";

    /// <summary>
    /// Returns true if the access token carries the "user" role in either the generic or
    /// project-scoped Zitadel roles claim. Returns true (fail-open) if the token is absent or
    /// cannot be parsed — never block login on a decode hiccup.
    /// </summary>
    public static bool HasUserRole(string? accessToken)
    {
        if (string.IsNullOrWhiteSpace(accessToken))
            return true;

        var parts = accessToken.Split('.');
        if (parts.Length < 2)
            return true;

        try
        {
            using var doc = JsonDocument.Parse(Base64UrlDecode(parts[1]));
            foreach (var claim in doc.RootElement.EnumerateObject())
            {
                if (claim.Name != ProjectRolesClaim &&
                    !(claim.Name.StartsWith(ProjectRolesClaimPrefix, StringComparison.Ordinal) &&
                      claim.Name.EndsWith(ProjectRolesClaimSuffix, StringComparison.Ordinal)))
                    continue;

                if (claim.Value.ValueKind == JsonValueKind.Object &&
                    claim.Value.TryGetProperty(UserRole, out _))
                    return true;
            }
            return false;
        }
        catch
        {
            return true;
        }
    }

    private static byte[] Base64UrlDecode(string input)
    {
        var s = input.Replace('-', '+').Replace('_', '/');
        switch (s.Length % 4)
        {
            case 2: s += "=="; break;
            case 3: s += "="; break;
        }
        return Convert.FromBase64String(s);
    }
}
