<?php

declare(strict_types=1);

namespace Drupal\flowdrop_ui_components\Render;

use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Extension\ExtensionPathResolver;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\Core\Render\BubbleableMetadata;
use Drupal\Core\Render\HtmlResponse;
use Drupal\Core\Render\Markup;
use Drupal\Core\Render\RenderContext;
use Drupal\Core\Render\RendererInterface;
use Drupal\Core\Template\Attribute;

/**
 * Renders a FlowDrop app as a bare, theme-free full-page document.
 *
 * The standard page pipeline renders inside the admin theme's `.page-wrapper`,
 * where admin-theme CSS bleeds into the Svelte app (e.g. Claro's
 * `body .page-wrapper :focus { outline: none }` resets, which strip FlowDrop's
 * focus rings). Delivering the app as its own document — with only the app's
 * own libraries attached and no `.page-wrapper` ancestor — gives it the same
 * clean CSS environment as the standalone library demo.
 *
 * @internal This class is not part of the public API and may change without notice.
 */
final class BarePageRenderer {

  /**
   * Minimal HTML document hosting an immersive FlowDrop app.
   *
   * Loads only the libraries bubbled by the rendered content, never the admin
   * theme. The placeholder tokens are replaced by
   * \Drupal\Core\Render\HtmlResponseAttachmentsProcessor.
   */
  private const HTML = <<<'HTML'
  <!DOCTYPE html>
  <html{{ html_attributes }}>
  <head>
    <head-placeholder token="HEAD-HERE-PLEASE">
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
    <link rel="icon" type="image/svg+xml" href="{{ favicon }}">
    <title>{{ title }}</title>
    <style>
      /* No admin theme/normalize is loaded here, so neutralize the UA body
         margin that would otherwise push the 100vh app down and produce a
         scrollbar. The app manages its own internal scrolling. */
      html, body { margin: 0; padding: 0; height: 100%; }
      body { overflow: hidden; }
    </style>
    <css-placeholder token="CSS-HERE-PLEASE">
    <js-placeholder token="JS-HERE-PLEASE">
  </head>
  <body{{ body_attributes }}>
    {{ content }}
    <js-bottom-placeholder token="JS-BOTTOM-HERE-PLEASE">
  </body>
  </html>
  HTML;

  public function __construct(
    private readonly RendererInterface $renderer,
    private readonly LanguageManagerInterface $languageManager,
    private readonly ConfigFactoryInterface $configFactory,
    private readonly ExtensionPathResolver $extensionPathResolver,
  ) {}

  /**
   * Wraps a render array in a bare, theme-free HTML page.
   *
   * @param array $content
   *   The app render array. Its bubbled libraries are carried onto the
   *   response so any auto-attached (e.g. SDC) JS/CSS still load.
   * @param string $title
   *   The page title (site name is appended automatically).
   *
   * @return \Drupal\Core\Render\HtmlResponse
   *   The standalone page.
   */
  public function render(array $content, string $title): HtmlResponse {
    // Render the content, capturing the assets and cache metadata it bubbles
    // (including any SDC component's auto-generated JS/CSS library).
    $context = new RenderContext();
    $markup = (string) $this->renderer->executeInRenderContext(
      $context,
      fn () => $this->renderer->render($content),
    );
    $bubbleable = $context->isEmpty()
      ? new BubbleableMetadata()
      : $context->pop();

    $language = $this->languageManager->getCurrentLanguage();
    $site_name = $this->configFactory->get('system.site')->get('name');
    $favicon = base_path()
      . $this->extensionPathResolver->getPath('module', 'flowdrop_ui_components')
      . '/assets/flowdrop-logo.svg';

    $page = [
      '#type' => 'inline_template',
      '#template' => self::HTML,
      '#context' => [
        'html_attributes' => new Attribute([
          'lang' => $language->getId(),
          'dir' => $language->getDirection(),
        ]),
        'body_attributes' => new Attribute([
          'class' => ['fd-fullscreen-page'],
        ]),
        'title' => $site_name ? "$title | $site_name" : $title,
        'favicon' => $favicon,
        'content' => Markup::create($markup),
      ],
    ];

    $response = new HtmlResponse((string) $this->renderer->renderInIsolation($page));

    // Carry the app's libraries onto the response. The placeholder tokens are
    // replaced by the HtmlResponse attachments processor.
    $attachments = $bubbleable->getAttachments();
    $attachments['html_response_attachment_placeholders'] = [
      'head' => '<head-placeholder token="HEAD-HERE-PLEASE">',
      'styles' => '<css-placeholder token="CSS-HERE-PLEASE">',
      'scripts' => '<js-placeholder token="JS-HERE-PLEASE">',
      'scripts_bottom' => '<js-bottom-placeholder token="JS-BOTTOM-HERE-PLEASE">',
    ];
    $response->setAttachments($attachments);
    $response->addCacheableDependency($bubbleable);
    $response->addCacheableDependency($this->configFactory->get('system.site'));

    return $response;
  }

}
