<?php

namespace Drupal\component_builder\Form;

use Drupal\component_builder\ComponentBuilderHelperInterface;
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\CloseDialogCommand;
use Drupal\Core\Ajax\ReplaceCommand;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Entity\ContentEntityTypeInterface;
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Form controller for the component_field_config entity edit forms.
 *
 * @ingroup component_field_config
 */
class ComponentFieldConfigForm extends FormBase {

  /**
   * The entity type manager.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected $entityTypeManager;

  /**
   * The component builder helper service.
   *
   * @var \Drupal\component_builder\ComponentBuilderHelperInterface
   */
  protected $componentBuilderHelper;

  /**
   * The entity bundle info.
   *
   * @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface
   */
  protected $entityTypeBundleInfo;

  /**
   * Constructs.
   */
  public function __construct(EntityTypeManagerInterface $entity_type_manager, ComponentBuilderHelperInterface $component_builder_helper, EntityTypeBundleInfoInterface $entity_type_bundle_info) {
    $this->entityTypeManager = $entity_type_manager;
    $this->componentBuilderHelper = $component_builder_helper;
    $this->entityTypeBundleInfo = $entity_type_bundle_info;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('entity_type.manager'),
      $container->get('component_builder.helper'),
      $container->get('entity_type.bundle.info'),
    );
  }

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

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state, $options = NULL) {
    $request = \Drupal::request();
    $mode = $request->get('mode');
    $field_entity_type = '';
    $field_machine_name = '';
    $field_name = '';
    $disable = FALSE;
    if ($mode && ($mode == 'edit' || $mode == 'delete')) {
      $form_state->set('mode', $mode);
      $field_entity_type = $request->get('entity_type');
      $field_machine_name = $request->get('field_name');
      $field_name = $this->componentBuilderHelper->getBundleHasField($field_entity_type, $field_machine_name);
      $disable = TRUE;
    }
    $entity_types = $this->entityTypeManager->getDefinitions();
    $option_entity_types = [];
    foreach ($entity_types as $entity_type_id => $entity_type) {
      if ($entity_type instanceof ContentEntityTypeInterface) {
        $option_entity_types[$entity_type_id] = $entity_type->getLabel();
      }
    }

    $form['#prefix'] = '<div id="wrapper-component-field-form">';
    $form['#suffix'] = '</div>';

    $form['status_messages'] = [
      '#type' => 'status_messages',
      '#weight' => -10,
    ];

    $form['error_modal'] = [
      '#type' => 'container',
      '#attributes' => [
        'class' => ['modal-component-field-error'],
      ],
      '#weight' => -1,
    ];
    $form['field_entity_type'] = [
      '#type' => 'select',
      '#title' => 'Entity Type',
      '#empty_value' => '',
      '#empty_option' => '- Select a value -',
      '#options' => $option_entity_types ?? [],
      '#default_value' => $field_entity_type,
      '#ajax' => [
        'callback' => [$this, 'entityTypeChange'],
        'event' => 'change',
        'wrapper' => 'wrapper-bundle',
      ],
      '#weight' => 0,
    ];
    if ($mode) {
      $form['field_entity_type']['#attributes']['disabled'] = 'disabled';
    }
    $form['wrapper_bundle'] = [
      '#type' => 'container',
      '#attributes' => [
        'id' => 'wrapper-bundle',
      ],
    ];

    $form['field_name'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Name'),
      '#required' => TRUE,
      '#default_value' => $field_name,
      '#attributes' => [
        'disabled' => $mode == 'delete' ? ['disabled'] : [],
      ],
      '#weight' => 0,
    ];
    if ($mode == 'delete') {
      $form['field_name']['#limit_validation_errors'] = [];
      $form['field_name']['#required'] = FALSE;
    }
    $form['field_machine_name'] = [
      '#type' => 'machine_name',
      '#title' => 'Machine name: ',
      '#maxlength' => 64,
      '#description' => $this->t('A unique name for this entity & bundle instance. Must be alpha-numeric and underscore separated.'),
      '#machine_name' => [
        'exists' => [$this, 'fieldExists'],
        'replace_pattern' => '[^a-z0-9_.]+',
        'source' => ['field_name'],
      ],
      '#default_value' => $field_machine_name,
      '#disabled' => $disable,
      '#weight' => 0,
    ];
    if ($field_entity_type || $form_state->getValue('field_entity_type')) {
      $field_entity_type_value = $form_state->getValue('field_entity_type') ?? $field_entity_type;
      $form['wrapper_bundle']['field_bundle_label'] = [
        '#type' => 'label',
        '#title' => $entity_types[$field_entity_type_value]->getBundleLabel(),
      ];

      $form['wrapper_bundle']['field_bundle_select'] = [
        '#type' => 'container',
        '#tree' => TRUE,
        '#weight' => 1,
      ];

      if ($mode == 'delete') {
        $form['wrapper_bundle']['description_bundle'] = [
          '#type' => 'markup',
          '#markup' => $this->t("This action cannot be undone."),
          '#weight' => 2,
        ];
      }

      if ($form_state->has('field_configs')) {
        $field_configs = $form_state->get('field_configs');
      }
      else {
        $field_configs = $this->entityTypeManager
          ->getStorage('field_config')
          ->loadByProperties([]);
        $form_state->set('field_configs', $field_configs);
      }

      $bundles = $this->entityTypeBundleInfo->getAllBundleInfo();
      foreach ($bundles[$field_entity_type_value] as $bundle => $bundle_info) {
        $field_config_name = "$field_entity_type.$bundle.$field_machine_name";
        if ($mode == 'delete') {
          if (isset($field_configs[$field_config_name])) {
            $form['wrapper_bundle']['field_bundle_select'][$bundle] = [
              '#type' => 'checkbox',
              '#title' => $bundle_info['label'],
              '#default_value' => FALSE,
            ];
          }
        }
        else {
          $form['wrapper_bundle']['field_bundle_select'][$bundle] = [
            '#type' => 'checkbox',
            '#title' => $bundle_info['label'],
            '#default_value' => FALSE,
          ];
        }
      }
    }

    $form['actions'] = [
      '#type' => 'actions',
      '#weight' => 2,
    ];

    $form['actions']['submit'] = [
      '#type' => 'submit',
      '#value' => $mode == 'delete' ? $this->t('Delete') : $this->t('Save'),
      '#submit' => ['::submitForm'],
      '#ajax' => [
        'callback' => [$this, 'submitCallback'],
      ],
    ];
    $form['actions']['cancel'] = [
      '#type' => 'button',
      '#value' => $this->t('Cancel'),
      '#ajax' => [
        'callback' => [$this, 'cancelCallback'],
      ],
      '#limit_validation_errors' => [],
    ];

    $form['#attached']['library'][] = 'core/drupal.dialog.ajax';
    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function validateForm(array &$form, FormStateInterface $form_state) {
    $validate_bundle = FALSE;
    $bundles = $form_state->getValue('field_bundle_select') ?? [];
    $mode = $form_state->get('mode');
    if (!$mode) {
      foreach ($bundles as $value) {
        if ($value != 0) {
          $validate_bundle = TRUE;
        }
      }
      if (!$validate_bundle) {
        $form_state->setErrorByName('field_bundle_label', $this->t('Please select bundle'));
      }
    }
  }

  /**
   * Callback when change bundle.
   */
  public function entityTypeChange(array $form, FormStateInterface $form_state) {
    return $form['wrapper_bundle'];
  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {
    $values = $form_state->getValues();
  }

  /**
   * Checks if a field machine name is taken.
   *
   * @param string $value
   *   The machine name, not prefixed.
   * @param array $element
   *   An array containing the structure of the 'field_name' element.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The current state of the form.
   *
   * @return bool
   *   Whether or not the field machine name is taken.
   */
  public function fieldExists($value, array $element, FormStateInterface $form_state) {
    $values = $form_state->getValues();
    if (isset($values['field_entity_type'], $values['field_bundle_select']) && $values['field_bundle_select']) {
      foreach ($values['field_bundle_select'] as $bundle) {
        $definitions = \Drupal::service('entity_field.manager')
          ->getFieldDefinitions($values['field_entity_type'], $bundle);
        if (isset($definitions[$value])) {
          return TRUE;
        }
      }
    }
    return FALSE;
  }

  /**
   * Submit field ajax.
   */
  public function cancelCallback(array $form, FormStateInterface $form_state) {
    $response = new AjaxResponse();
    $response->addCommand(new CloseDialogCommand());
    return $response;
  }

  /**
   * Submit field ajax.
   */
  public function submitCallback(array $form, FormStateInterface $form_state) {
    $response = new AjaxResponse();
    if ($form_state->hasAnyErrors()) {
      $response->addCommand(new ReplaceCommand('#wrapper-component-field-form', $form));
    }
    else {
      $mode = $form_state->get('mode');
      $values = $form_state->getValues();
      $entity_type = $values['field_entity_type'];
      $field_name = $values['field_name'];
      $field_machine_name = $values['field_machine_name'];
      $bundles = $values['field_bundle_select'] ?? [];
      if ($mode == 'delete' && (!$bundles || !$field_machine_name || !$field_name)) {
        $this->componentBuilderHelper->deleteComponentField($entity_type, '', $field_machine_name);
      }
      elseif ($entity_type && $field_name && $field_machine_name) {
        $this->componentBuilderHelper->createStorageField($entity_type, $field_machine_name);
        if ($bundles) {
          foreach ($bundles as $bundle => $value) {
            if ($value !== 0) {
              if ($mode == 'edit') {
                $this->componentBuilderHelper->updateComponentField($entity_type, $bundle, $field_machine_name, $field_name);
              }
              elseif ($mode == 'delete') {
                $this->componentBuilderHelper->deleteComponentField($entity_type, $bundle, $field_machine_name);
              }
              else {
                $this->componentBuilderHelper->createReferenceComponentWrapperField($entity_type, $bundle, $field_machine_name, $field_name);
              }
            }
          }
        }
      }
      \Drupal::service("router.builder")->rebuild();
      Cache::invalidateTags(['local_task']);
      $table = $this->componentBuilderHelper->buildTableComponentFields();
      $response->addCommand(new ReplaceCommand('#table-information', $table));
      $response->addCommand(new CloseDialogCommand());
    }
    return $response;
  }

}
