<?php

namespace App\Http\Middleware;

use App\Models\ApiRequestLog;
use App\Services\Api\RequestLogSanitizer;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Symfony\Component\HttpFoundation\Response;

class ApiRequestLogger
{
    public function handle(Request $request, Closure $next): Response
    {
        if (!$request->isMethod('POST') || !$request->is('api/v1') && !$request->is('api/v1/*')) {
            return $next($request);
        }

        $requestUuid = (string) \Illuminate\Support\Str::uuid();
        $startedAt = now();
        $hrtimeStart = hrtime(true);

        $response = null;
        try {
            $response = $next($request);
        } finally {
            if ($response !== null) {
            try {
                $endedAt = now();
                $durationNs = hrtime(true) - $hrtimeStart;
                $durationMs = (int) round($durationNs / 1e6);

                $httpStatus = $response->getStatusCode();

                $responseSize = null;
                if (!$response instanceof \Symfony\Component\HttpFoundation\StreamedResponse) {
                    try {
                        $content = $response->getContent();
                        $responseSize = $content !== false ? strlen($content) : null;
                    } catch (\Throwable) {
                        $responseSize = null;
                    }
                }

                $success = null;
                $errorCode = null;
                $errorMessage = null;
                try {
                    $content = $response->getContent();
                    if ($content !== false) {
                        $decoded = json_decode($content, true);
                        if (is_array($decoded)) {
                            $success = $decoded['success'] ?? null;
                            $errorCode = isset($decoded['code']) ? (int) $decoded['code'] : null;
                            $errorMessage = isset($decoded['error']) ? (string) $decoded['error'] : null;
                        }
                    }
                } catch (\Throwable) {
                    // leave success, errorCode, errorMessage as null
                }

                $bodyContent = $request->getContent();
                $bodyArray = null;
                if ($bodyContent !== false && $bodyContent !== '') {
                    $bodyArray = json_decode($bodyContent, true);
                }
                if (!is_array($bodyArray)) {
                    $bodyArray = [];
                }

                $action = $bodyArray['action'] ?? null;
                $plugin = $bodyArray['plugin'] ?? null;
                $host = $bodyArray['host'] ?? null;
                $version = $bodyArray['version'] ?? null;
                $projectid = $bodyArray['projectid'] ?? null;
                $environmentPayload = $bodyArray['environment'] ?? $bodyArray['site'] ?? null;
                if ($environmentPayload !== null && !is_array($environmentPayload)) {
                    $environmentPayload = null;
                }
                if (is_array($environmentPayload)) {
                    $environmentPayload = RequestLogSanitizer::redactSubtree($environmentPayload);
                }

                $payloadStored = RequestLogSanitizer::payloadForStorage($bodyArray);

                $allHeaders = $request->headers->all();
                $sanitizedHeaders = RequestLogSanitizer::sanitizeHeaders($allHeaders);

                $queryParams = $request->query->all();

                $bearerToken = $request->bearerToken();
                $authType = $bearerToken ? 'bearer' : 'none';
                $bearerTokenHash = null;
                if ($bearerToken && $httpStatus >= 400) {
                    $bearerTokenHash = hash('sha256', $bearerToken);
                }

                $licenseTokenId = null;
                $environmentId = null;
                $clientId = null;
                $licenseToken = $request->get('_license_token');
                $environment = $request->get('_environment');
                if ($licenseToken instanceof \App\Models\Products\LicenseToken) {
                    $licenseTokenId = $licenseToken->id;
                    $clientId = $licenseToken->client_id;
                }
                if ($environment instanceof \App\Models\Environments\Environment) {
                    $environmentId = $environment->id;
                    if ($clientId === null && $environment->client_id) {
                        $clientId = $environment->client_id;
                    }
                }

                ApiRequestLog::create([
                    'request_uuid' => $requestUuid,
                    'method' => $request->getMethod(),
                    'path' => $request->path(),
                    'ip' => $request->ip(),
                    'user_agent' => $request->userAgent(),
                    'headers' => $sanitizedHeaders,
                    'query' => $queryParams ?: null,
                    'auth_type' => $authType,
                    'bearer_token_hash' => $bearerTokenHash,
                    'license_token_id' => $licenseTokenId,
                    'environment_id' => $environmentId,
                    'client_id' => $clientId,
                    'action' => $action ? (string) $action : null,
                    'plugin' => $plugin ? (string) $plugin : null,
                    'host' => $host ? (string) $host : null,
                    'version' => $version ? (string) $version : null,
                    'projectid' => $projectid ? (string) $projectid : null,
                    'environment' => $environmentPayload,
                    'payload' => $payloadStored,
                    'http_status' => $httpStatus,
                    'success' => $success,
                    'error_code' => $errorCode,
                    'error' => $errorMessage,
                    'response_size' => $responseSize,
                    'duration_ms' => $durationMs,
                    'started_at' => $startedAt,
                    'ended_at' => $endedAt,
                ]);
            } catch (\Throwable $e) {
                Log::error('ApiRequestLogger failed to persist log', [
                    'request_uuid' => $requestUuid ?? 'unknown',
                    'exception' => $e->getMessage(),
                ]);
            }
            }
        }

        return $response;
    }
}
