<?php

declare(strict_types=1);

namespace Drupal\simple_interactive_maps\Controller;

use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\ReplaceCommand;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Render\RendererInterface;
use Drupal\simple_interactive_maps\InteractiveMapInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\HttpException;

/**
 * Returns responses for Simple Interactive Maps routes.
 */
final class AjaxMapLoaderController extends ControllerBase {

  /**
   * The controller constructor.
   */
  public function __construct(
    private RendererInterface $renderer,
  ) {}

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container): self {
    return new self(
      $container->get('renderer'),
    );
  }

  /**
   * Builds the response.
   */
  public function __invoke(Request $request): AjaxResponse {

    // Load the interactive_map from the POST parameter map_to_load.
    $map_id = $request->request->get('map_to_load');
    $target_element = $request->request->get('target_element');

    $interactive_map = $this->entityTypeManager()->getStorage('interactive_map')->load($map_id);

    if (!($interactive_map instanceof InteractiveMapInterface)) {
      throw new HttpException(404, 'Interactive map not found.');
    }

    $build['map'] = [
      '#theme' => 'interactive_map',
      '#map' => $interactive_map,
    ];

    $rendered_map = $this->renderer->renderInIsolation($build);

    $response = new AjaxResponse();
    $ajax_command = new ReplaceCommand('#' . $target_element, (string) $rendered_map);
    $response->addCommand($ajax_command);

    // renderInIsolation() populates $build['#attached'] with the map's
    // libraries and drupalSettings (needed for tooltips/region actions to
    // work on the newly-loaded map), but - unlike a normal render() call
    // inside an active render context - never bubbles them anywhere on its
    // own, since that's the whole point of rendering "in isolation". They
    // have to be attached to the AjaxResponse explicitly or they're lost.
    if (!empty($build['#attached'])) {
      $response->setAttachments($build['#attached']);
    }

    return $response;
  }

}
