<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;

class EnsureMobileClientRequest
{
    public function handle(Request $request, Closure $next): mixed
    {
        $clientHeader = (string) config('mobile_exam.client_header', 'X-Mobile-Client');
        $keyHeader = (string) config('mobile_exam.key_header', 'X-Mobile-Key');
        $expectedClient = trim((string) config('mobile_exam.client_name', ''));
        $expectedKey = trim((string) config('mobile_exam.api_key', ''));

        $providedClient = trim((string) $request->headers->get($clientHeader, ''));
        $providedKey = trim((string) $request->headers->get($keyHeader, ''));

        if ($expectedClient === '' || $providedClient === '' || ! hash_equals($expectedClient, $providedClient)) {
            return $this->forbidden('Application client is not allowed.');
        }

        if ($expectedKey === '' || $providedKey === '' || ! hash_equals($expectedKey, $providedKey)) {
            return $this->forbidden('Application access key is invalid.');
        }

        if ((bool) config('mobile_exam.require_signature', false)) {
            $signatureHeader = (string) config('mobile_exam.signature_header', 'X-Mobile-Signature');
            $timestampHeader = (string) config('mobile_exam.timestamp_header', 'X-Mobile-Timestamp');
            $providedSignature = trim((string) $request->headers->get($signatureHeader, ''));
            $providedTimestamp = (int) $request->headers->get($timestampHeader, 0);
            $allowedDrift = max(30, (int) config('mobile_exam.signature_ttl_seconds', 300));

            if ($providedTimestamp <= 0 || abs(now()->timestamp - $providedTimestamp) > $allowedDrift) {
                return $this->forbidden('Request timestamp is invalid or expired.');
            }

            $signaturePayload = implode('|', [
                strtoupper($request->method()),
                '/' . ltrim($request->path(), '/'),
                (string) $providedTimestamp,
                hash('sha256', $request->getContent()),
            ]);

            $expectedSignature = hash_hmac('sha256', $signaturePayload, $expectedKey);

            if ($providedSignature === '' || ! hash_equals($expectedSignature, $providedSignature)) {
                return $this->forbidden('Request signature is invalid.');
            }
        }

        // Force API-style validation and exception responses for mobile clients.
        $request->headers->set('Accept', 'application/json');

        return $next($request);
    }

    private function forbidden(string $message): JsonResponse
    {
        return response()->json([
            'message' => $message,
        ], 403);
    }
}
