<?php

namespace App\Http\Middleware;

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

/**
 * X-Api-Key-only authentication middleware for Flutter device clients.
 *
 * Unlike EnsureApiClientKey (which requires auth:sanctum to run first),
 * this middleware validates the API key AND sets the authenticated user
 * from the key's owner — no Bearer token required.
 *
 * Used for the /api/v1/ compatibility routes so Flutter apps can sync
 * using just the API key provisioned via /api/auth/firebase.
 */
class EnsureDeviceApiKey
{
    /**
     * @param  string  ...$options  Pass 'no-count' to skip per-key rate counting
     *                              (used for billing/subscription routes that must
     *                              never be blocked by sync burst traffic).
     */
    public function handle(Request $request, Closure $next, string ...$options): Response
    {
        $plainKey = $request->header('X-Api-Key');
        if (!$plainKey) {
            return response()->json(['error' => 'Missing X-Api-Key header'], 401);
        }

        $key = ApiClientKey::with('user')
            ->where('key_hash', hash('sha256', $plainKey))
            ->first();

        if (!$key || !$key->isUsable()) {
            return response()->json(['error' => 'Invalid or revoked API key'], 401);
        }

        $user = $key->user;
        if (!$user || $user->is_banned) {
            return response()->json(['error' => 'Account suspended or not found'], 403);
        }

        $skipCounting = in_array('no-count', $options, true);

        if (!$skipCounting) {
            // Rate limiting (shared logic with EnsureApiClientKey)
            $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 rate limit exceeded',
                    'limits' => ['per_minute' => $minuteLimit, 'per_day' => $dayLimit],
                ], 429);
            }
        }

        // Authenticate the user for this request cycle
        Auth::setUser($user);

        $key->forceFill([
            'last_used_at' => now(),
            'last_used_ip' => $request->ip(),
        ])->save();

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

        /** @var Response $response */
        $response = $next($request);

        if (!$skipCounting) {
            $minuteLimit = $minuteLimit ?? (int) $user->planLimit('api_rate_limit_per_minute', $key->rate_limit_per_minute);
            $dayLimit    = $dayLimit    ?? (int) $user->planLimit('api_rate_limit_per_day',    $key->rate_limit_per_day);
            $minuteCount = $minuteCount ?? 0;
            $dayCount    = $dayCount    ?? 0;
            $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);
    }
}
