<?php

declare(strict_types=1);

namespace Drupal\simple_interactive_maps\Form;

use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Form\SubformState;
use Drupal\simple_interactive_maps\InteractiveMapInterface;
use Drupal\simple_interactive_maps\MapActionPluginManager;
use Psr\Container\ContainerInterface;
use Symfony\Component\HttpKernel\Exception\HttpException;

/**
 * Provides a Simple Interactive Maps form.
 */
final class GroupAddForm extends FormBase {

  /**
   * Form Constructor.
   *
   * @param \Drupal\simple_interactive_maps\MapActionPluginManager $actionPluginManager
   *   The map action plugin manager.
   */
  public function __construct(protected MapActionPluginManager $actionPluginManager) {}

  /**
   * {@inheritDoc}
   */
  public static function create(ContainerInterface $container): GroupAddForm {
    /** @var \Drupal\simple_interactive_maps\MapActionPluginManager $mapActionPluginManager */
    $mapActionPluginManager = $container->get('plugin.manager.map_action');

    return new GroupAddForm($mapActionPluginManager);
  }

  /**
   * {@inheritdoc}
   */
  public function getFormId(): string {
    return 'simple_interactive_maps_group_add';
  }

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state, ?InteractiveMapInterface $interactive_map = NULL, ?string $group = NULL): array {
    if (!($interactive_map instanceof InteractiveMapInterface)) {
      throw new HttpException(404, 'Interactive map not found.');
    }

    $form['map'] = [
      '#type' => 'value',
      '#value' => $interactive_map,
    ];

    $groupId = $group;

    if ($group !== NULL) {
      $groups = $interactive_map->get('groups');
      if (!isset($groups[$group])) {
        throw new HttpException(404, 'Group not found.');
      }
      $form['group'] = [
        '#type' => 'value',
        '#value' => $group,
      ];
      $group = $groups[$group];
    }

    $form['label'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Name'),
      '#required' => TRUE,
      '#default_value' => $group ? $group['label'] : '',
    ];

    // Create a machine name derived from the name field.
    $form['machine_name'] = [
      '#type' => 'machine_name',
      '#title' => $this->t('Machine name'),
      '#required' => TRUE,
      '#default_value' => $groupId ?: '',
      '#machine_name' => [
        'source' => ['label'],
        'exists' => [$this, 'groupExists'],
      ],
      '#element_validate' => [
        [$this, 'validateMachineNameFormat'],
      ],
    ];

    $form['tabs'] = [
      '#type' => 'horizontal_tabs',
      '#default_tab' => 'edit-group',
    ];

    $form['tabs']['colors'] = [
      '#type' => 'details',
      '#title' => $this->t('Colors'),
      '#group' => 'tabs',
      '#attributes' => ['class' => ['edit-group']],
    ];

    $form['tabs']['colors']['override_colors'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Override colors'),
      '#default_value' => $group ? $group['override_colors'] : FALSE,
    ];

    $form['tabs']['colors']['fill_color'] = [
      '#type' => 'color',
      '#title' => $this->t('Fill color'),
      '#default_value' => $group ? $group['fill_color'] : $interactive_map->get('fill_color'),
      '#states' => [
        'visible' => [
          ':input[name="override_colors"]' => ['checked' => TRUE],
        ],
      ],
    ];

    $form['tabs']['colors']['hover_color'] = [
      '#type' => 'color',
      '#title' => $this->t('Hover color'),
      '#default_value' => $group ? $group['hover_color'] : $interactive_map->get('hover_color'),
      '#states' => [
        'visible' => [
          ':input[name="override_colors"]' => ['checked' => TRUE],
        ],
      ],
    ];

    $form['tabs']['colors']['stroke_color'] = [
      '#type' => 'color',
      '#title' => $this->t('Stroke color'),
      '#default_value' => $group ? $group['stroke_color'] : $interactive_map->get('stroke_color'),
      '#states' => [
        'visible' => [
          ':input[name="override_colors"]' => ['checked' => TRUE],
        ],
      ],
    ];

    $form['tabs']['colors']['text_color'] = [
      '#type' => 'color',
      '#title' => $this->t('Text color'),
      '#default_value' => $group ? $group['text_color'] : $interactive_map->get('text_color'),
      '#states' => [
        'visible' => [
          ':input[name="override_colors"]' => ['checked' => TRUE],
        ],
      ],
    ];

    $form['tabs']['tooltip'] = [
      '#type' => 'details',
      '#title' => $this->t('Tooltip'),
      '#group' => 'tabs',
      '#attributes' => ['class' => ['edit-group']],
    ];

    $form['tabs']['tooltip']['override_tooltip'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Override tooltip'),
      '#default_value' => $group ? $group['override_tooltip'] : FALSE,
    ];

    $form['tabs']['tooltip']['tooltip'] = [
      '#type' => 'text_format',
      '#title' => $this->t('Tooltip'),
      '#default_value' => $group ? $group['tooltip']['value'] : '',
      '#format' => $group ? $group['tooltip']['format'] : 'full_html',
      '#states' => [
        'visible' => [
          ':input[name="override_tooltip"]' => ['checked' => TRUE],
        ],
      ],
    ];

    $form['tabs']['actions'] = [
      '#type' => 'details',
      '#title' => $this->t('Actions'),
      '#group' => 'tabs',
      '#attributes' => ['class' => ['edit-group']],
    ];

    $form['tabs']['actions']['override_action'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Override action'),
      '#default_value' => $group ? $group['override_action'] : FALSE,
    ];

    $actions = $this->actionPluginManager->getDefinitions();
    $options = [];
    foreach ($actions as $action) {
      $options[$action['id']] = $action['label'];
    }

    $form['tabs']['actions']['plugin_id'] = [
      '#type' => 'select',
      '#title' => $this->t('Action'),
      '#options' => $options,
      '#default_value' => $group['action']['plugin_id'] ?? 'none',
      '#states' => [
        'visible' => [
          ':input[name="override_action"]' => ['checked' => TRUE],
        ],
      ],
      '#ajax' => [
        'callback' => [$this, 'getActionForm'],
        'event' => 'change',
        'wrapper' => 'edit-plugin-configuration',
      ],
    ];

    $selectedAction = $form_state->getValue('plugin_id') ?? $group['action']['plugin_id'] ?? 'none';
    $action = $this->actionPluginManager->createInstance($selectedAction, $group['action']['plugin_configuration'] ?? []);

    $form['tabs']['actions']['plugin_configuration'] = [];
    $subformState = SubformState::createForSubform($form['tabs']['actions']['plugin_configuration'], $form, $form_state);
    $form['tabs']['actions']['plugin_configuration'] = $action->buildConfigurationForm($form['tabs']['actions']['plugin_configuration'], $subformState);
    $form['tabs']['actions']['plugin_configuration']['#type'] = 'container';
    $form['tabs']['actions']['plugin_configuration']['#attributes'] = [
      'id' => 'edit-plugin-configuration',
    ];
    $form['tabs']['actions']['plugin_configuration']['#tree'] = TRUE;

    $form['actions'] = [
      '#type' => 'actions',
      'submit' => [
        '#type' => 'submit',
        '#value' => $this->t('Save'),
      ],
    ];

    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function validateForm(array &$form, FormStateInterface $form_state): void {
    $action = $this->actionPluginManager->createInstance($form_state->getValue('plugin_id'));
    $subformState = SubformState::createForSubform($form['tabs']['actions']['plugin_configuration'], $form, $form_state);
    $action->validateConfigurationForm($form['tabs']['actions']['plugin_configuration'], $subformState);
  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state): void {
    $map = $form_state->getValue('map');
    if ($map instanceof InteractiveMapInterface) {
      $groups = $map->getGroups();

      $group = [
        'label' => $form_state->getValue('label'),
        'override_colors' => $form_state->getValue('override_colors'),
        'fill_color' => $form_state->getValue('fill_color'),
        'hover_color' => $form_state->getValue('hover_color'),
        'stroke_color' => $form_state->getValue('stroke_color'),
        'text_color' => $form_state->getValue('text_color'),
        'override_tooltip' => $form_state->getValue('override_tooltip'),
        'tooltip' => $form_state->getValue('tooltip'),
        'override_action' => $form_state->getValue('override_action'),
        'action' => [
          'plugin_id' => $form_state->getValue('plugin_id'),
          'plugin_configuration' => $form_state->getValue('plugin_configuration'),
        ],
      ];

      $groups[$form_state->getValue('machine_name')] = $group;

      $map->setGroups($groups);
      $map->save();
    }
  }

  /**
   * Ajax callback to load the action config form.
   *
   * @param array $form
   *   Form structure.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   Form state.
   *
   * @return array
   *   The action form.S
   */
  public function getActionForm(array &$form, FormStateInterface $form_state): array {
    $plugin_configuration = $form['tabs']['actions']['plugin_configuration'];
    return $plugin_configuration;
  }

  /**
   * Validates the machine name format.
   *
   * @param array $element
   *   The form element.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The form state.
   * @param array $form
   *   The complete form structure.
   */
  public function validateMachineNameFormat(array &$element, FormStateInterface $form_state, array $form) {
    $machine_name = $form_state->getValue('machine_name');
    $machine_name = strtolower($machine_name);
    $machine_name = str_replace(' ', '_', $machine_name);
    $machine_name = preg_replace('/[^a-z0-9_]/', '', $machine_name);
    $form_state->setValue('machine_name', $machine_name);
  }

}
