<?php

declare(strict_types=1);

namespace App\Http\Middleware;

use App\Services\Traffic\OnlineVisitorRepository;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

final class TrackOnlineVisitor
{
    public function __construct(private readonly OnlineVisitorRepository $visitors)
    {
    }

    public function handle(Request $request, Closure $next): Response
    {
        $shouldTrack = $this->shouldTrack($request);
        $response = $next($request);

        if ($shouldTrack) {
            try {
                $this->visitors->track($request);
            } catch (\Throwable) {
                // Presence tracking is best-effort only.
            }
        }

        return $response;
    }

    private function shouldTrack(Request $request): bool
    {
        if (! in_array($request->getMethod(), ['GET', 'HEAD'], true)) {
            return false;
        }

        if ($this->matchesAny($request, [
            'build/*',
            'storage/*',
            'favicon.ico',
            'livewire/*',
            '_debugbar/*',
            'telescope/*',
            'horizon/*',
            'moderation/*',
        ])) {
            return false;
        }

        if ($request->path() === 'moderation/traffic/online/data') {
            return false;
        }

        if ($this->matchesAny($request, [
            'api/*',
            'admin/*',
            'dashboard*',
            'studio*',
            'settings*',
            'messages*',
            'creator*',
            'login',
            'register',
            'forgot-password',
            'reset-password/*',
            'email/*',
            'logout',
            'up',
        ])) {
            return false;
        }

        return ! $this->isStaticAssetPath($request->path());
    }

    /**
     * @param array<int, string> $patterns
     */
    private function matchesAny(Request $request, array $patterns): bool
    {
        foreach ($patterns as $pattern) {
            if ($request->is($pattern)) {
                return true;
            }
        }

        return false;
    }

    private function isStaticAssetPath(string $path): bool
    {
        $normalizedPath = '/' . ltrim($path, '/');

        if (in_array($normalizedPath, ['/robots.txt', '/sitemap.xml'], true) || str_starts_with($normalizedPath, '/sitemaps/')) {
            return false;
        }

        return (bool) preg_match('/\.(?:css|js|mjs|map|png|jpe?g|gif|svg|webp|avif|ico|woff2?|ttf|eot|otf|mp4|webm|mp3|wav|pdf|zip)$/i', $normalizedPath);
    }
}