<?php

declare(strict_types=1);

namespace App\Controller;

use App\Entity\User;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\DependencyInjection\Attribute\Autowire;
use Symfony\Component\HttpFoundation\Cookie;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;

#[IsGranted('ROLE_USER')]
class SpaController extends AbstractController
{
    public function __construct(
        #[Autowire('%kernel.project_dir%/public/build')]
        private readonly string $buildDir,
        #[Autowire('%env(default::MERCURE_PUBLIC_URL)%')]
        private readonly string $mercurePublicUrl = '',
    ) {}

    #[Route(
        '/{path}',
        name: 'spa',
        requirements: ['path' => '^(?!api|setup|token|help|login|register|logout|_profiler|_wdt).*'],
        defaults: ['path' => ''],
    )]
    public function index(): Response
    {
        $indexFile = $this->buildDir . '/index.html';

        if (!file_exists($indexFile)) {
            throw $this->createNotFoundException('SPA not built — run npm run build in frontend/.');
        }

        /** @var User $user */
        $user          = $this->getUser();
        $theme         = $user->getTheme() ?? 'warm-craft';
        $designVersion = $user->getDesignVersion();  // 'v1' or 'v2'; defaults to 'v1'

        $userData = json_encode([
            'id'            => $user->getId(),
            'email'         => $user->getEmail(),
            'roles'         => $user->getRoles(),
            'theme'         => $theme,
            'designVersion' => $designVersion,
            'timezone'      => $user->getTimezone(),
        ], JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT);

        $html = (string) file_get_contents($indexFile);

        // Inject theme + design version on <html> so CSS applies before JS hydrates (no FOUC)
        $html = str_replace(
            '<html lang="en">',
            '<html lang="en" data-theme="' . htmlspecialchars($theme, ENT_QUOTES)
                . '" data-design="' . htmlspecialchars($designVersion, ENT_QUOTES) . '">',
            $html,
        );

        // Bootstrap current user into window so Pinia auth store needs no initial API call.
        // Also expose the Mercure public URL so the live-updates composable can subscribe
        // without needing its own /api/config round trip.
        $mercureJson = json_encode($this->mercurePublicUrl, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT);
        $html = str_replace(
            '</head>',
            '<script>window.__PF_USER__=' . $userData . ';window.__PF_MERCURE_URL__=' . $mercureJson . ';</script></head>',
            $html,
        );

        $response = new Response($html, headers: ['Content-Type' => 'text/html; charset=utf-8']);
        // Refresh the design cookie on every SPA load so Twig pages (login,
        // setup, help) reflect the current server-side preference even after
        // a login on a new browser.
        $response->headers->setCookie(Cookie::create('wevisto_design', $designVersion)
            ->withPath('/')
            ->withExpires(new \DateTimeImmutable('+1 year'))
            ->withHttpOnly(false)
            ->withSameSite('Lax'));
        return $response;
    }
}
