<?php

namespace Drupal\castorcito\Plugin\Field\FieldWidget;

use Drupal\castorcito\CastorcitoManager;
use Drupal\Core\Entity\EntityDisplayRepositoryInterface;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\WidgetBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Url;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Plugin implementation of the 'castorcito_component_widget' widget.
 *
 * @FieldWidget(
 *   id = "castorcito_component_widget",
 *   module = "castorcito",
 *   label = @Translation("Castorcito component"),
 *   description = @Translation("Define all components."),
 *   field_types = {
 *     "json",
 *     "json_native",
 *     "json_native_binary"
 *   },
 * )
 */
class CastorcitoComponentWidget extends WidgetBase {

  /**
   * The entity display repository.
   *
   * @var \Drupal\Core\Entity\EntityDisplayRepositoryInterface
   */
  protected $entityDisplayRepository;

  /**
   * The castorcito manager.
   *
   * @var Drupal\castorcito\CastorcitoManager
   */
  protected $castorcitoManager;

  /**
   * Constructs an CastorcitoComponentWidget instance.
   *
   * @param string $plugin_id
   *   The plugin ID for the widget.
   * @param mixed $plugin_definition
   *   The plugin implementation definition.
   * @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
   *   The definition of the field to which the widget is associated.
   * @param array $settings
   *   The widget settings.
   * @param array $third_party_settings
   *   Any third party settings.
   * @param \Drupal\Core\Entity\EntityDisplayRepositoryInterface $entity_display_repository
   *   The entity display repository.
   * @param \Drupal\castorcito\CastorcitoManager $castorcito_manager
   *   Castorcito manager service.
   */
  public function __construct(
    $plugin_id,
    $plugin_definition,
    FieldDefinitionInterface $field_definition,
    array $settings,
    array $third_party_settings,
    EntityDisplayRepositoryInterface $entity_display_repository,
    CastorcitoManager $castorcito_manager,
  ) {
    parent::__construct($plugin_id, $plugin_definition, $field_definition, $settings, $third_party_settings);
    $this->entityDisplayRepository = $entity_display_repository;
    $this->castorcitoManager = $castorcito_manager;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    return new static(
      $plugin_id,
      $plugin_definition,
      $configuration['field_definition'],
      $configuration['settings'],
      $configuration['third_party_settings'],
      $container->get('entity_display.repository'),
      $container->get('castorcito.manager')
    );
  }

  /**
   * {@inheritdoc}
   */
  public static function defaultSettings() {
    return [
      'components' => [],
      'components_settings' => [],
    ] + parent::defaultSettings();
  }

  /**
   * {@inheritdoc}
   */
  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
    if (!isset($form['#is_castorcito'])) {
      $form['#is_castorcito'] = 'field--widget-castorcito-component-widget';
    }

    $element['value'] = $element + [
      '#type' => 'textarea',
      '#default_value' => $items[$delta]->value,
      '#attributes' => [
        'target-weight' => $delta,
      ],
    ];

    return $element;
  }

  /**
   * {@inheritdoc}
   */
  public function settingsForm(array $form, FormStateInterface $form_state) {
    $allowed_components = array_filter($this->getSetting('components'));
    $components = $this->castorcitoManager->castorcitoComponentsOptions();
    $missing_components = array_diff_key($allowed_components, $components);

    if (!empty($missing_components)) {
      $element['missing_components'] = [
        '#markup' => '<div class="messages messages--warning"><h2 class="visually-hidden">Warning message</h2>' . $this->t('Warning: Some selected components are missing. Saving may cause data loss or errors. Proceed only if you’re certain.') . '</div>',
      ];
    }

    $element['components'] = [
      '#type' => 'checkboxes',
      '#title' => $this->t('Components list'),
      '#options' => $components,
      '#default_value' => $allowed_components,
      '#required' => TRUE,
      '#multiple' => TRUE,
    ];

    $route_params = [
      'entity_type' => $this->fieldDefinition->get('entity_type'),
      'bundle' => $this->fieldDefinition->get('bundle'),
      'field_name' => $this->fieldDefinition->getName(),
    ];

    $element['components_settings_fieldset'] = [
      '#type' => 'fieldset',
      '#title' => $this->t('Override configuration'),
    ];

    $element['components_settings_fieldset']['help_text'] = [
      '#markup' => $this->t('<p>To override the default configurations from a component, first select the component and press the corresponding button.<br>
      In the configuration page override the desired options. Then return to the widget configuration, clic on <strong>Update</strong> button from widget settings. Finally <strong>Save</strong> the Manage Form Display.</p>'),
    ];

    foreach ($components as $c_key => $component_label) {
      $route_params['component_id'] = $c_key;
      $element['components_settings_fieldset'][$c_key] = [
        '#type' => 'link',
        '#title' => $component_label,
        '#url' => Url::fromRoute('castorcito.list_override_component_config')->setRouteParameters($route_params),
        '#attributes' => [
          'class' => ['button'],
          'target' => '_blank'
        ],
        '#states' => [
          'visible' => [
            ':input[value="' . $c_key . '"]' => ['checked' => TRUE],
          ],
        ]
      ];
    }

    $element['components_settings'] = [
      '#type' => 'hidden',
      '#default_value' => '',
      '#element_validate' => [
        [$this, 'validateComponentsSettings'],
      ],
    ];

    return $element;
  }

  /**
   * {@inheritdoc}
   */
  public function settingsSummary() {
    $components = array_filter($this->getSetting('components'));

    if (!empty($components)) {
      $components_options = $this->castorcitoManager->castorcitoComponentsOptions();
      $missing_components = array_diff_key($components, $components_options);

      if (!empty($missing_components)) {
        \Drupal::messenger()->addError($this->t('Some components are missing: @components', [
          '@components' => implode(', ', array_keys($missing_components)),
        ]));
      }

      $items = [];
      foreach ($components as $component) {
        if(!isset($components_options[$component])) {
          $items[] = $component . $this->t('(Missing)');
        }
        else {
          $items[] = $components_options[$component];
        }
      }

      $summary[] = $this->t('<strong>Allowed components</strong>');
      $summary[] = [
        '#theme' => 'item_list',
        '#list_type' => 'ul',
        '#items' => $items,
      ];
    }
    else {
      $summary[] = $this->t('You don\'t have any selected components for this field.');
      $summary[] = $this->t('Choose the components you want to use.');
    }

    return $summary;
  }

  /**
   * Validation callback for a components_settings element.
   *
   * @param array $element
   *   The form element whose value is being validated.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The current state of the form.
   * @param array $complete_form
   *   The complete form structure.
   */
  public function validateComponentsSettings(&$element, FormStateInterface $form_state, &$complete_form) {
    // We avoid using $this->getSetting('components_settings') because it may return
    // a stale cached value if the configuration was recently updated from another route,
    // such as 'castorcito.list_override_component_config'.
    // Instead, we fetch the latest configuration directly from the EntityFormDisplay storage
    // to ensure the most up-to-date settings are used.
    $entity_type = $this->fieldDefinition->get('entity_type');
    $bundle = $this->fieldDefinition->get('bundle');
    $form_display = $this->entityDisplayRepository->getFormDisplay($entity_type, $bundle);
    $form_display_component = $form_display->getComponent($this->fieldDefinition->getName());
    $components_settings = $form_display_component['settings']['components_settings'] ?? [];

    // Get the user-submitted components data from the form state.
    $components_parents = $element['#parents'];
    $components_parents[array_key_last($components_parents)] = 'components';
    $components = array_filter($form_state->getValue($components_parents));

    // Filter only those component settings that match selected components.
    $new_element_value = array_intersect_key($components_settings, $components);

    // Set the filtered value to the element.
    $form_state->setValueForElement($element, $new_element_value);
  }

}
