<?php

namespace Drupal\component_builder_toolbar\Form;

use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\CloseDialogCommand;
use Drupal\Core\Ajax\InvokeCommand;
use Drupal\Core\Ajax\ReplaceCommand;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Serialization\Yaml;
use Drupal\Core\Url;

/**
 * Form controller for the component_wrapper entity edit properties forms.
 *
 * @ingroup component_wrapper
 */
class ComponentWrapperPropertiesForm extends FormBase {
  /**
   * The component wrapper.
   *
   * @var \Drupal\component_builder\Entity\ComponentWrapper
   */
  protected $componentWrapper;

  /**
   * The entity.
   *
   * @var \Drupal\Core\Entity\EntityInterface
   */
  protected $entity;

  /**
   * The entity type id.
   *
   * @var string
   */
  protected $entityTypeId;

  /**
   * The field name.
   *
   * @var string
   */
  protected $fieldName;


  /**
   * The field label.
   *
   * @var string
   */
  protected $fieldLabel;

  /**
   * The delta.
   *
   * @var string
   */
  protected $delta;

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

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state, $entity_type_id = '', $component_wrapper = '', $field_name = '', $delta = '') {
    $this->entityTypeId = $entity_type_id;
    $this->fieldName = $field_name;
    $this->delta = $delta;
    $this->componentWrapper = $component_wrapper;
    $this->fieldLabel = $component_wrapper->label();
    $this->entity = $this->getRequest()->get($entity_type_id);
    $form['component_attributes'] = [
      '#type' => 'container',
      '#attributes' => ['id' => 'component-attributes-wrapper'],
      '#weight' => $form['component_type']['#weight'],
      '#tree' => TRUE,
    ];
    $form['config'] = [
      '#type' => 'details',
      '#title' => t('Config'),
      '#weight' => $form['component_type']['#weight'],
      '#access' => FALSE,
    ];
    $this->loadYmlComponents($form, $form_state);
    $this->renderAttributeMarkup($form, $form_state);

    $form['#attached']['library'][] = 'component_builder/component_wrapper';

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

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

    $form['actions']['cancel'] = [
      '#type' => 'button',
      '#value' => $this->t('Cancel'),
      '#ajax' => [
        'callback' => [$this, 'cancelCallback'],
      ],
    ];

    return $form;
  }

  /**
   * Submit field ajax.
   */
  public function submitCallback(array $form, FormStateInterface $form_state) {
    $response = new AjaxResponse();
    $wrapper_selector = "[data-wrapper-id='{$this->componentWrapper->id()}']";
    $move_wrapper_url = Url::fromRoute(
      'entity.' . $this->entityTypeId . '.component_builder_toolbar_move_component',
      [
        $this->entityTypeId => $this->entity->id(),
        'component_wrapper' => $this->componentWrapper->id(),
        'field_name' => $this->fieldName,
      ]
    );
    $wrapper_markup = \Drupal::service('component_builder_toolbar.manager')->buildComponentWrapperMarkup($this->entity, $this->componentWrapper, $move_wrapper_url, $this->delta);
    $response->addCommand(new ReplaceCommand($wrapper_selector, $wrapper_markup));
    $response->addCommand(new InvokeCommand($wrapper_selector, 'addClass', ["preview"]));
    $response->addCommand(new CloseDialogCommand());
    return $response;
  }

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

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {
    $values = $form_state->getValue($form['#parents']);
    $template_machine_name = $this->componentWrapper->getTemplateMachineName();
    $properties = '';
    if (isset($values['component_attributes'][$template_machine_name]) && $values['component_attributes'][$template_machine_name]) {
      $properties = json_encode($values['component_attributes'][$template_machine_name]);
    }
    $this->componentWrapper->set('field_properties', $properties)->save();
    return $form;
  }

  /**
   * Render attribute as markup.
   */
  public function loadYmlComponents(array &$form, FormStateInterface $form_state) {
    $component_type_name = $this->componentWrapper->getTemplateMachineName();
    $component_type_machine = preg_replace('@[^a-z0-9-]+@', '_', $component_type_name);
    $plugin_manager = \Drupal::service('plugin.manager.component_builder');
    if ($plugin = $plugin_manager->getInstanceByTemplateName($component_type_machine)) {
      $yml_path = $plugin->getDefinePath();
      if ($yml_path && file_exists($yml_path)) {
        $yml_content = file_get_contents($yml_path);
        $yml_content = Yaml::decode($yml_content);
        if (isset($yml_content['properties'])) {
          $properties_component = $yml_content['properties'];
          if (is_array($properties_component)) {
            $form['component_attributes'][$component_type_machine] = [
              '#type' => 'container',
              '#attributes' => [
                'id' => 'component-attributes-wrapper--' . $component_type_machine,
                'class' => [
                  'component-attributes-wrapper--' . $component_type_machine,
                  'component-attributes-wrapper--item',
                ],
              ],
            ];
          }
          foreach ($properties_component as $key_properties_component => $properties) {
            $title_properties = $key_properties_component;
            if ($properties['label']) {
              $title_properties = $properties['label'];
              unset($properties['label']);
            }
            $form['component_attributes'][$component_type_machine][$key_properties_component] = [
              '#type' => 'details',
              '#attributes' => [
                'id' => $component_type_machine . '-' . $key_properties_component,
                'class' => [
                  $component_type_machine . '-' . $key_properties_component . '--item',
                  $component_type_machine . '-' . $key_properties_component,
                ],
              ],
              '#open' => TRUE,
              '#title' => $title_properties,
            ];
            foreach ($properties as $key => $values) {
              if (is_array(reset($values))) {
                $form['component_attributes'][$component_type_machine][$key_properties_component][$key] = [
                  '#type' => 'fieldset',
                  '#attributes' => [
                    'id' => $component_type_machine . '--' . $key_properties_component . '-' . $key,
                    'class' => ['component-attributes-wrapper--' . $key_properties_component . '-' . $key],
                  ],
                  '#title' => $key,
                ];
                foreach ($values as $option_key => $option_value) {
                  $options = [];
                  if (
                    !($component_type_machine === 'bubble_map' && ($option_key === 'number_display_item' || $option_key === 'item_shape'))
                    && !($component_type_machine === 'flexslider' && $option_key === 'type')
                  ) {
                    $options = ['_none' => '-- None --'];
                  }
                  $options += $option_value;
                  $form['component_attributes'][$component_type_machine][$key_properties_component][$key][$option_key] = [
                    '#type' => 'select',
                    '#title' => 'Select ' . $option_key,
                    '#options' => $options,
                  ];
                }
              }
            }
          }
        }
      }
    }
  }

  /**
   * Set value for attribute of component.
   */
  public function renderAttributeMarkup(array &$form, FormStateInterface $form_state) {
    if (isset($form['component_attributes'])) {
      $template_machine_name = $this->componentWrapper->getTemplateMachineName();
      $properties = $this->componentWrapper->get('field_properties')->value;
      if ($properties) {
        $properties = json_decode($properties, TRUE);
        if (is_array($properties)) {
          foreach ($properties as $key => $property_types) {
            foreach ($property_types as $parent_type_key => $types) {
              foreach ($types as $type_key => $value) {
                $form['component_attributes'][$template_machine_name][$key][$parent_type_key][$type_key]['#default_value'] = $value;
              }
            }
          }
        }
      }
      $display = $this->componentWrapper->get('field_display_mode')->value;
      if ($display) {
        $form['component_attributes'][$template_machine_name]['display_mode']['#default_value'] = json_decode($display, TRUE);
      }
    }
  }

}
