<?php

namespace Drupal\component_builder\Form;

use Drupal\Component\Datetime\TimeInterface;
use Drupal\Component\Utility\NestedArray;
use Drupal\component_builder\ComponentBuilderManager;
use Drupal\component_builder\ComponentWrapperFormTrait;
use Drupal\component_builder\Entity\ComponentWrapperInterface;
use Drupal\Core\Entity\ContentEntityForm;
use Drupal\Core\Entity\EntityRepositoryInterface;
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
use Drupal\Core\Extension\ExtensionPathResolver;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\Element;
use Drupal\Core\Serialization\Yaml;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Form controller for the component_wrapper entity edit forms.
 *
 * @ingroup component_wrapper
 */
class ComponentWrapperForm extends ContentEntityForm {

  use ComponentWrapperFormTrait;

  /**
   * The extension path resolver.
   *
   * @var \Drupal\Core\Extension\ExtensionPathResolver
   */
  protected $extensionPathResolver;

  /**
   * The component builder plugin manager.
   *
   * @var \Drupal\component_builder\ComponentBuilderManager
   */
  protected $componentBuilderManager;

  /**
   * Constructs a ContentEntityForm object.
   */
  public function __construct(EntityRepositoryInterface $entity_repository, EntityTypeBundleInfoInterface $entity_type_bundle_info, TimeInterface $time, ExtensionPathResolver $extensionPathResolver, ComponentBuilderManager $componentBuilderManager) {
    parent::__construct($entity_repository, $entity_type_bundle_info, $time);
    $this->extensionPathResolver = $extensionPathResolver;
    $this->componentBuilderManager = $componentBuilderManager;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('entity.repository'),
      $container->get('entity_type.bundle.info'),
      $container->get('datetime.time'),
      $container->get('extension.path.resolver'),
      $container->get('plugin.manager.component_builder'),
    );
  }

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state) {
    $form = parent::buildForm($form, $form_state);
    $form['field_header']['#states'] = [
      'visible' => [
        ":input[name='display_header[value]']" => ['checked' => TRUE],
      ],
    ];
    $form['field_footer']['#states'] = [
      'visible' => [
        ":input[name='display_footer[value]']" => ['checked' => TRUE],
      ],
    ];

    $form['field_image_container'] = [
      '#type' => 'container',
      '#attributes' => [
        'class' => [
          'wrapper-field-image-container--custom',
          'component-builder--properties---item',
        ],
      ],
      '#weight' => 2,
    ];
    $form['field_image_container']['field_image'] = $form['field_image'];

    $form['field_image_container']['#states'] = [
      'visible' => [
        ":input[name='display_image[value]']" => ['checked' => TRUE],
      ],
    ];
    $selector_region = 'display_in_region[value]';
    $form['field_region']['#states'] = [
      'visible' => [
        ":input[name='$selector_region']" => ['checked' => TRUE],
      ],
    ];
    $form['field_weight_in_region']['#states'] = [
      'visible' => [
        ":input[name='$selector_region']" => ['checked' => TRUE],
      ],
    ];
    $region_input = &$form['field_region'];
    $region_input['#type'] = 'select';
    $theme = \Drupal::config('system.theme')->get('default');
    $region_options = system_region_list($theme);
    $region_input['#options'] = $region_options;
    $region_input['#multiple'] = FALSE;
    $form['display_in_region_wrapper'] = [
      '#type' => 'details',
      '#title' => $this->t('Region configuration'),
      '#attributes' => [
        'class' => [
          'display-in-region--wrapper',
          'component-builder--properties---item',
        ],
      ],
      '#states' => [
        'visible' => [
          ":input[name='$selector_region']" => ['checked' => TRUE],
        ],
      ],
      '#open' => TRUE,
      '#weight' => $form['component_type']['#weight'] + 1,
      'field_region' => $form['field_region'],
      'field_weight_in_region' => $form['field_weight_in_region'],
    ];

    $form['field_header']['#attributes']['class'][] = 'component-builder--properties---item';
    $form['field_footer']['#attributes']['class'][] = 'component-builder--properties---item';
    $form['wrapper_display'] = [
      '#type' => 'container',
      '#attributes' => [
        'class' => [
          'wrapper-display--custom',
          'component-attributes-wrapper__style--none-border',
        ],
      ],
      'label' => [
        '#type' => 'label',
        '#title' => $this->t('Features'),
      ],
      'input' => [
        '#type' => 'container',
        'display_title' => $form['display_title'],
        'display_header' => $form['display_header'],
        'display_footer' => $form['display_footer'],
        'display_image' => $form['display_image'],
        'display_in_region' => $form['display_in_region'],
        'custom_style' => [
          '#type' => 'checkbox',
          '#title' => 'Custom Styles',
          '#weight' => $form['display_in_region']['#weight'] + 1,
        ],
      ],
      '#weight' => $form['component_type']['#weight'],
    ];

    unset($region_input['#size'], $form['field_region'], $form['field_weight_in_region'], $form['display_header'], $form['display_footer'], $form['display_title'], $form['display_image'], $form['field_image'], $form['display_in_region']);

    $form['component_attributes'] = [
      '#type' => 'container',
      '#attributes' => [
        'id' => 'component-attributes-wrapper',
        'class' => [
          'component-attributes-wrapper',
          'component-attributes-wrapper__style--none-border',
        ],
      ],
      '#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);

    $component_types = $form['component_type']['widget']['#options'];
    $component_builder_path = $this->moduleHandler->getModule('component_builder')->getPath();
    $setting_component_types = [];
    $plugin_collections = $this->componentBuilderManager->getGroupCollectionWithPlugin();
    $group_options = [];
    foreach ($component_types as $tid => $component_type) {
      if ($component_type == '_none') {
        continue;
      }
      $plugin_id = preg_replace('@[^a-z0-9-]+@', '_', strtolower($component_type));
      $image_path = $component_builder_path . '/components/component_' . $plugin_id . '/assets/images/default.png';
      if (file_exists($image_path)) {
        $setting_component_types[$tid] = $image_path;
      }
      if (isset($plugin_collections[$plugin_id])) {
        if (!isset($group_options[$plugin_collections[$plugin_id]['group']]['label'])) {
          $group_options[$plugin_collections[$plugin_id]['group']]['label'] = $plugin_collections[$plugin_id]['group'];
        }
        $indexes_group = $this->getDefaultWeightGroup($plugin_collections[$plugin_id]['group']);
        $default_value = $form['component_type']['widget']['#default_value'] ? $form['component_type']['widget']['#default_value'][0] : FALSE;
        $group_options[$plugin_collections[$plugin_id]['group']]['weight'] = $indexes_group;

        $group_options[$plugin_collections[$plugin_id]['group']]['items'][] = [
          'value' => $tid,
          'label' => $component_type,
          'selected' => $tid == $default_value ? TRUE : FALSE,
        ];
      }
    }
    usort($group_options, function ($a, $b) {
      return strcmp($a['weight'], $b['weight']);
    });

    $form['component_type']['widget']['#theme'] = 'component_type_select';
    $form['component_type']['widget']['#groups'] = $group_options;
    $select_parents = $form['component_type']['#parents'] ?? [];
    $selector_select = $root_select = array_shift($select_parents);
    if ($selector_select) {
      $selector_select = $root_select . '[' . implode('][', $select_parents) . ']';
      $form['component_type']['#name'] = $selector_select;
    }

    $form['field_properties']['#attributes']['style'] = "display: none;";
    $form['field_display_mode']['#attributes']['style'] = "display: none;";

    $form['#attached']['drupalSettings']['component_type_images'] = json_encode($setting_component_types);
    $form['#attached']['library'][] = 'component_builder/select2.min';
    $form['#attached']['library'][] = 'component_builder/component_wrapper';
    foreach (Element::children($form) as $key) {
      if (str_contains($key, 'field_')) {
        $form[$key]['#attributes']['class'][] = 'component-builder-toolbar--wrapper-field-reference';
      }
    }
    unset($form['langcode']);
    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {
    $values = $form_state->getValue($form['#parents']);
    $component_id = $form_state->getValue(array_merge($form['#parents'], [
      'component_type',
      '0',
      'target_id',
    ]));
    $component_wrapper_templates = $form_state->get('component_wrapper_templates');
    if ($component_id) {
      $template_machine_name = $component_wrapper_templates[$component_id];
      $display_mode = '';
      $properties = '';
      if (isset($values['component_attributes'][$template_machine_name]) && $values['component_attributes'][$template_machine_name]) {
        $properties = json_encode($values['component_attributes'][$template_machine_name]);
      }
      if (isset($values['component_attributes'][$template_machine_name]['properties']['options']['display_modes'])) {
        $display_mode = $values['component_attributes'][$template_machine_name]['properties']['options']['display_modes'];
      }
      $form_state->setValue(array_merge($form['#parents'], ['field_properties']), [0 => ['value' => $properties]]);
      $form_state->setValue(array_merge($form['#parents'], ['field_display_mode']), [0 => ['value' => $display_mode]]);
    }
    parent::submitForm($form, $form_state);
  }

  /**
   * {@inheritdoc}
   */
  public function save(array $form, FormStateInterface $form_state) {
    $form_state->setRedirect('entity.component_wrapper.collection');
    $entity = $this->getEntity();
    $entity->save();
  }

  /**
   * Render attribute as markup.
   */
  public function loadYmlComponents(array &$form, FormStateInterface $form_state) {
    $options = $form['component_type']['widget']['#options'];
    unset($options['_none']);
    $templates = [];
    foreach ($options as $template_id => $component_type) {
      $component_type_name = strtolower($component_type);
      $component_type_machine = preg_replace('@[^a-z0-9-]+@', '_', $component_type_name);
      $templates[$template_id] = $component_type_machine;
      $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' => 'fieldset',
                '#attributes' => [
                  'id' => $component_type_machine . '-' . $key_properties_component,
                  'class' => [
                    $component_type_machine . '-' . $key_properties_component . '--item',
                    $component_type_machine . '-' . $key_properties_component,
                    'component-builder--properties---item',
                  ],
                ],
                '#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,
                    ];
                  }
                }
              }
            }
          }
        }
      }
    }
    $form_state->set('component_wrapper_templates', $templates);
  }

  /**
   * Set value for attribute of component.
   */
  public function renderAttributeMarkup(array &$form, FormStateInterface $form_state) {
    $component_wrapper = $form_state->getFormObject()->getEntity();
    if (isset($form['component_attributes'])) {
      if ($component_wrapper instanceof ComponentWrapperInterface) {
        $component_type = $component_wrapper->get('component_type')->getValue();
        $component_id = NestedArray::getValue($component_type, [
          0,
          'target_id',
        ]);
        if ($component_id) {
          $component_wrapper_templates = $form_state->get('component_wrapper_templates');
          $template_machine_name = $component_wrapper_templates[$component_id];
          $properties = $component_wrapper->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 = $component_wrapper->get('field_display_mode')->value;
          if ($display) {
            $form['component_attributes'][$template_machine_name]['display_mode']['#default_value'] = json_decode($display, TRUE);
          }
        }
      }
    }
  }

}
