// ==============================================================================
// MORPH-SPEC - Azure Identity (Microsoft Identity) Configuration Template
// Configuração de autenticação com Microsoft Identity Platform
// ==============================================================================

using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.Identity.Web;
using Microsoft.Identity.Web.UI;
using System.Security.Claims;

namespace {{Namespace}}.Infrastructure.Auth;

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

public static class AzureIdentityServiceExtensions
{
    /// <summary>
    /// Adiciona autenticação Microsoft Identity para Web Apps
    /// Requer: Microsoft.Identity.Web, Microsoft.Identity.Web.UI
    /// </summary>
    public static IServiceCollection AddAzureIdentityAuthentication(
        this IServiceCollection services,
        IConfiguration configuration)
    {
        services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
            .AddMicrosoftIdentityWebApp(configuration.GetSection("AzureAd"));

        services.AddControllersWithViews()
            .AddMicrosoftIdentityUI();

        services.AddAuthorization(options =>
        {
            // Default policy - requires authenticated user
            options.FallbackPolicy = options.DefaultPolicy;

            // Custom policies
            options.AddPolicy("RequireAdmin", policy =>
                policy.RequireRole("Admin"));

            options.AddPolicy("RequireManager", policy =>
                policy.RequireAssertion(context =>
                    context.User.IsInRole("Admin") ||
                    context.User.IsInRole("Manager")));
        });

        return services;
    }

    /// <summary>
    /// Adiciona autenticação Microsoft Identity para Blazor Server
    /// </summary>
    public static IServiceCollection AddAzureIdentityBlazor(
        this IServiceCollection services,
        IConfiguration configuration)
    {
        services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
            .AddMicrosoftIdentityWebApp(configuration.GetSection("AzureAd"));

        services.AddControllersWithViews()
            .AddMicrosoftIdentityUI();

        services.AddRazorPages();
        services.AddServerSideBlazor()
            .AddMicrosoftIdentityConsentHandler();

        services.AddAuthorization();

        return services;
    }

    /// <summary>
    /// Adiciona autenticação Microsoft Identity para APIs (JWT Bearer)
    /// </summary>
    public static IServiceCollection AddAzureIdentityApi(
        this IServiceCollection services,
        IConfiguration configuration)
    {
        services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
            .AddMicrosoftIdentityWebApi(configuration.GetSection("AzureAd"));

        services.AddAuthorization();

        return services;
    }

    /// <summary>
    /// Adiciona suporte para chamar APIs downstream (Graph, custom APIs)
    /// </summary>
    public static IServiceCollection AddAzureIdentityWithDownstreamApi(
        this IServiceCollection services,
        IConfiguration configuration)
    {
        services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
            .AddMicrosoftIdentityWebApp(configuration.GetSection("AzureAd"))
            .EnableTokenAcquisitionToCallDownstreamApi()
            .AddMicrosoftGraph(configuration.GetSection("Graph"))
            .AddInMemoryTokenCaches();

        return services;
    }
}

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

public interface IAzureIdentityUserService
{
    string? GetUserId();
    string? GetUserEmail();
    string? GetUserName();
    IEnumerable<string> GetUserRoles();
    bool IsAuthenticated();
    bool IsInRole(string role);
}

public class AzureIdentityUserService : IAzureIdentityUserService
{
    private readonly IHttpContextAccessor _httpContextAccessor;

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

    private ClaimsPrincipal? User => _httpContextAccessor.HttpContext?.User;

    public string? GetUserId() =>
        User?.FindFirstValue(ClaimTypes.NameIdentifier) ??
        User?.FindFirstValue("oid"); // Azure AD Object ID

    public string? GetUserEmail() =>
        User?.FindFirstValue(ClaimTypes.Email) ??
        User?.FindFirstValue("preferred_username");

    public string? GetUserName() =>
        User?.FindFirstValue(ClaimTypes.Name) ??
        User?.FindFirstValue("name");

    public IEnumerable<string> GetUserRoles() =>
        User?.FindAll(ClaimTypes.Role).Select(c => c.Value) ??
        Enumerable.Empty<string>();

    public bool IsAuthenticated() =>
        User?.Identity?.IsAuthenticated ?? false;

    public bool IsInRole(string role) =>
        User?.IsInRole(role) ?? false;
}

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

public static class AzureIdentityMiddlewareExtensions
{
    public static IApplicationBuilder UseAzureIdentityAuthentication(this IApplicationBuilder app)
    {
        app.UseAuthentication();
        app.UseAuthorization();
        return app;
    }
}

// ==============================================================================
// BLAZOR COMPONENTS HELPER
// ==============================================================================

/*
<!-- App.razor -->
<CascadingAuthenticationState>
    <Router AppAssembly="@typeof(App).Assembly">
        <Found Context="routeData">
            <AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)">
                <NotAuthorized>
                    @if (!context.User.Identity?.IsAuthenticated ?? true)
                    {
                        <RedirectToLogin />
                    }
                    else
                    {
                        <p>Você não tem permissão para acessar este recurso.</p>
                    }
                </NotAuthorized>
            </AuthorizeRouteView>
        </Found>
    </Router>
</CascadingAuthenticationState>
*/

// ==============================================================================
// REDIRECT TO LOGIN COMPONENT
// ==============================================================================

/*
<!-- Components/RedirectToLogin.razor -->
@inject NavigationManager Navigation

@code {
    protected override void OnInitialized()
    {
        var returnUrl = Uri.EscapeDataString(Navigation.Uri);
        Navigation.NavigateTo($"MicrosoftIdentity/Account/SignIn?redirectUri={returnUrl}", forceLoad: true);
    }
}
*/

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

/*
{
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "Domain": "yourdomain.onmicrosoft.com",
    "TenantId": "your-tenant-id",
    "ClientId": "your-client-id",
    "ClientSecret": "your-client-secret",
    "CallbackPath": "/signin-oidc"
  },
  "Graph": {
    "BaseUrl": "https://graph.microsoft.com/v1.0",
    "Scopes": "User.Read"
  }
}
*/

// ==============================================================================
// PROGRAM.CS EXAMPLES
// ==============================================================================

/*
// Web App (MVC/Razor Pages)
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAzureIdentityAuthentication(builder.Configuration);

var app = builder.Build();
app.UseAzureIdentityAuthentication();
app.MapControllers();
app.Run();

// Blazor Server
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAzureIdentityBlazor(builder.Configuration);

var app = builder.Build();
app.UseAzureIdentityAuthentication();
app.MapBlazorHub();
app.MapFallbackToPage("/_Host");
app.Run();

// API (JWT Bearer)
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAzureIdentityApi(builder.Configuration);

var app = builder.Build();
app.UseAzureIdentityAuthentication();
app.MapControllers().RequireAuthorization();
app.Run();
*/

// ==============================================================================
// AZURE AD B2C CONFIGURATION
// ==============================================================================

/*
// For Azure AD B2C, use this configuration:
{
  "AzureAdB2C": {
    "Instance": "https://yourtenant.b2clogin.com",
    "Domain": "yourtenant.onmicrosoft.com",
    "TenantId": "your-tenant-id",
    "ClientId": "your-client-id",
    "SignUpSignInPolicyId": "B2C_1_signupsignin",
    "ResetPasswordPolicyId": "B2C_1_passwordreset",
    "EditProfilePolicyId": "B2C_1_editprofile"
  }
}

// And use:
services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApp(configuration.GetSection("AzureAdB2C"));
*/
