using ScadaLink.Commons.Entities.InboundApi;
using ScadaLink.Commons.Interfaces.Repositories;

namespace ScadaLink.InboundAPI;

/// <summary>
/// WP-1: Validates API keys from X-API-Key header.
/// Checks that the key exists, is enabled, and is approved for the requested method.
/// </summary>
public class ApiKeyValidator
{
    private readonly IInboundApiRepository _repository;

    public ApiKeyValidator(IInboundApiRepository repository)
    {
        _repository = repository;
    }

    /// <summary>
    /// Validates an API key for a given method.
    /// Returns (isValid, apiKey, statusCode, errorMessage).
    /// </summary>
    public async Task<ApiKeyValidationResult> ValidateAsync(
        string? apiKeyValue,
        string methodName,
        CancellationToken cancellationToken = default)
    {
        if (string.IsNullOrEmpty(apiKeyValue))
        {
            return ApiKeyValidationResult.Unauthorized("Missing X-API-Key header");
        }

        var apiKey = await _repository.GetApiKeyByValueAsync(apiKeyValue, cancellationToken);
        if (apiKey == null || !apiKey.IsEnabled)
        {
            return ApiKeyValidationResult.Unauthorized("Invalid or disabled API key");
        }

        var method = await _repository.GetMethodByNameAsync(methodName, cancellationToken);
        if (method == null)
        {
            return ApiKeyValidationResult.NotFound($"Method '{methodName}' not found");
        }

        // Check if this key is approved for the method
        var approvedKeys = await _repository.GetApprovedKeysForMethodAsync(method.Id, cancellationToken);
        var isApproved = approvedKeys.Any(k => k.Id == apiKey.Id);

        if (!isApproved)
        {
            return ApiKeyValidationResult.Forbidden("API key not approved for this method");
        }

        return ApiKeyValidationResult.Valid(apiKey, method);
    }
}

/// <summary>
/// Result of API key validation.
/// </summary>
public class ApiKeyValidationResult
{
    public bool IsValid { get; private init; }
    public int StatusCode { get; private init; }
    public string? ErrorMessage { get; private init; }
    public ApiKey? ApiKey { get; private init; }
    public ApiMethod? Method { get; private init; }

    public static ApiKeyValidationResult Valid(ApiKey apiKey, ApiMethod method) =>
        new() { IsValid = true, StatusCode = 200, ApiKey = apiKey, Method = method };

    public static ApiKeyValidationResult Unauthorized(string message) =>
        new() { IsValid = false, StatusCode = 401, ErrorMessage = message };

    public static ApiKeyValidationResult Forbidden(string message) =>
        new() { IsValid = false, StatusCode = 403, ErrorMessage = message };

    public static ApiKeyValidationResult NotFound(string message) =>
        new() { IsValid = false, StatusCode = 400, ErrorMessage = message };
}
