<?php

namespace App\Http\Middleware;

use App\Models\ApiClientKey;
use Closure;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
use Symfony\Component\HttpFoundation\Response;

class EnsureApiClientKey
{
    public function handle(Request $request, Closure $next): Response
    {
        $user = $request->user();
        if (!$user) {
            return response()->json(['error' => 'Unauthenticated'], 401);
        }

        $plainKey = $request->header('X-Api-Key');
        if (!$plainKey) {
            return response()->json(['error' => 'Missing API key'], 401);
        }

        $key = ApiClientKey::where('key_hash', hash('sha256', $plainKey))->first();
        if (!$key || !$key->isUsable() || $key->user_id !== $user->id) {
            return response()->json(['error' => 'Invalid API key'], 401);
        }

        $minuteLimit = (int) $user->planLimit('api_rate_limit_per_minute', $key->rate_limit_per_minute);
        $dayLimit = (int) $user->planLimit('api_rate_limit_per_day', $key->rate_limit_per_day);
        $minuteCount = $this->incrementCounter('minute', $key->id, now()->format('YmdHi'));
        $dayCount = $this->incrementCounter('day', $key->id, now()->format('Ymd'));

        if ($minuteCount > $minuteLimit || $dayCount > $dayLimit) {
            return new JsonResponse([
                'error' => 'API key rate limit exceeded',
                'limits' => ['per_minute' => $minuteLimit, 'per_day' => $dayLimit],
            ], 429);
        }

        $key->forceFill([
            'last_used_at' => now(),
            'last_used_ip' => $request->ip(),
            'plan_snapshot' => $user->currentPlanDetails(),
            'rate_limit_per_minute' => $minuteLimit,
            'rate_limit_per_day' => $dayLimit,
        ])->save();

        $request->attributes->set('api_client_key', $key);

        /** @var Response $response */
        $response = $next($request);
        $response->headers->set('X-RateLimit-Per-Minute', (string) $minuteLimit);
        $response->headers->set('X-RateLimit-Per-Day', (string) $dayLimit);
        $response->headers->set('X-RateLimit-Used-Minute', (string) $minuteCount);
        $response->headers->set('X-RateLimit-Used-Day', (string) $dayCount);

        return $response;
    }

    private function incrementCounter(string $scope, string $keyId, string $bucket): int
    {
        $cacheKey = "api_key_limit:{$scope}:{$keyId}:{$bucket}";
        if (!Cache::has($cacheKey)) {
            Cache::put($cacheKey, 0, $scope === 'minute' ? now()->addMinute() : now()->endOfDay());
        }

        return (int) Cache::increment($cacheKey);
    }
}
