using System.Security.Claims;
using JobTrackerApi.Models;
using Microsoft.AspNetCore.Identity;

namespace JobTrackerApi.Services;

public sealed record AiPrivacyDecision(bool ExternalProcessingAllowed, string Provider);

public sealed class AiPrivacyPolicy(IConfiguration configuration, IServiceScopeFactory scopes)
{
    public const string ExternalAllowedHeader = "X-Ai-External-Allowed";
    public const string TaskTypeHeader = "X-Ai-Task-Type";

    public string ExternalProvider
    {
        get
        {
            var provider = (configuration["Ai:ExternalProvider"] ?? "ollama").Trim().ToLowerInvariant();
            return provider is "gemini" or "groq" ? provider : "ollama";
        }
    }

    public string RoutingMode
    {
        get
        {
            var mode = (configuration["Ai:RoutingMode"] ?? "local_first").Trim().ToLowerInvariant();
            return mode is "local_only" or "local_first" or "external_only" ? mode : "local_only";
        }
    }

    public bool ExternalProcessingAvailable =>
        configuration.GetValue("Ai:ExternalProcessingEnabled", false)
        && RoutingMode != "local_only"
        && ExternalProvider is "gemini" or "groq";

    public async Task<AiPrivacyDecision> EvaluateAsync(string? userId, CancellationToken cancellationToken = default)
    {
        if (!ExternalProcessingAvailable || string.IsNullOrWhiteSpace(userId))
            return new AiPrivacyDecision(false, "local");

        await using var scope = scopes.CreateAsyncScope();
        var users = scope.ServiceProvider.GetRequiredService<UserManager<ApplicationUser>>();
        var user = await users.FindByIdAsync(userId);
        cancellationToken.ThrowIfCancellationRequested();
        if (user is null || !user.AiEnabled || !user.ExternalAiProcessingAllowed)
            return new AiPrivacyDecision(false, "local");

        var isPro = AccountPlans.ForRoles(await users.GetRolesAsync(user)).Ai;
        return isPro
            ? new AiPrivacyDecision(true, ExternalProvider)
            : new AiPrivacyDecision(false, "local");
    }
}

public sealed class AiPrivacyHeaderHandler(
    IHttpContextAccessor httpContext,
    AiPrivacyPolicy privacyPolicy,
    AiOperationExecutionScope executionScope) : DelegatingHandler
{
    protected override async Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request,
        CancellationToken cancellationToken)
    {
        if (request.RequestUri?.AbsolutePath.StartsWith("/cv/", StringComparison.OrdinalIgnoreCase) == true)
        {
            var operationContext = executionScope.Current;
            var externalAllowed = operationContext?.EffectivePrivacyPolicy == "external_allowed";
            if (operationContext is not null)
                request.Headers.TryAddWithoutValidation(AiPrivacyPolicy.TaskTypeHeader, operationContext.Lease.TaskType);
            else
            {
                var userId = httpContext.HttpContext?.User.FindFirstValue(ClaimTypes.NameIdentifier)
                    ?? httpContext.HttpContext?.User.FindFirstValue("sub");
                externalAllowed = (await privacyPolicy.EvaluateAsync(userId, cancellationToken)).ExternalProcessingAllowed;
            }

            if (externalAllowed)
                request.Headers.TryAddWithoutValidation(AiPrivacyPolicy.ExternalAllowedHeader, "true");
        }

        return await base.SendAsync(request, cancellationToken);
    }
}
