<?php

namespace Drupal\component_builder\Form;

use Drupal\Component\Serialization\Json;
use Drupal\Component\Utility\NestedArray;
use Drupal\component_builder\ComponentBuilderManager;
use Drupal\component_builder\ComponentWrapperFormTrait;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Entity\EntityFieldManagerInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Extension\ExtensionPathResolver;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\Element;
use Drupal\Core\Serialization\Yaml;
use Drupal\Core\Theme\ThemeManagerInterface;
use Drupal\inline_entity_form\Form\EntityInlineForm;
use Drupal\node\NodeForm;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Defines the inline form for component wrapper.
 */
class ComponentWrapperInlineForm extends EntityInlineForm {

  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;

  /**
   * The config factory.
   *
   * @var \Drupal\Core\Config\ConfigFactoryInterface
   */
  protected $configFactory;

  /**
   * Constructs the inline entity form controller.
   *
   * @param \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager
   *   The entity field manager.
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *   The entity type manager.
   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
   *   The module handler.
   * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
   *   The entity types.
   * @param \Drupal\Core\Theme\ThemeManagerInterface $theme_manager
   *   The theme manager.
   * @param \Drupal\Core\Extension\ExtensionPathResolver $extension_path_resolver
   *   The extension path resolver.
   * @param \Drupal\component_builder\ComponentBuilderManager $componentBuilderManager
   *   The component builder plugin manager.
   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
   *   The factory for configuration objects.
   */
  public function __construct(
      EntityFieldManagerInterface $entity_field_manager,
      EntityTypeManagerInterface $entity_type_manager,
      ModuleHandlerInterface $module_handler,
      EntityTypeInterface $entity_type,
      ThemeManagerInterface $theme_manager,
      ExtensionPathResolver $extension_path_resolver,
      ComponentBuilderManager $componentBuilderManager,
      ConfigFactoryInterface $config_factory
    ) {
    parent::__construct($entity_field_manager, $entity_type_manager, $module_handler, $entity_type, $theme_manager);
    $this->extensionPathResolver = $extension_path_resolver;
    $this->componentBuilderManager = $componentBuilderManager;
    $this->configFactory = $config_factory;
  }

  /**
   * {@inheritdoc}
   */
  public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) {
    return new static(
      $container->get('entity_field.manager'),
      $container->get('entity_type.manager'),
      $container->get('module_handler'),
      $entity_type,
      $container->get('theme.manager'),
      $container->get('extension.path.resolver'),
      $container->get('plugin.manager.component_builder'),
      $container->get('config.factory'),
    );
  }

  /**
   * Detect entity has field references to component wrapper.
   */
  public function detectEntity() {
    static $drupal_static_fast_detect_entity_id;
    if (!isset($drupal_static_fast_detect_entity_id)) {
      $storage = $this->entityTypeManager->getStorage('field_storage_config');
      $entity_ids = $storage->getQuery()
        ->accessCheck(TRUE)
        ->execute();
      $field_storages = $storage->loadMultipleOverrideFree($entity_ids);
      $drupal_static_fast_detect_entity_id = [];
      foreach ($field_storages as $field_storage) {
        $field_storage_name = $field_storage->getName();
        $filed_storage_type = $field_storage->getType();
        $allowed_type = [
          'entity_reference',
        ];
        if (in_array($filed_storage_type, $allowed_type, TRUE)) {
          $filed_storage_target_type = $field_storage->getSettings()['target_type'];
          if ($filed_storage_target_type === 'component_wrapper') {
            foreach ($field_storage->getBundles() as $bundle) {
              $drupal_static_fast_detect_entity_id[$bundle][] = $field_storage_name;
            }
          }
        }
      }
    }
    return $drupal_static_fast_detect_entity_id;
  }

  /**
   * {@inheritdoc}
   */
  public function entityForm(array $entity_form, FormStateInterface $form_state) {
    $entity_form['#process'][] = '_component_builder_inline_entity_form_build_actions';
    $entity_form = parent::entityForm($entity_form, $form_state);
    $entity_form['#attributes']['class'][] = 'component-wrapper-inline-form';
    $entity_form['field_display_mode']['#attributes']['class'][] = 'visually-hidden';
    // $entity_form['title']['#attributes']['class'][] = 'visually-hidden';
    $plugin_selected = NULL;

    $group_feature_parent = $group_parents = $entity_form['#parents'];
    $group_parents[] = 'content';
    $group_select_name = implode('][', $group_parents);
    $group_feature_parent[] = "feature";
    $group_feature_name = implode('][', $group_feature_parent);
    $entity_form['feature'] = [
      "#group" => $group_select_name,
      "#weight" => 10.1,
      "#type" => "container",
      "#tree" => TRUE,
      '#parents' => $group_feature_parent,
      '#prefix' => '<div class="group-feature-wrapper"><div class="group-feature__label form-item__label">Features</div>',
      '#suffix' => '</div>',
    ];
    $entity_form['display_header']['#group'] = $group_feature_name;
    $entity_form['display_footer']['#group'] = $group_feature_name;
    $entity_form['display_title']['#group'] = $group_feature_name;
    $entity_form['display_image']['#group'] = $group_feature_name;
    $entity_form['display_in_region']['#group'] = $group_feature_name;
    $entity_form['custom_styles']['#group'] = $group_feature_name;


    $group_header_parent = $group_parents = $entity_form['#parents'];
    $group_parents[] = 'content';
    $group_header_container_name = implode('][', $group_parents);
    $group_header_parent[] = "header_container";
    $group_header_name = implode('][', $group_header_parent);
    $entity_form['header_container'] = [
      "#group" => $group_header_container_name,
      "#weight" => 10.2,
      "#type" => "container",
      "#tree" => TRUE,
      '#parents' => $group_header_parent,
    ];
    $entity_form['field_header']['#group'] = $group_header_name;
    $header_parents = $entity_form['display_header']['widget']['#parents'];
    $selector_header = $root_header = array_shift($header_parents);
    if ($selector_header) {
      $selector_header = $root_header . '[' . implode('][', $header_parents) . '][value]';
      $entity_form['header_container']['#states'] = [
        'visible' => [
          ":input[name='$selector_header']" => ['checked' => TRUE],
        ],
      ];
    }

    $group_footer_parent = $group_parents = $entity_form['#parents'];
    $group_parents[] = 'content';
    $group_footer_container_name = implode('][', $group_parents);
    $group_footer_parent[] = "footer_container";
    $group_footer_name = implode('][', $group_footer_parent);
    $entity_form['footer_container'] = [
      "#group" => $group_footer_container_name,
      "#weight" => 50,
      "#type" => "container",
      "#tree" => TRUE,
      '#parents' => $group_footer_parent,
    ];
    $entity_form['field_footer']['#group'] = $group_footer_name;

    $footer_parents = $entity_form['display_footer']['widget']['#parents'];
    $selector_footer = $root_footer = array_shift($footer_parents);
    if ($selector_footer) {
      $selector_footer = $root_footer . '[' . implode('][', $footer_parents) . '][value]';
      $entity_form['footer_container']['#states'] = [
        'visible' => [
          ":input[name='$selector_footer']" => ['checked' => TRUE],
        ],
      ];
    }

    $group_image_parent = $group_parents = $entity_form['#parents'];
    $group_parents[] = 'content';
    $group_image_container_name = implode('][', $group_parents);
    $group_image_parent[] = "image_container";
    $group_image_name = implode('][', $group_image_parent);
    $entity_form['image_container'] = [
      "#group" => $group_image_container_name,
      "#weight" => 10.3,
      "#type" => "container",
      "#tree" => TRUE,
      '#parents' => $group_image_parent,
    ];
    $entity_form['field_image']['#group'] = $group_image_name;

    $image_parents = $entity_form['display_image']['widget']['#parents'];
    $selector_image = $root_image = array_shift($image_parents);
    if ($selector_image) {
      $selector_image = $root_image . '[' . implode('][', $image_parents) . '][value]';
      $entity_form['image_container']['#states'] = [
        'visible' => [
          ":input[name='$selector_image']" => ['checked' => TRUE],
        ],
      ];
    }

    /** @deprecated "Display in region" will be removed in next version. */
    $region_parents = $entity_form['display_in_region']['widget']['#parents'];
    $selector_region = $root_region = array_shift($region_parents);
    if ($selector_region) {
      $selector_region = $root_region . '[' . implode('][', $region_parents) . '][value]';
      $region_input = &$entity_form['field_region']['widget'][0]['value'];
      $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;
      unset($region_input['#size']);

      $group_parents = $parents = $entity_form['#parents'];
      $parents[] = 'content';
      $group_parent_name = implode('][', $parents);
      $group_parents[] = "display_in_region_container";
      $group_display_in_region_name = implode('][', $group_parents);
      $entity_form['display_in_region_container'] = [
        '#group' => $group_parent_name,
        '#weight' => 10.4,
        '#type' => 'details',
        '#open' => TRUE,
        '#title' => $this->t('Region configuration'),
        "#tree" => TRUE,
        '#parents' => $group_parents,
        '#states' => [
          'visible' => [
            ":input[name='$selector_region']" => ['checked' => TRUE],
          ],
        ],
      ];
      $entity_form['field_region']['#group'] = $group_display_in_region_name;
      $entity_form['field_weight_in_region']['#group'] = $group_display_in_region_name;
    }

    $options = $entity_form['component_type']['widget']['#options'];
    $options = $this->filterComponents($options);
    $entity_form['component_type']['widget']['#options'] = $options;
    unset($entity_form['component_type']['widget']['#options']['_none']);
    $default_component = $this->configFactory->get('component_builder.settings')->get('default_component');
    $config_default_component = $this->getDefaultComponent($entity_form['component_type']['widget']['#options'], $default_component);

    /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
    $entity = $entity_form['#entity'];
    $entity_form['component_type']['widget']['#ajax'] = [
      'callback' => 'component_wrapper_inline_form_change_type',
      'wrapper' => 'inline-entity-form-' . $entity_form['#ief_id'],
      'event' => 'change',
    ];
    $entity_form['component_type']['widget']['#prefix'] = '<div class="component__features">';
    $entity_form['component_type']['widget']['#suffix'] = '<div class="btn-features"><em>icon</em></div></div>';

    $allowed_field = [];
    $component_fields = [
      'field_left_column',
      'field_middle_column',
      'field_right_column',
      'field_title_top',
      'field_highlighted_button_text',
    ];
    //todo Move custom code elsewhere.
    $component_special = [
      'bild' => 'image_item',
    ];

    $components = $this->componentBuilderManager->getDefinitions();
    foreach ($components as $id => $define) {
      $component_fields = array_merge($component_fields, ['field_' . $id]);
    }
    $component_type_options = $entity_form['component_type']['widget']['#options'];
    $parent_component_type = $entity_form['component_type']['widget']['#parents'];

    if ($component_selected = NestedArray::getValue($form_state->getUserInput(), $parent_component_type)) {
      $allowed_field_term_id = $component_selected;
    }
    elseif (!$entity->get('component_type')->isEmpty()) {
      $allowed_field_term_id = $entity->get('component_type')->target_id;
    }

    if (empty($allowed_field_term_id)) {
      $allowed_field_term_id = $config_default_component;
      $entity_form['component_type']['widget']['#default_value'] = $config_default_component;
    }

    if (isset($allowed_field_term_id)) {
      $component_name = $this->getComponentNameWithTerm($component_type_options, $allowed_field_term_id);
      if (isset($component_special[$component_name])) {
        $component_name = $component_special[$component_name];
      }
      if ($component_name) {
        $allowed_field_name = 'field_' . $component_name;
        $form_state->set('field_allowed', $allowed_field_name);
        $allowed_field = [$allowed_field_name];
        $plugin_selected = $this->componentBuilderManager->getInstanceByTemplateName($component_name);

        $entity_form[$allowed_field_name]['widget'][0]['#field_title'] = '';
        $entity_form[$allowed_field_name]['widget'][0]['#attributes']['class'][] = 'component-wrapper__field';
        $entity_form[$allowed_field_name]['widget'][0]['#type'] = 'container';

        if ($component_name === 'composite') {
          $allowed_field = array_merge($allowed_field, [
            'field_left_column',
            'field_middle_column',
            'field_right_column',
          ]);
        }

        $entity_form['#attributes']['class'][] = 'component-attributes-wrapper--' . $component_name;
      }

      if (in_array('field_overview_page', $allowed_field)) {
        $allowed_field = array_merge($allowed_field, [
          'field_title_top',
          'field_highlighted_button_text',
        ]);
      }
    }

    foreach (Element::children($entity_form) as $key) {
      if (in_array($key, $component_fields) && !in_array($key, $allowed_field)) {
        $entity_form[$key]['#access'] = FALSE;
      }
    }

    $has_property = FALSE;
    if ($plugin_selected) {
      $yml_path = $plugin_selected->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 = $yml_content['properties'])) {
          $has_property = TRUE;
          $build_config = [];
          $properties_value = $entity->get('field_properties')->value;
          $this->renderProperties($build_config, $properties, $properties_value);
          $build_config['#parents'] = $entity_form['field_properties']['widget']['#parents'];
          $build_config['#tree'] = $entity_form['field_properties']['widget']['#tree'];
          $build_config['#field_parents'] = $entity_form['field_properties']['widget']['#field_parents'];
          $entity_form['field_properties']['widget'][0] = $build_config;

          $group_properties_parents = $group_parents = $entity_form['#parents'];
          $group_parents[] = 'content';
          $group_properties_container_name = implode('][', $group_parents);
          $group_properties_parents[] = "properties_container";
          $group_properties_name = implode('][', $group_properties_parents);
          $entity_form['properties_container'] = [
            "#group" => $group_properties_container_name,
            "#weight" => 10.5,
            "#type" => "container",
            "#tree" => TRUE,
            '#parents' => $group_properties_parents,
          ];
          $entity_form['field_properties']['#group'] = $group_properties_name;

          $custom_style_parents = $entity_form['custom_styles']['widget']['#parents'];
          $selector_custom_style = $root_custom_style = array_shift($custom_style_parents);
          if ($selector_custom_style) {
            $selector_custom_style = $root_custom_style . '[' . implode('][', $custom_style_parents) . '][value]';
            $entity_form['properties_container']['#states'] = [
              'visible' => [
                ":input[name='$selector_custom_style']" => ['checked' => TRUE],
              ],
            ];
          }
        }
      }
    }
    if (!$has_property) {
      $entity_form['custom_styles']['#access'] = FALSE;
      $entity_form['field_properties']['#access'] = FALSE;
    }

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

    // select2
    $form_object = $form_state->getFormObject();
    if ($form_object instanceof NodeForm) {
      $bundle = $form_object->getEntity()->bundle();
      $detect_field = $this->detectEntity();

      if (isset($detect_field[$bundle])) {
        $form_state->set('field_name_alter', $detect_field[$bundle]);
        $form_state->set('template_options', $entity_form['component_type']['widget']['#options']);

        $component_types = $entity_form['component_type']['widget']['#options'];
        $component_builder_path = \Drupal::moduleHandler()->getModule('component_builder')
          ->getPath();
        $plugin_collections = \Drupal::service('plugin.manager.component_builder')
          ->getGroupCollectionWithPlugin();
        $plugin_manager = \Drupal::service('plugin.manager.component_builder');
        $setting_component_types = [];
        $group_options = [];

        $default_component = $entity_form['component_type']['widget']['#default_value'] ? $entity_form['component_type']['widget']['#default_value'] : FALSE;

        if (!$default_component) {
          $post_component_id = NestedArray::getValue($_POST, $entity_form['component_type']['widget']['#parents']);
          if ($post_component_id) {
            $default_component = $post_component_id;
          }
          elseif ($config_default_component) {
            $default_component = array_flip($component_types)[$config_default_component['label']];
          }
        }

        foreach ($component_types as $tid => $component_type) {
          if ($component_type == '_none') {
            continue;
          }
          if (!empty($config_allowed_components) && !in_array(strtolower($component_type), $config_allowed_components)) {
            continue;
          }

          $plugin_id = preg_replace('@[^a-z0-9-]+@', '_', strtolower($component_type));
          $plugin = $plugin_manager->getInstanceByTemplateName($plugin_id);
          $image_path = $plugin ? $plugin->getIcon() : $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])) {
            $group_name = $plugin_collections[$plugin_id]['group'];
            if (!isset($group_options[$group_name]['label'])) {
              $group_options[$group_name]['label'] = $group_name;
            }

            $indexes_group = $this->getDefaultWeightGroup($group_name);
            $group_options[$group_name]['type'] = 'optgroup';
            $group_options[$group_name]['weight'] = $indexes_group;
            $group_options[$group_name]['options'][$tid] = $component_type;
          }
        }
        $entity_form['#attached']['drupalSettings']['component_type_images'] = json_encode($setting_component_types);

        uasort($group_options, function ($a, $b) {
          return strcmp($a['weight'], $b['weight']);
        });

        $optgroup = [];
        foreach ($group_options as $group_option) {
          $optgroup[$group_option['label']] = $group_option['options'];
        }

        $entity_form['component_type']['widget']['#options'] = $optgroup;
      }

      $entity_form['#attached']['library'][] = 'component_builder/select2.min';
    }

    return $entity_form;
  }

  /**
   * {@inheritdoc}
   */
  public function entityFormSubmit(array &$entity_form, FormStateInterface $form_state) {
    $parent_properties = $entity_form['field_properties']['widget']['#parents'];
    $property_value = $form_state->getValue($parent_properties);
    if (isset($property_value[0]['value'])) {
      $properties = "";
    }
    else {
      $properties = Json::encode($property_value);
    }
    $form_state->setValue($parent_properties, [0 => ['value' => $properties]]);

    $display_mode = NULL;
    if (isset($property_value['properties']['options']['display_modes'])) {
      $display_mode = $property_value['properties']['options']['display_modes'];
    }
    $form_state->setValue($entity_form['field_display_mode']['widget']['#parents'], [0 => ['value' => $display_mode]]);

    // if ($form_state->has('field_allowed')) {
    //   $field_name = $form_state->get('field_allowed');
    //   if (isset($entity_form[$field_name])) {
    //     $parents = $entity_form[$field_name]['widget']['#parents'];
    //     $parents = array_merge($parents, [0, 'inline_entity_form']);
    //     $item_submitted = $form_state->getValue($parents);

    //     if (isset($item_submitted['title'])) {
    //       $title = $item_submitted['title'][0]['value'];

    //       if (!empty($title)) {
    //         $form_state->setValue($entity_form['title']['widget']['#parents'], [0 => ['value' => $title]]);
    //       }
    //     }
    //   }
    // }

    parent::entityFormSubmit($entity_form, $form_state);
  }

}
