<?php

namespace App\Support;

use App\Services\Settings;
use Illuminate\Http\Request;

/**
 * Helper for the admin-pasted analytics scripts feature. Reads
 * `marketing.scripts` Settings once per request and exposes:
 *
 *   - `payload()` — head/body strings + an `enabled` flag (true when either
 *     slot has non-whitespace content)
 *   - `isPublicMarketingRequest(Request)` — route-name-based check, true
 *     for the public marketing surface (welcome / pricing / about /
 *     contact / templates / privacy / terms / refund / custom pages)
 *   - `cspProfile(Request)` — convenience: returns 'permissive' when the
 *     two above are both true, else 'strict'
 *
 * The permissive CSP only applies on public marketing pages. Admin /
 * editor / auth surfaces stay strict regardless of script configuration —
 * the blast radius of a poisoned vendor snippet is bounded to the
 * unauthenticated marketing surface.
 */
class MarketingScripts
{
    /** Route names that constitute the "public marketing surface". When a
     *  request matches one of these AND scripts are configured, both the
     *  blade emit and the permissive-CSP profile activate. The `/` welcome
     *  route is unnamed in routes/web.php so it's handled separately by
     *  path match in {@see isPublicMarketingRequest}. */
    private const PUBLIC_MARKETING_ROUTE_NAMES = [
        'pricing',
        'templates',
        'about',
        'contact',
        'privacy',
        'terms',
        'refund',
        'marketing.custom',
    ];

    /** @var array{version: int, head: string, body: string, enabled: bool}|null */
    private static ?array $cache = null;

    /**
     * Resolve the scripts payload. Memoized per-process — Settings is
     * already memoized inside Settings::get, but this avoids re-running
     * the migrator chain on every call.
     *
     * @return array{version: int, head: string, body: string, enabled: bool}
     */
    public static function payload(): array
    {
        if (self::$cache !== null) {
            return self::$cache;
        }

        try {
            $stored = Settings::get('marketing.scripts');
            $doc = is_array($stored)
                ? MarketingMigrator::migrateScripts($stored)
                : MarketingDefaults::scripts();
        } catch (\Throwable) {
            $doc = MarketingDefaults::scripts();
        }

        $head = (string) ($doc['head'] ?? '');
        $body = (string) ($doc['body'] ?? '');

        return self::$cache = [
            'version' => (int) ($doc['version'] ?? MarketingMigrator::CURRENT_SCRIPTS_VERSION),
            'head' => $head,
            'body' => $body,
            'enabled' => trim($head) !== '' || trim($body) !== '',
        ];
    }

    /** Resets the per-process memo. Called after admin save so the next
     *  request inside the same worker reflects the new value. */
    public static function flush(): void
    {
        self::$cache = null;
    }

    /** True when the request targets one of the public marketing routes.
     *  Welcome (`/`) is unnamed so we match by path. Falls back to false
     *  for any unknown / unmatched route. */
    public static function isPublicMarketingRequest(Request $request): bool
    {
        if ($request->path() === '/' || $request->path() === '') {
            return true;
        }
        $route = $request->route();
        if ($route === null) {
            return false;
        }
        $name = $route->getName();
        if (! is_string($name)) {
            return false;
        }

        return in_array($name, self::PUBLIC_MARKETING_ROUTE_NAMES, true);
    }

    /** Convenience for CSP middleware + view composer. Returns 'permissive'
     *  only when both gates are true. */
    public static function cspProfile(Request $request): string
    {
        if (! self::payload()['enabled']) {
            return 'strict';
        }
        if (! self::isPublicMarketingRequest($request)) {
            return 'strict';
        }

        return 'permissive';
    }
}
