<?php

declare(strict_types=1);

namespace App\Modules\Theme;

/**
 * ThemeService -- Coordinates Registry, Loader, and Renderer.
 *
 * This is the single public entry point for the Theme Engine.
 * Controllers interact only with ThemeService -- never with
 * Registry, Loader, or Renderer directly.
 *
 * Responsibilities:
 *   - Expose getAvailableThemes() via the registry.
 *   - Resolve a theme code via the loader (with fallback).
 *   - Delegate rendering to the renderer.
 *
 * No HTML. No SQL.
 *
 * @package Inveetaire
 * @ref     RC-009
 */
class ThemeService
{
    private ThemeRegistry $registry;
    private ThemeLoader   $loader;
    private ThemeRenderer $renderer;

    public function __construct()
    {
        $this->registry = new ThemeRegistry();
        $this->loader   = new ThemeLoader();
        $this->renderer = new ThemeRenderer();
    }

    /**
     * Return all available themes discovered on disk.
     *
     * @return array<string, array> Map of theme_code => manifest.
     */
    public function getAvailableThemes(): array
    {
        return $this->registry->getAvailableThemes();
    }

    /**
     * Resolve a theme by code. Falls back to theme-001 automatically.
     *
     * @param string $themeCode
     * @return array Resolved theme data (manifest, path, entry).
     */
    public function resolve(string $themeCode): array
    {
        return $this->loader->load($themeCode);
    }

    /**
     * Render the invitation using the appropriate theme.
     *
     * Resolves theme_code from the workspace data,
     * loads the correct theme with fallback, and renders it.
     *
     * The $payload must contain:
     *   - workspace  : array
     *   - guest      : array
     *   - invitation : array
     *   - events     : array
     *   - sections   : array
     *   - theme      : array (DB theme row)
     *   - url        : string
     *   - qr_code    : string
     *   - rsvp       : array|null
     *   - wish       : array|null
     *
     * theme_code is read from $payload['workspace']['theme_code']
     * with a fallback to ThemeLoader::FALLBACK_THEME.
     *
     * @param array $payload Full invitation render payload from the controller.
     * @return void
     */
    public function renderInvitation(array $payload): void
    {
        // Determine which theme file set to use
        $themeCode = (string) ($payload['workspace']['theme_code'] ?? ThemeLoader::FALLBACK_THEME);
        if ($themeCode === '') {
            $themeCode = ThemeLoader::FALLBACK_THEME;
        }

        // Load theme (includes automatic fallback)
        $resolved = $this->loader->load($themeCode);

        // Merge resolved theme manifest into payload so theme entry can use it
        $payload['themeManifest'] = $resolved['manifest'];

        // Delegate rendering -- controller never touches paths
        $this->renderer->render($resolved['entry'], $payload);
    }
}