// ==============================================================================
// MORPH-SPEC - Clerk Authentication Configuration Template
// Configuração de autenticação com Clerk para .NET
// ==============================================================================

using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Components.Authorization;
using System.Security.Claims;

namespace {{Namespace}}.Infrastructure.Auth;

// ==============================================================================
// OPTIONS
// ==============================================================================

public class ClerkOptions
{
    public const string SectionName = "Clerk";

    /// <summary>
    /// Clerk Secret Key (starts with sk_)
    /// </summary>
    public string SecretKey { get; set; } = string.Empty;

    /// <summary>
    /// Clerk Publishable Key (starts with pk_)
    /// </summary>
    public string PublishableKey { get; set; } = string.Empty;

    /// <summary>
    /// Clerk Frontend API URL
    /// </summary>
    public string FrontendApi { get; set; } = string.Empty;
}

// ==============================================================================
// SERVICE EXTENSIONS
// ==============================================================================

public static class ClerkServiceExtensions
{
    /// <summary>
    /// Adiciona autenticação Clerk ao projeto
    /// Requer: Clerk.Net.AspNetCore.Security
    /// </summary>
    public static IServiceCollection AddClerkAuthentication(
        this IServiceCollection services,
        IConfiguration configuration)
    {
        services.Configure<ClerkOptions>(configuration.GetSection(ClerkOptions.SectionName));

        // Opção 1: Usando Clerk.Net SDK oficial
        // services.AddClerk(configuration);

        // Opção 2: Configuração manual com JWT
        services.AddAuthentication("Clerk")
            .AddJwtBearer("Clerk", options =>
            {
                var clerkOptions = configuration.GetSection(ClerkOptions.SectionName).Get<ClerkOptions>()!;

                options.Authority = clerkOptions.FrontendApi;
                options.TokenValidationParameters = new()
                {
                    ValidateIssuer = true,
                    ValidateAudience = false,
                    ValidateLifetime = true,
                    ValidateIssuerSigningKey = true,
                    NameClaimType = ClaimTypes.NameIdentifier
                };
            });

        services.AddAuthorization();

        return services;
    }

    /// <summary>
    /// Adiciona Clerk para Blazor Server
    /// </summary>
    public static IServiceCollection AddClerkBlazor(
        this IServiceCollection services,
        IConfiguration configuration)
    {
        services.AddClerkAuthentication(configuration);
        services.AddScoped<AuthenticationStateProvider, ClerkAuthenticationStateProvider>();
        services.AddCascadingAuthenticationState();

        return services;
    }
}

// ==============================================================================
// AUTHENTICATION STATE PROVIDER (Blazor)
// ==============================================================================

public class ClerkAuthenticationStateProvider : AuthenticationStateProvider
{
    private readonly IHttpContextAccessor _httpContextAccessor;

    public ClerkAuthenticationStateProvider(IHttpContextAccessor httpContextAccessor)
    {
        _httpContextAccessor = httpContextAccessor;
    }

    public override Task<AuthenticationState> GetAuthenticationStateAsync()
    {
        var user = _httpContextAccessor.HttpContext?.User ?? new ClaimsPrincipal();
        return Task.FromResult(new AuthenticationState(user));
    }

    public void NotifyAuthenticationStateChanged()
    {
        NotifyAuthenticationStateChanged(GetAuthenticationStateAsync());
    }
}

// ==============================================================================
// CLERK USER SERVICE
// ==============================================================================

public interface IClerkUserService
{
    Task<ClerkUser?> GetCurrentUserAsync(CancellationToken ct = default);
    Task<ClerkUser?> GetUserByIdAsync(string userId, CancellationToken ct = default);
    Task UpdateUserMetadataAsync(string userId, Dictionary<string, object> metadata, CancellationToken ct = default);
}

public class ClerkUserService : IClerkUserService
{
    private readonly HttpClient _httpClient;
    private readonly IHttpContextAccessor _httpContextAccessor;
    private readonly ILogger<ClerkUserService> _logger;

    public ClerkUserService(
        HttpClient httpClient,
        IHttpContextAccessor httpContextAccessor,
        ILogger<ClerkUserService> logger)
    {
        _httpClient = httpClient;
        _httpContextAccessor = httpContextAccessor;
        _logger = logger;
    }

    public async Task<ClerkUser?> GetCurrentUserAsync(CancellationToken ct = default)
    {
        var userId = _httpContextAccessor.HttpContext?.User.FindFirstValue(ClaimTypes.NameIdentifier);
        if (string.IsNullOrEmpty(userId)) return null;

        return await GetUserByIdAsync(userId, ct);
    }

    public async Task<ClerkUser?> GetUserByIdAsync(string userId, CancellationToken ct = default)
    {
        try
        {
            var response = await _httpClient.GetAsync($"users/{userId}", ct);

            if (!response.IsSuccessStatusCode)
            {
                _logger.LogWarning("Failed to get Clerk user {UserId}: {Status}", userId, response.StatusCode);
                return null;
            }

            return await response.Content.ReadFromJsonAsync<ClerkUser>(ct);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error getting Clerk user {UserId}", userId);
            return null;
        }
    }

    public async Task UpdateUserMetadataAsync(string userId, Dictionary<string, object> metadata, CancellationToken ct = default)
    {
        var request = new { public_metadata = metadata };
        var response = await _httpClient.PatchAsJsonAsync($"users/{userId}", request, ct);
        response.EnsureSuccessStatusCode();
    }
}

// ==============================================================================
// CLERK USER MODEL
// ==============================================================================

public record ClerkUser
{
    public string Id { get; init; } = string.Empty;
    public string? FirstName { get; init; }
    public string? LastName { get; init; }
    public string? ImageUrl { get; init; }
    public List<ClerkEmailAddress>? EmailAddresses { get; init; }
    public string? PrimaryEmailAddressId { get; init; }
    public Dictionary<string, object>? PublicMetadata { get; init; }
    public long CreatedAt { get; init; }
    public long UpdatedAt { get; init; }

    public string? PrimaryEmail => EmailAddresses?
        .FirstOrDefault(e => e.Id == PrimaryEmailAddressId)?.EmailAddress;

    public string FullName => $"{FirstName} {LastName}".Trim();
}

public record ClerkEmailAddress
{
    public string Id { get; init; } = string.Empty;
    public string EmailAddress { get; init; } = string.Empty;
    public bool Verified { get; init; }
}

// ==============================================================================
// MIDDLEWARE PIPELINE
// ==============================================================================

public static class ClerkMiddlewareExtensions
{
    public static IApplicationBuilder UseClerkAuthentication(this IApplicationBuilder app)
    {
        app.UseAuthentication();
        app.UseAuthorization();
        return app;
    }
}

// ==============================================================================
// APPSETTINGS EXAMPLE
// ==============================================================================

/*
{
  "Clerk": {
    "SecretKey": "sk_test_xxxxx",
    "PublishableKey": "pk_test_xxxxx",
    "FrontendApi": "https://your-app.clerk.accounts.dev"
  }
}
*/

// ==============================================================================
// PROGRAM.CS EXAMPLE
// ==============================================================================

/*
// Program.cs
var builder = WebApplication.CreateBuilder(args);

// Add Clerk authentication
builder.Services.AddClerkAuthentication(builder.Configuration);
// Or for Blazor:
// builder.Services.AddClerkBlazor(builder.Configuration);

var app = builder.Build();

app.UseClerkAuthentication();

app.MapControllers().RequireAuthorization();

app.Run();
*/
