<?php

namespace App\Http\Middleware;

use App\Models\ApiClient;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;

class ApiClientAuthenticate
{
    public function handle(Request $request, Closure $next)
    {
        $publicKey = trim((string) $request->header('X-Api-Key', ''));
        $timestamp = trim((string) $request->header('X-Timestamp', ''));
        $nonce = trim((string) $request->header('X-Nonce', ''));
        $signature = trim((string) $request->header('X-Signature', ''));

        if ($publicKey === '' || $timestamp === '' || $nonce === '' || $signature === '') {
            return response()->json([
                'success' => false,
                'message' => 'Missing authentication headers.',
                'required' => ['X-Api-Key', 'X-Timestamp', 'X-Nonce', 'X-Signature'],
            ], 401);
        }

        if (! ctype_digit($timestamp)) {
            return response()->json(['success' => false, 'message' => 'Invalid timestamp format.'], 401);
        }

        $now = now()->timestamp;
        $ts = (int) $timestamp;
        if (abs($now - $ts) > 300) {
            return response()->json(['success' => false, 'message' => 'Timestamp outside allowed window.'], 401);
        }

        $client = ApiClient::query()
            ->with('user')
            ->where('public_key', $publicKey)
            ->where('status', 'active')
            ->first();

        if (! $client || ! $client->user || ! $client->user->isActiveCustomer()) {
            return response()->json(['success' => false, 'message' => 'Invalid API credentials.'], 401);
        }

        if (! $this->ipAllowed($client, (string) $request->ip())) {
            return response()->json(['success' => false, 'message' => 'IP address is not allowed for this API key.'], 403);
        }

        $nonceCacheKey = "api:nonce:{$client->id}:".sha1($nonce);
        if (Cache::has($nonceCacheKey)) {
            return response()->json(['success' => false, 'message' => 'Replay detected for nonce.'], 409);
        }

        $bodyHash = hash('sha256', (string) $request->getContent());
        $payload = strtoupper((string) $request->method())."\n"
            .$request->path()."\n"
            .$timestamp."\n"
            .$nonce."\n"
            .$bodyHash;

        $expected = hash_hmac('sha256', $payload, (string) $client->secret);

        if (! hash_equals($expected, $signature)) {
            return response()->json(['success' => false, 'message' => 'Invalid API signature.'], 401);
        }

        Cache::put($nonceCacheKey, true, now()->addMinutes(5));

        $client->forceFill(['last_used_at' => now()])->save();

        $request->attributes->set('api_client', $client);
        $request->setUserResolver(fn () => $client->user);

        return $next($request);
    }

    protected function ipAllowed(ApiClient $client, string $ip): bool
    {
        $whitelist = array_values(array_filter(array_map('trim', (array) ($client->ip_whitelist_json ?? []))));

        if (count($whitelist) === 0) {
            return true;
        }

        return in_array($ip, $whitelist, true);
    }
}
