<?php

declare(strict_types=1);

namespace Drupal\simple_interactive_maps\Form;

use Drupal\Component\Plugin\Exception\PluginNotFoundException;
use Drupal\Core\Entity\EntityForm;
use Drupal\Core\Form\FormStateInterface;
use Drupal\simple_interactive_maps\Entity\InteractiveMap;
use Drupal\simple_interactive_maps\MapDataLoader;
use Drupal\simple_interactive_maps\MapDefinitionPluginManager;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpKernel\Exception\HttpException;

/**
 * Interactive Map form.
 */
final class InteractiveMapForm extends EntityForm {

  /**
   * Form Constructor.
   *
   * @param \Drupal\simple_interactive_maps\MapDataLoader $mapDataLoader
   *   Data loader service.
   * @param \Drupal\simple_interactive_maps\MapDefinitionPluginManager $mapPluginManager
   *   Map plugin manager.
   *
   * @todo see if this is needed or needs to be replaced with entity storage.
   */
  public function __construct(protected MapDataLoader $mapDataLoader, protected MapDefinitionPluginManager $mapPluginManager) {}

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container): InteractiveMapForm {
    /** @var \Drupal\simple_interactive_maps\MapDataLoader $mapDataLoader */
    $mapDataLoader = $container->get('simple_interactive_maps.map_data_loader');

    /** @var \Drupal\simple_interactive_maps\MapDefinitionPluginManager $mapPluginManager */
    $mapPluginManager = $container->get('plugin.manager.map_definition');

    return new InteractiveMapForm($mapDataLoader, $mapPluginManager);
  }

  /**
   * {@inheritdoc}
   */
  public function form(array $form, FormStateInterface $form_state): array {
    $config = $this->config('simple_interactive_maps.settings');

    $form = parent::form($form, $form_state);

    assert($this->entity instanceof InteractiveMap);

    $form['label'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Label'),
      '#maxlength' => 255,
      '#default_value' => $this->entity->label(),
      '#required' => TRUE,
    ];

    $form['id'] = [
      '#type' => 'machine_name',
      '#default_value' => $this->entity->id(),
      '#machine_name' => [
        'exists' => [InteractiveMap::class, 'load'],
      ],
      '#disabled' => !$this->entity->isNew(),
    ];

    $map_plugins = [];

    $definitions = $this->mapPluginManager->getDefinitions();

    array_walk($definitions, function (&$definition) {
      if (!array_key_exists('map_category', $definition)) {
        $definition['map_category'] = '';
      }
    });

    // Sort the definitions by map_category and then label.
    uasort($definitions, function ($a, $b) {
      if ($a['map_category'] === $b['map_category']) {
        return $a['label'] <=> $b['label'];
      }
      return $a['map_category'] <=> $b['map_category'];
    });

    foreach ($definitions as $mapDefinition) {
      if ($mapDefinition['map_category'] !== '') {
        $map_plugins[$mapDefinition['map_category']][$mapDefinition['id']] = $mapDefinition['label'];
      }
      else {
        $map_plugins[$mapDefinition['id']] = $mapDefinition['label'];
      }
    }

    $form['base_map'] = [
      '#type' => 'select',
      '#title' => $this->t('Base Map'),
      '#options' => $map_plugins,
      '#default_value' => $this->entity->get('base_map') ?? '',
      '#required' => TRUE,
      '#disabled' => $this->entity->isNew() === FALSE,
    ];

    // Generate a rich text editor for the description field.
    $form['description'] = [
      '#type' => 'text_format',
      '#title' => $this->t('Description'),
      '#default_value' => $this->entity->get('description')['value'] ?? '',
      '#format' => $this->entity->get('description')['format'] ?? 'full_html',
    ];

    $disableColors = $this->entity->isNew() === FALSE;
    // Map default fill color.
    $form['fill_color'] = [
      '#type' => 'color',
      '#title' => $this->t('Fill Color'),
      '#default_value' => $this->entity->get('fill_color') ?? $config->get('default_fill_color') ?? '#4ba0a6',
      '#description' => $this->t('The default fill color for the map.'),
      '#access' => !$disableColors,
    ];

    $form['hover_color'] = [
      '#type' => 'color',
      '#title' => $this->t('Hover Color'),
      '#default_value' => $this->entity->get('hover_color') ?? $config->get('default_hover_color') ?? '#076369',
      '#description' => $this->t('The color of the map when hovered over.'),
      '#access' => !$disableColors,
    ];

    // Map default stroke color.
    $form['stroke_color'] = [
      '#type' => 'color',
      '#title' => $this->t('Stroke Color'),
      '#default_value' => $this->entity->get('stroke_color') ?? $config->get('default_stroke_color') ?? '#e6e6e6',
      '#description' => $this->t('The default stroke color for the map.'),
      '#access' => !$disableColors,
    ];

    $form['text_color'] = [
      '#type' => 'color',
      '#title' => $this->t('Text Color'),
      '#default_value' => $this->entity->get('text_color') ?? $config->get('default_text_color') ?? '#000000',
      '#description' => $this->t('The default text color for the map.'),
      '#access' => !$disableColors,
    ];

    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function save(array $form, FormStateInterface $form_state): int {
    assert($this->entity instanceof InteractiveMap);

    if ($this->entity->isNew()) {
      try {
        $mapPlugin = $this->mapPluginManager->createInstance($form_state->getValue('base_map'));
        $regionData = $mapPlugin->mapData();
      }
      catch (\JsonException | PluginNotFoundException $e) {
        throw new HttpException(500, 'Failed to load map data.');
      }

      $config = $this->config('simple_interactive_maps.settings');

      $regions = [];

      foreach ($regionData as $key => $value) {
        $tooltip = $config->get('default_region_tooltip') ?? [
          'value' => '',
          'format' => 'full_html',
        ];

        // If the map plugin uses the default tooltip, then we need to
        // replace the @label token with the actual label.
        $pluginDefinition = $mapPlugin->getPluginDefinition();
        if ($pluginDefinition['uses_default_tooltip'] ?? FALSE) {
          $tooltipTemplate = $pluginDefinition['default_tooltip'];

          if (str_contains($tooltipTemplate, '@label')) {
            $tooltip['value'] = str_replace('@label', $value['label'], $tooltipTemplate);
          }
          else {
            $tooltip['value'] = $tooltipTemplate;
          }
        }

        $regions[$key] = [
          'id' => $key,
          'label' => $value['label'],
          'tooltip' => $tooltip,
          'hidden' => 0,
          'fill_color' => $form_state->getValue('fill_color') ?? $config->get('default_fill_color') ?? '#4ba0a6',
          'hover_color' => $form_state->getValue('hover_color') ?? $config->get('default_hover_color') ?? '#076369',
          'stroke_color' => $form_state->getValue('stroke_color') ?? $config->get('default_stroke_color') ?? '#e6e6e6',
          'text_color' => $form_state->getValue('text_color') ?? $config->get('default_text_color') ?? '#000000',
          'action' => [
            'plugin_id' => 'none',
            'plugin_configuration' => [],
          ],
          'group' => '',
        ];
        $this->entity->set($key, $value);
      }
      $this->entity->set('groups', []);
      $this->entity->set('regions', $regions);
    }
    $result = parent::save($form, $form_state);
    $message_args = ['%label' => $this->entity->label()];
    $this->messenger()->addStatus(
      match ($result) {
        \SAVED_NEW => $this->t('Created new example %label.', $message_args),
        default => $this->t('Updated example %label.', $message_args),
      }
    );
    $form_state->setRedirectUrl($this->entity->toUrl('collection'));
    return $result;
  }

}
