using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.EntityFrameworkCore;
using watcher_monitoring.Data;

namespace watcher_monitoring.Attributes;

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class ApiKeyAuthAttribute : Attribute, IAsyncActionFilter
{
    private const string ApiKeyHeaderName = "X-API-Key";

    public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
    {
        if (!context.HttpContext.Request.Headers.TryGetValue(ApiKeyHeaderName, out var extractedApiKey))
        {
            context.Result = new UnauthorizedObjectResult(new { error = "API-Key fehlt im Header" });
            return;
        }

        var apiKeyString = extractedApiKey.ToString();

        var dbContext = context.HttpContext.RequestServices.GetRequiredService<WatcherDbContext>();
        var logger = context.HttpContext.RequestServices.GetRequiredService<ILogger<ApiKeyAuthAttribute>>();

        var apiKey = await dbContext.ApiKeys
            .FirstOrDefaultAsync(k => k.Key == apiKeyString);

        if (apiKey == null)
        {
            logger.LogWarning("Ungültiger API-Key verwendet: {ApiKey}", apiKeyString);
            context.Result = new UnauthorizedObjectResult(new { error = "Ungültiger API-Key" });
            return;
        }

        if (!apiKey.IsActive)
        {
            logger.LogWarning("Inaktiver API-Key verwendet: {Name}", apiKey.Name);
            context.Result = new UnauthorizedObjectResult(new { error = "API-Key ist deaktiviert" });
            return;
        }

        if (apiKey.IsExpired)
        {
            logger.LogWarning("Abgelaufener API-Key verwendet: {Name}", apiKey.Name);
            context.Result = new UnauthorizedObjectResult(new { error = "API-Key ist abgelaufen" });
            return;
        }

        // Letzten Verwendungszeitpunkt aktualisieren
        apiKey.LastUsedAt = DateTime.UtcNow;
        await dbContext.SaveChangesAsync();

        logger.LogInformation("API-Zugriff mit Key: {Name}", apiKey.Name);

        await next();
    }
}
