<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

/**
 * Adds hardening response headers to every web response.
 *
 * The Content-Security-Policy is deliberately PRAGMATIC: Livewire and Alpine
 * inject inline scripts/handlers and Alpine relies on `eval`, so 'unsafe-eval'
 * and 'unsafe-inline' are permitted for scripts/styles. connect-src allows
 * ws:/wss: so Reverb (realtime) and Vite HMR keep working in dev. This CSP can
 * be TIGHTENED LATER (e.g. nonce-based scripts, dropping 'unsafe-*') once the
 * app no longer depends on inline/eval — start strict on the structural
 * directives (base-uri, frame-ancestors) and relax only what the stack needs.
 */
class SecurityHeaders
{
    public function handle(Request $request, Closure $next): Response
    {
        $response = $next($request);

        $headers = $response->headers;

        $headers->set('X-Frame-Options', 'DENY');
        $headers->set('X-Content-Type-Options', 'nosniff');
        $headers->set('Referrer-Policy', 'strict-origin-when-cross-origin');
        $headers->set(
            'Permissions-Policy',
            'camera=(), microphone=(), geolocation=(), interest-cohort=()'
        );

        // Livewire/Alpine need inline + eval; Reverb rides ws/wss.
        $scriptSrc = ["'self'", "'unsafe-eval'", "'unsafe-inline'"];
        $styleSrc = ["'self'", "'unsafe-inline'"];
        $connectSrc = ["'self'", 'ws:', 'wss:'];
        $fontSrc = ["'self'"];

        // In dev, Vite serves the bundle + HMR from a SEPARATE origin (e.g.
        // http://host:5173). A same-origin CSP would block it and break the app,
        // so allow the running dev-server origin (from public/hot) outside prod.
        // In production assets are same-origin (/build) and this branch is inert.
        if (! app()->isProduction() && is_file(public_path('hot'))) {
            $dev = trim((string) file_get_contents(public_path('hot')));
            if ($dev !== '') {
                $devWs = preg_replace('#^http#', 'ws', $dev);
                array_push($scriptSrc, $dev);
                array_push($styleSrc, $dev);
                array_push($fontSrc, $dev);
                array_push($connectSrc, $dev, $devWs);
            }
        }

        $headers->set('Content-Security-Policy', implode('; ', [
            "default-src 'self'",
            'script-src '.implode(' ', $scriptSrc),
            'style-src '.implode(' ', $styleSrc),
            'connect-src '.implode(' ', $connectSrc),
            "img-src 'self' data:",
            'font-src '.implode(' ', $fontSrc),
            "base-uri 'self'",
            "form-action 'self'",
            "frame-ancestors 'none'",
        ]));

        // Only assert HSTS over an already-secure connection so we never
        // pin clients to HTTPS on a plain-HTTP dev/LAN deployment.
        if ($request->isSecure()) {
            $headers->set(
                'Strict-Transport-Security',
                'max-age=31536000; includeSubDomains'
            );
        }

        return $response;
    }
}
