<?php

namespace Drupal\castorcito\Form;

use Drupal\castorcito\CastorcitoComponentInterface;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;

/**
 * Provides a base form for castorcito component field.
 */
class CastorcitoComponentDisplaySettingsForm extends FormBase {

  /**
   * The Component.
   *
   * @var \Drupal\castorcito\CastorcitoComponentInterface
   */
  protected $component;

  /**
   * The field name settings.
   *
   */
  protected $fieldName;

  /**
   * {@inheritdoc}
   */
  public function getFormId() {
    return 'castorcito_component_field_settings_form';
  }

  /**
   * {@inheritdoc}
   *
   * @param array $form
   *   A nested array form elements comprising the form.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The current state of the form.
   * @param \Drupal\castorcito\CastorcitoComponentInterface|null $castorcito_component
   *   The Castorcito component, or NULL if not provided.
   *
   * @return array
   *   The form structure.
   *
   * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
   */
  public function buildForm(array $form, FormStateInterface $form_state, ?CastorcitoComponentInterface $castorcito_component = NULL, $field_name = NULL) {
    $this->component = $castorcito_component;
    $this->fieldName = $field_name;
    $settings = [];
    $items_count = 0;

    if (!empty($this->fieldName) && !empty($this->component->get('display_settings')[$this->fieldName])) {
      $settings = $this->component->get('display_settings')[$this->fieldName];

      if (isset($settings['options'])) {
        $items_count = max(count($settings['options']), 0) - 1;
      }
    }

    $form['ds_label'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Label'),
      '#default_value' => $settings['label'] ?? '',
      '#required' => TRUE,
    ];

    $form['ds_id'] = [
      '#type' => 'machine_name',
      '#machine_name' => [
        'exists' => [
          $this,
          'hasSetting',
        ],
        'source' => [
          'ds_label',
        ],
      ],
      '#default_value' => $this->fieldName ?? '',
      '#disabled' => $this->fieldName,
      '#required' => TRUE,
    ];

    $form['ds_field_type'] = [
      '#type' => 'select',
      '#title' => $this->t('Field type'),
      '#options' => [
        'textfield' => $this->t('Text field'),
        'checkbox' => $this->t('Checkbox'),
        'select' => $this->t('Select'),
      ],
      '#empty_option' => $this->t('- Select -'),
      '#default_value' => $settings['type'] ?? '',
      '#disabled' => $this->fieldName,
      '#required' => TRUE,
    ];

    $form['ds_description'] = [
      '#type' => 'textarea',
      '#title' => $this->t('Description'),
      '#default_value' => $settings['description'] ?? '',
      '#rows' => 5,
      '#description' => $this->t('Instructions to present to the user below this field on the editing'),
    ];

    $form['ds_required'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Required field'),
      '#default_value' => $settings['required'] ?? FALSE,
    ];

    if (!$form_state->get('items_count')) {
      $form_state->set('items_count', $items_count);
    }

    if (!$form_state->get('removed_item')) {
      $form_state->set('removed_item', []);
    }

    $form['#tree'] = TRUE;
    $form['ds_select_fieldset'] = [
      '#type' => 'details',
      '#title' => $this->t('Add options'),
      '#prefix' => '<div id="names-fieldset-wrapper">',
      '#suffix' => '</div>',
      '#open' => TRUE,
      '#states' => [
        'visible' => [
          ':input[name="ds_field_type"]' => ['value' => 'select'],
        ],
      ],
    ];

    $form['ds_select_fieldset']['table'] = [
      '#type' => 'table',
      '#header' => [
        $this->t('Allowed values'),
        $this->t('Delete'),
        $this->t('Weight'),
      ],
      '#attributes' => [
        'id' => 'allowed-values-order',
        'data-field-list-table' => TRUE,
        'class' => ['allowed-values-table'],
      ],
      '#tabledrag' => [
        [
          'action' => 'order',
          'relationship' => 'sibling',
          'group' => 'weight',
        ],
      ],
    ];

    $max = $form_state->get('items_count');
    $removed_item = $form_state->get('removed_item');
    for ($i = 0; $i <= $max; $i++) {
      if (!in_array($i, $removed_item)) {
        $form['ds_select_fieldset']['table'][$i] = [
          '#attributes' => [
            'class' => ['draggable'],
          ],
          '#weight' => $i,
        ];

        $form['ds_select_fieldset']['table'][$i]['item'] = [
          'label' => [
            '#type' => 'textfield',
            '#maxlength' => 255,
            '#title' => $this->t('Name'),
            '#default_value' => $settings['options'][$i]['label'] ?? '',
            '#weight' => -1,
          ],
          'key' => [
            '#type' => 'textfield',
            '#title' => $this->t('Value'),
            '#weight' => 0,
            '#default_value' => $settings['options'][$i]['key'] ?? '',
          ],
        ];

        $form['ds_select_fieldset']['table'][$i]['delete'] = [
          '#type' => 'submit',
          '#value' => $this->t('Remove'),
          '#name' => $i,
          '#submit' => [
            [$this, 'removeCallback'],
          ],
          '#limit_validation_errors' => [],
          '#ajax' => [
            'callback' => [$this, 'addmoreCallback'],
            'wrapper' => 'names-fieldset-wrapper',
            'effect' => 'fade',
          ],
        ];
        $form['ds_select_fieldset']['table'][$i]['weight'] = [
          '#type' => 'weight',
          '#title' => $this->t('Weight for row @number', ['@number' => $i + 1]),
          '#title_display' => 'invisible',
          '#delta' => 50,
          '#default_value' => $i,
          '#attributes' => ['class' => ['weight']],
        ];
      }
    }

    $form['ds_select_fieldset']['add_name'] = [
      '#type' => 'submit',
      '#value' => $this->t('Add one more'),
      '#submit' => [
       [$this, 'addMoreSubmit'],
      ],
      '#ajax' => [
        'callback' => [$this, 'addmoreCallback'],
        'wrapper' => 'names-fieldset-wrapper',
      ],
    ];

    if (!empty($this->getDisplaySettingsOptions())) {
      $form['ds_visibility_condition'] = [
        '#type' => 'details',
        '#title' => $this->t('Visibility conditional logic'),
        '#attributes' => ['class' => ['container-inline']]
      ];

      $form['ds_visibility_condition']['this_option'] = [
        '#markup' => $this->t('This option is'),
      ];

      $form['ds_visibility_condition']['state'] = [
        '#type' => 'select',
        '#title' => '',
        '#default_value' => $settings['visibility_condition']['state'] ?? '',
        '#options' => [
          'visible' => $this->t('Visible'),
          'invisible' => $this->t('Invisible'),
        ],
        '#empty_option' => $this->t('- Select -'),
        '#description' => '',
      ];

      $form['ds_visibility_condition']['if_option'] = [
        '#markup' => $this->t('if option'),
      ];

      $form['ds_visibility_condition']['conditional_option'] = [
        '#type' => 'select',
        '#title' => '',
        '#default_value' => $settings['visibility_condition']['conditional_option'] ?? '',
        '#options' => $this->getDisplaySettingsOptions(),
        '#empty_option' => $this->t('- Select -'),
        '#description' => '',
      ];

      $form['ds_visibility_condition']['is_has'] = [
        '#markup' => $this->t('is/has'),
      ];

      $form['ds_visibility_condition']['trigger'] = [
       '#type' => 'select',
        '#title' => '',
        '#default_value' => $settings['visibility_condition']['trigger'] ?? '',
        '#options' => [
          'checked' => $this->t('Checked'),
          'unchecked' => $this->t('Unchecked'),
          'value' => $this->t('Value equal than'),
          '!value' => $this->t('Value different than'),
        ],
        '#empty_option' => $this->t('- Select -'),
        '#description' => '',
      ];

      $form['ds_visibility_condition']['value'] = [
        '#type' => 'textfield',
        '#title' => '',
        '#default_value' => $settings['visibility_condition']['value'] ?? '',
        '#description' => '',
        '#placeholder' => $this->t('Enter value…'),
        '#states' => [
          'visible' => [
            ':input[name="ds_visibility_condition[trigger]"]' => [
              ['value' => 'value'],
              ['value' => '!value'],
            ]
          ],
        ],
      ];
    }

    $form['ds_default_value'] = [
      '#type' => 'hidden',
      '#value' => $settings['default_value'] ?? '',
    ];

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

    $form['actions']['cancel'] = [
      '#type' => 'link',
      '#title' => $this->t('Cancel'),
      '#url' => $this->component->toUrl('edit-form'),
      '#attributes' => ['class' => ['button']],
    ];

    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function validateForm(array &$form, FormStateInterface $form_state) {
    $s_field_type = $form_state->getValue('ds_field_type');

    // Check if it's a select field and if options are defined.
    if ($s_field_type === 'select') {
      $ds_select_fieldset = $form_state->getValue('ds_select_fieldset');
      $options = $ds_select_fieldset['table'] ?? [];

      // Check if at least one option has a non-empty key.
      $has_options = array_reduce($options, function ($carry, $value) {
        return $carry || !empty($value['item']['key']);
      }, FALSE);

      if (!$has_options) {
        $form_state->setErrorByName('ds_select_fieldset', $this->t('You must add options to the select field.'));
      }
    }

    $ds_visibility_condition = $form_state->getValue('ds_visibility_condition');
    if (!empty($ds_visibility_condition) && !empty(array_filter($ds_visibility_condition))) {
      if (empty($ds_visibility_condition['state'])) {
        $form_state->setErrorByName('ds_visibility_condition][state', $this->t('You must select a state.'));
      }
      if (empty($ds_visibility_condition['conditional_option'])) {
        $form_state->setErrorByName('ds_visibility_condition][conditional_option', $this->t('You must select a conditional option.'));
      }
      if (empty($ds_visibility_condition['trigger'])) {
        $form_state->setErrorByName('ds_visibility_condition][trigger', $this->t('You must select a trigger.'));
      }
    }
  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {
    $field_id = $form_state->getValue('ds_id');
    $field_type = $form_state->getValue('ds_field_type');
    $ds_visibility_condition = $form_state->getValue('ds_visibility_condition');

    $data = [
      $field_id => [
        'label' => $form_state->getValue('ds_label'),
        'type' => $field_type,
        'description' => $form_state->getValue('ds_description'),
        'required' => (bool) $form_state->getValue('ds_required'),
        'default_value' => $form_state->getValue('ds_default_value'),
        'visibility_condition' => (!empty($ds_visibility_condition) && !empty(array_filter($ds_visibility_condition))) ? $ds_visibility_condition : [],
      ],
    ];

    if ($field_type === 'select') {
      $options = array_values(array_map(function ($item) {
        return [
          'key' => $item['item']['key'] ?? '',
          'label' => $item['item']['label'] ?? '',
        ];
      }, $form_state->getValue(['ds_select_fieldset', 'table']) ?? []));

      $data[$field_id]['options'] = array_filter($options, function ($option) {
        return !empty($option['key']) && !empty($option['label']);
      });
    }

    $this->component->updateComponentDisplaySettings($data);
    $form_state->setRedirectUrl($this->component->toUrl('edit-form'));
  }

  /**
   * Checks if a setting with the given ID exists.
   *
   * @param string $id
   *   The ID of the setting to check.
   *
   * @return bool
   *   TRUE if the setting exists, FALSE otherwise.
   */
  public function hasSetting($id) {
    $settings = (array) $this->component->get('display_settings');
    return isset($settings[$id]);
  }

  /**
   * Ajax callback for the "Add another item" button.
   */
  public function addmoreCallback(array &$form, FormStateInterface $form_state) {
    return $form['ds_select_fieldset'];
  }

  /**
   * Adds a new option.
   *
   * @param array $form
   *   The form array to add elements to.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The current state of the form.
   */
  public function addMoreSubmit(array &$form, FormStateInterface $form_state) {
    $items_count = $form_state->get('items_count');
    $add_button = $items_count + 1;
    $form_state->set('items_count', $add_button);
    $form_state->setRebuild();
  }

  /**
   * Deletes a row/option.
   *
   * @param array $form
   *   The form array to add elements to.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The current state of the form.
   */
  public function removeCallback(array &$form, FormStateInterface $form_state) {
    $trigger = $form_state->getTriggeringElement();
    $index_remove = $trigger['#name'];
    $removed_fields = $form_state->get('removed_item');
    $removed_fields[] = $index_remove;
    $form_state->set('removed_item', $removed_fields);
    $form_state->setRebuild();
  }

  /**
   * Gets the display settings excluding the current field.
   */
  protected function getDisplaySettingsOptions(): array {
    $options = [];

    foreach ($this->component->get('display_settings') as $key => $value) {
      if ($key !== $this->fieldName) {
        $options[$key] = $value['label'];
      }
    }

    return $options;
  }

}
