<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;

class LogApiRequests
{
    public function handle(Request $request, Closure $next)
    {
        $start = microtime(true);

        $response = $next($request);

        $duration = round((microtime(true) - $start) * 1000, 2);

        $logData = [
            'request' => [
                'method'  => $request->method(),
                'url'     => $request->fullUrl(),
                'path'    => $request->path(),
                'route'   => optional($request->route())->getName(),
                'module'  => $this->detectModule($request),
                'ip'      => $request->ip(),
                'headers' => $this->filteredHeaders($request),
                'payload' => $this->filteredPayload($request),
            ],
            'response' => [
                'status'      => $response->status(),
                'time_ms'     => $duration,
            ],
            'user' => [
                'id'    => auth()->id(),
                'email' => auth()->user()?->email,
            ],
            'meta' => [
                'user_agent' => $request->userAgent(),
                'timestamp'  => now()->toDateTimeString(),
            ],
        ];

        Log::channel('api_requests')->info('API REQUEST LOG', $logData);

        return $response;
    }

    private function detectModule(Request $request): string
    {
        if (!$request->route()) {
            return 'unknown';
        }

        $action = $request->route()->getActionName();

        if (Str::contains($action, 'Modules')) {
            return explode('\\', $action)[1] ?? 'module';
        }

        return 'app';
    }

    private function filteredHeaders(Request $request): array
    {
        return collect($request->headers->all())
            ->only([
                'accept',
                'content-type',
                'authorization',
                'x-request-id',
            ])
            ->map(fn ($v) => is_array($v) ? $v[0] : $v)
            ->toArray();
    }

    private function filteredPayload(Request $request): array
    {
        return collect($request->all())->toArray();
    }
}
