<?php

namespace Drupal\keycloak_user_provisioning\Form;

use Drupal\Component\Serialization\Json;
use Drupal\Core\Config\Config;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Config\ImmutableConfig;
use Drupal\Core\Entity\EntityFieldManagerInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Render\Markup;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\Url;
use Drupal\field\Entity\FieldConfig;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Form for Keycloak mapping configuration.
 */
class MoKeycloakMappingTab extends FormBase {
  use StringTranslationTrait;

  /**
   * ImmutableConfig property.
   *
   * @var Drupal\Core\Config\ImmutableConfig
   */
  private ImmutableConfig $config;

  /**
   * Config property.
   *
   * @var Drupal\Core\Config\Config
   */
  private Config $configfactory;

  /**
   * Entity field manager.
   *
   * @var \Drupal\Core\Entity\EntityFieldManagerInterface
   */
  protected EntityFieldManagerInterface $entityFieldManager;

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

  /**
   * Module handler.
   *
   * @var \Drupal\Core\Module\ModuleHandlerInterface
   */
  protected ModuleHandlerInterface $moduleHandler;

  /**
   * Constructs a new MoKeycloakMappingTab object.
   *
   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
   *   The config factory.
   * @param \Drupal\Core\Messenger\MessengerInterface $messenger
   *   The messenger service.
   * @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.
   */
  public function __construct(
    ConfigFactoryInterface $config_factory,
    MessengerInterface $messenger,
    EntityFieldManagerInterface $entity_field_manager,
    EntityTypeManagerInterface $entity_type_manager,
    ModuleHandlerInterface $module_handler,
  ) {
    $this->config = $config_factory->get('keycloak_user_provisioning.settings');
    $this->configfactory = $config_factory->getEditable('keycloak_user_provisioning.settings');
    $this->messenger = $messenger;
    $this->entityFieldManager = $entity_field_manager;
    $this->entityTypeManager = $entity_type_manager;
    $this->moduleHandler = $module_handler;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('config.factory'),
      $container->get('messenger'),
      $container->get('entity_field.manager'),
      $container->get('entity_type.manager'),
      $container->get('module_handler')
    );
  }

  /**
   * FormID of the form.
   *
   * @return string
   *   Returns formID of the form.
   */
  public function getFormId() {
    return 'MoKeycloakMappingTab';
  }

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state) {
    // Add CSS for mapping UI.
    $form['#attached']['library'][] = 'keycloak_user_provisioning/keycloak_user_provisioning.admin';

    if (($this->config->get('mo_keycloak_attr_list_from_server')) != '') {
      $keycloak_test_data = Json::decode($this->config->get('mo_keycloak_attr_list_from_server'));
    }

    // Create vertical tabs for different mapping types.
    $form['mapping_tabs'] = [
      '#type' => 'vertical_tabs',
    ];

    // Add the button AFTER the vertical tabs are created but before
    // the content.
    if (isset($keycloak_test_data['id']) || isset($keycloak_test_data['errorCode'])) {
      $form['mapping_tab_attribute_button_container'] = [
        '#type' => 'container',
        '#attributes' => [
          'style' => 'text-align: right;',
        ],
        '#weight' => -50,
        '#prefix' => '<div class="attr_received_from_keycloak_btn">',
        '#suffix' => '</div>',
      ];

      $form['mapping_tab_attribute_button_container']['mapping_tab_attribute_button'] = [
        '#type' => 'link',
        '#title' => $this->t('Attributes Received from Keycloak'),
        '#url' => Url::fromRoute('keycloak_user_provisioning.attributeListOfKeycloak'),
        '#attributes' => [
          'class' => ['button', 'button--primary', 'use-ajax', 'js-form-submit', 'form-submit'],
          'data-dialog-type' => 'modal',
          'data-dialog-options' => json_encode(['width' => '65%']),
        ],
        '#limit_validation_errors' => [],
        '#prefix' => '<br>',
      ];
    }

    // Attribute Mapping Tab.
    $form['attribute_mapping'] = [
      '#type' => 'details',
      '#title' => $this->t('Attribute Mapping'),
      '#group' => 'mapping_tabs',
      '#open' => TRUE,
    ];

    // Basic Attribute Mapping Fieldset.
    $form['attribute_mapping']['basic_attribute_mapping_fieldset'] = [
      '#type' => 'fieldset',
      '#title' => $this->t('Basic Attribute Mapping'),
    ];

    // Get all field definitions for the user entity.
    $field_definitions = $this->entityFieldManager->getFieldDefinitions('user', 'user');

    // Prepare dropdown options.
    $custom_fields = [];

    // Always include system fields you want.
    $custom_fields['name'] = 'name';
    $custom_fields['mail'] = 'mail';

    // Add only fields created via "Manage fields".
    foreach ($field_definitions as $field_name => $definition) {
      // Include only configurable fields, and exclude user_picture.
      if ($definition instanceof FieldConfig && $field_name !== 'user_picture') {
        $custom_fields[$field_name] = $field_name;
      }
    }

    $first_name_attr = $this->configfactory->get('keycloak_user_provisioning_basic_first_name_mapping');
    $last_name_attr = $this->configfactory->get('keycloak_user_provisioning_basic_last_name_mapping');

    $first_name_attr = $first_name_attr ?? 'name';
    $last_name_attr = $last_name_attr ?? 'name';

    $form['attribute_mapping']['basic_attribute_mapping_fieldset']['first_name_attribute'] = [
      '#type' => 'select',
      '#title' => $this->t('User First Name'),
      '#default_value' => $custom_fields[$first_name_attr],
      '#attributes' => ['style' => 'width:30rem', 'placeholder' => 'Enter Username attribute'],
      '#options' => $custom_fields,
    ];

    $form['attribute_mapping']['basic_attribute_mapping_fieldset']['last_name_attribute'] = [
      '#type' => 'select',
      '#title' => $this->t('User Last Name'),
      '#default_value' => $custom_fields[$last_name_attr],
      '#attributes' => ['style' => 'width:30rem', 'placeholder' => 'Enter Username attribute'],
      '#options' => $custom_fields,
    ];

    // Custom Attribute Mapping Fieldset.
    $premium_badge = ' <span class="premium-badge">PREMIUM</span><hr>';
    $form['attribute_mapping']['mo_keycloak_custom_attribute_mapping'] = [
      '#type' => 'fieldset',
      '#title' => Markup::create($this->t('Custom Attribute Mapping') . $premium_badge),
    ];

    $form['attribute_mapping']['mo_keycloak_custom_attribute_mapping']['description'] = [
      '#markup' => '<div class="mo_keycloak_highlight_background">This feature allows you to map the user attributes from your Drupal to Keycloak as well as from Keycloak to Drupal.</div>',
    ];

    $custom_attr_mapping_header = [
      ['data' => $this->t('Drupal Field Machine Name'), 'width' => '35%'],
      ['data' => $this->t('Keycloak Attribute Name'), 'width' => '35%'],
      ['data' => $this->t('Operation'), 'width' => '10%'],
    ];

    $form['attribute_mapping']['mo_keycloak_custom_attribute_mapping']['custom_mappings_table'] = [
      '#type' => 'table',
      '#header' => $custom_attr_mapping_header,
      '#attributes' => ['class' => ['remove_bottom_border']],
    ];

    $form['attribute_mapping']['mo_keycloak_custom_attribute_mapping']['custom_mappings_table']['first_row'] = $this->getProfileMappingRow('custom_mapping', $custom_fields);
    $form['attribute_mapping']['mo_keycloak_custom_attribute_mapping']['attribute_mapping_add_more'] = $this->generateAddButton();

    // Add save button at the bottom of this tab.
    $form['attribute_mapping']['save_configuration'] = [
      '#type' => 'submit',
      '#value' => $this->t('Save Configuration'),
      '#button_type' => 'primary',
      '#attributes' => ['class' => ['button', 'button--primary']],
    ];

    // Role Mapping Tab.
    $form['role_mapping'] = [
      '#type' => 'details',
      '#title' => $this->t('Role Mapping'),
      '#group' => 'mapping_tabs',
    ];

    // Basic Role Mapping Fieldset.
    $premium_badge = ' <span class="premium-badge">PREMIUM</span><hr>';
    $form['role_mapping']['basic_role_mapping'] = [
      '#type' => 'fieldset',
      '#title' => Markup::create($this->t('Basic Role Mapping') . $premium_badge),
    ];

    $form['role_mapping']['basic_role_mapping']['enable_role_mapping'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Enable Role Mapping'),
      '#description' => $this->t('Note : Enable this first if you want to use below features.'),
      '#disabled' => TRUE,
    ];

    $form['role_mapping']['basic_role_mapping']['update_existing_roles'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Update the users existing roles.'),
      '#description' => $this->t('Note : Enable this if you want to update/delete the existing user roles in the Drupal.'),
      '#disabled' => TRUE,
    ];

    $form['role_mapping']['basic_role_mapping']['default_group_heading'] = [
      '#markup' => '<strong>' . $this->t('Select default group for new users') . '</strong>',
    ];

    // Get all Drupal roles (excluding anonymous)
    $role_storage = $this->entityTypeManager->getStorage('user_role');
    $roles = $role_storage->loadMultiple();
    $drupal_roles = [];
    foreach ($roles as $role) {
      if ($role->id() !== 'anonymous') {
        $drupal_roles[$role->id()] = $role->label();
      }
    }

    $form['role_mapping']['basic_role_mapping']['default_group'] = [
      '#type' => 'select',
      '#options' => $drupal_roles,
      '#default_value' => 'authenticated',
      '#description' => $this->t('Note: This role will be assigned to user at the time of user creation in Drupal site.'),
      '#disabled' => TRUE,
    ];

    // Custom Role Mapping Fieldset.
    $premium_badge = ' <span class="premium-badge">PREMIUM</span><hr>';
    $form['role_mapping']['custom_role_mapping'] = [
      '#type' => 'fieldset',
      '#title' => Markup::create($this->t('Custom Role Mapping') . $premium_badge),
    ];

    $form['role_mapping']['custom_role_mapping']['role_attribute'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Role Attribute'),
      '#placeholder' => $this->t('Enter Role Attribute'),
      '#attributes' => ['style' => 'width: 30rem;'],
      '#disabled' => TRUE,
    ];

    $custom_role_mapping_header = [
      ['data' => $this->t('Drupal Roles'), 'width' => '35%'],
      ['data' => $this->t('Keycloak Attribute Value'), 'width' => '35%'],
      ['data' => $this->t('Operation'), 'width' => '10%'],
    ];

    $form['role_mapping']['custom_role_mapping']['custom_role_mappings_table'] = [
      '#type' => 'table',
      '#header' => $custom_role_mapping_header,
      '#attributes' => ['class' => ['remove_bottom_border']],
    ];

    $form['role_mapping']['custom_role_mapping']['custom_role_mappings_table']['first_row'] = $this->getProfileMappingRow('role_mapping', $drupal_roles);
    $form['role_mapping']['custom_role_mapping']['role_mapping_add_more'] = $this->generateAddButton();

    $form['role_mapping']['save_configuration'] = [
      '#type' => 'submit',
      '#value' => $this->t('Save Configuration'),
      '#button_type' => 'primary',
      '#attributes' => ['class' => ['button', 'button--primary']],
    ];

    // Group Mapping Tab.
    $form['group_mapping'] = [
      '#type' => 'details',
      '#title' => $this->t('Group Module Mapping'),
      '#group' => 'mapping_tabs',
    ];

    $form['group_mapping']['select_how_to_map_group'] = [
      '#type' => 'radios',
      '#title' => $this->t('Select how to map group'),
      '#options' => [
        'group_name' => $this->t('Group Name'),
        'user_attribute' => $this->t('User Attribute'),
      ],
      '#default_value' => 'group_name',
    ];

    $premium_badge = ' <span class="premium-badge">PREMIUM</span><hr>';
    $form['group_mapping']['group_module_mapping_fieldset'] = [
      '#type' => 'fieldset',
      '#title' => Markup::create($this->t('Group Module Mapping') . $premium_badge),
      '#states' => [
        'visible' => [
          ':input[name="select_how_to_map_group"]' => ['value' => 'group_name'],
        ],
      ],
    ];

    // Group Mapping Note.
    $form['group_mapping']['group_module_mapping_fieldset']['group_mapping_note'] = [
      '#markup' => '<div class="mo_keycloak_highlight_background"><strong>Note:</strong> Maps user groups from the SCIM provider to Drupal groups by name. If a matching group does not exist, a new one will be created automatically.</div>',
    ];

    $form['group_mapping']['group_module_mapping_fieldset']['enable_group_mapping'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Enable Group Mapping'),
      '#description' => $this->t('<span style="color: red;">Note : Enable this first if you want to use Group Mapping.</span>'),
      '#disabled' => TRUE,
    ];

    // Get group types from Group module.
    $group_types = [];
    if ($this->moduleHandler->moduleExists('group')) {
      $group_type_storage = $this->entityTypeManager->getStorage('group_type');
      $group_type_entities = $group_type_storage->loadMultiple();
      foreach ($group_type_entities as $group_type) {
        $group_types[$group_type->id()] = $group_type->label();
      }
    }

    $form['group_mapping']['group_module_mapping_fieldset']['group_type'] = [
      '#type' => 'select',
      '#title' => $this->t('Group Type'),
      '#options' => $group_types,
      '#default_value' => array_key_first($group_types),
      '#description' => $this->t('Select the group type to use when creating a new group.'),
      '#disabled' => TRUE,
    ];

    $form['group_mapping']['group_module_mapping_fieldset']['drupal_username'] = [
      '#type' => 'entity_autocomplete',
      '#title' => $this->t('Enter the Drupal Username'),
      '#description' => $this->t('Enter the username of the account that will own newly created groups. This is required when the module creates a new group. If no username is provided, the root user (user ID 1) will be set as the owner by default.'),
      '#default_value' => '',
      '#target_type' => 'user',
      '#selection_handler' => 'default:user',
      '#selection_settings' => [
        'include_anonymous' => FALSE,
      ],
      '#attributes' => ['style' => 'width: 30rem;'],
      '#disabled' => TRUE,
    ];

    // User Attribute Mapping Fieldset.
    $premium_badge = ' <span class="premium-badge">PREMIUM</span><hr>';
    $form['group_mapping']['user_attribute_mapping_fieldset'] = [
      '#type' => 'fieldset',
      '#title' => Markup::create($this->t('User Attribute Mapping') . $premium_badge),
      '#states' => [
        'visible' => [
          ':input[name="select_how_to_map_group"]' => ['value' => 'user_attribute'],
        ],
      ],
    ];

    $form['group_mapping']['user_attribute_mapping_fieldset']['description'] = [
      '#markup' => '<div class="mo_keycloak_highlight_background">This mapping allows to map attributes received from the Identity Provider to the fields of Group module.</div>',
    ];

    $form['group_mapping']['user_attribute_mapping_fieldset']['enable_group_mapping'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Enable Group Mapping'),
      '#description' => $this->t('Enable this first if you want to use Group Mapping.'),
      '#disabled' => TRUE,
    ];

    $form['group_mapping']['user_attribute_mapping_fieldset']['keep_existing_groups'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Keep existing groups if groups not mapped below'),
      '#disabled' => TRUE,
    ];

    $form['group_mapping']['user_attribute_mapping_fieldset']['group_attribute_heading'] = [
      '#markup' => '<strong>' . $this->t('Group Attribute') . '</strong>',
    ];

    $form['group_mapping']['user_attribute_mapping_fieldset']['group_attribute'] = [
      '#type' => 'textfield',
      '#placeholder' => $this->t('Enter Group Attribute'),
      '#attributes' => ['style' => 'width: 30rem;'],
      '#disabled' => TRUE,
    ];

    $form['group_mapping']['user_attribute_mapping_fieldset']['group_mapping_settings'] = [
      '#type' => 'fieldset',
      '#title' => $this->t('Group Mapping Settings'),
      '#open' => TRUE,
    ];

    $group_mapping_header = [
      ['data' => $this->t('Drupal Group Name'), 'width' => '35%'],
      ['data' => $this->t('Server Group Name/ID'), 'width' => '35%'],
      ['data' => $this->t('Action'), 'width' => '10%'],
    ];

    $form['group_mapping']['user_attribute_mapping_fieldset']['group_mapping_settings']['group_mappings_table'] = [
      '#type' => 'table',
      '#header' => $group_mapping_header,
      '#attributes' => ['class' => ['remove_bottom_border']],
    ];

    // Get available groups for dropdown.
    $group_options = [];
    if ($this->moduleHandler->moduleExists('group')) {
      $group_storage = $this->entityTypeManager->getStorage('group');
      $groups = $group_storage->loadMultiple();
      foreach ($groups as $group) {
        $group_options[$group->id()] = $group->label();
      }
    }

    $form['group_mapping']['user_attribute_mapping_fieldset']['group_mapping_settings']['group_mappings_table']['first_row'] = $this->getProfileMappingRow('group_mapping', $group_options);

    $form['group_mapping']['user_attribute_mapping_fieldset']['group_mapping_settings']['group_mapping_add_more'] = $this->generateAddButton();

    $premium_badge = ' <span class="premium-badge">PREMIUM</span><hr>';
    $form['group_mapping']['role_group_mapping'] = [
      '#type' => 'fieldset',
      '#title' => Markup::create($this->t('Group Provisioning') . $premium_badge),
    ];

    // Enable Group Provisioning checkbox.
    $form['group_mapping']['role_group_mapping']['enable_group_provisioning'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Enable Group Provisioning'),
      '#description' => $this->t('Enable to allow the SCIM server to synchronize group operations with a SCIM client.'),
      '#disabled' => TRUE,
    ];

    // Group Provisioning Settings fieldset.
    $form['group_mapping']['role_group_mapping']['group_provisioning_settings'] = [
      '#type' => 'fieldset',
      '#title' => $this->t('Group Provisioning Settings'),
    ];

    // Create Groups checkbox.
    $form['group_mapping']['role_group_mapping']['group_provisioning_settings']['create_groups'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Create Groups'),
      '#description' => $this->t('When a new group is created on the SCIM client, a Drupal role with the same name will be created.'),
      '#disabled' => TRUE,
    ];

    // Delete Groups checkbox.
    $form['group_mapping']['role_group_mapping']['group_provisioning_settings']['delete_groups'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Delete Groups'),
      '#description' => $this->t('When a group is deleted on the SCIM client, the corresponding Drupal role will also be deleted.'),
      '#disabled' => TRUE,
    ];

    // Update Groups checkbox.
    $form['group_mapping']['role_group_mapping']['group_provisioning_settings']['update_groups'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Update Groups'),
      '#description' => $this->t('Changes to existing groups (e.g., renaming) on the SCIM client will be applied on this server.'),
      '#disabled' => TRUE,
    ];

    $form['group_mapping']['save_configuration'] = [
      '#type' => 'submit',
      '#value' => $this->t('Save Configuration'),
      '#button_type' => 'primary',
      '#attributes' => ['class' => ['button', 'button--primary']],
    ];

    return $form;
  }

  /**
   * Generate fields for mapping sections.
   */
  private function getProfileMappingRow($mapping_type = '', $custom_fields = '') {
    $row = [];

    if ($mapping_type == 'custom_mapping') {
      $row['drupal_field_name'] = [
        '#type' => 'select',
        '#options' => $custom_fields,
        '#disabled' => TRUE,
      ];
    }
    elseif ($mapping_type == 'role_mapping') {
      $row['drupal_role'] = [
        '#type' => 'select',
        '#options' => $custom_fields,
        '#disabled' => TRUE,
      ];
    }
    elseif ($mapping_type == 'group_mapping') {
      $row['drupal_group_name'] = [
        '#type' => 'select',
        '#options' => $custom_fields,
        '#disabled' => TRUE,
      ];
    }

    if ($mapping_type == 'role_mapping') {
      $row['keycloak_attribute_value'] = [
        '#type' => 'textfield',
        '#disabled' => TRUE,
      ];
    }
    elseif ($mapping_type == 'group_mapping') {
      $row['server_group_name'] = [
        '#type' => 'textfield',
        '#placeholder' => 'Semicolon (;) seperated values',
        '#disabled' => TRUE,
      ];
    }
    else {
      $row['keycloak_attribute_name'] = [
        '#type' => 'textfield',
        '#disabled' => TRUE,
      ];
    }

    $row['delete'] = [
      '#type' => 'button',
      '#value' => $this->t('Delete'),
      '#disabled' => TRUE,
    ];

    return $row;

  }

  /**
   * Generate Add button.
   */
  public function generateAddButton() {
    $form['button_prefix_mapping'] = [
      '#prefix'  => '<div class="container-inline">',
    ];

    $form['button_add'] = [
      '#type' => 'submit',
      '#value' => $this->t('Add'),
      '#disabled' => TRUE,
    ];

    $form['total_rows'] = [
      '#type' => 'number',
      '#disabled' => TRUE,
      '#default_value' => 1,
      '#min' => 1,
      '#max' => 50,
    ];

    $form['rows_markup'] = [
      '#type' => 'item',
      '#markup' => 'more rows',
      '#prefix' => '&nbsp;&nbsp;',
      '#suffix' => '</div>',
    ];
    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {
    $form_values = $form_state->getValues();
    $first_name_attr = $form_values['first_name_attribute'];
    $last_name_attr = $form_values['last_name_attribute'];
    $this->configfactory
      ->set('keycloak_user_provisioning_basic_first_name_mapping', $first_name_attr)
      ->set('keycloak_user_provisioning_basic_last_name_mapping', $last_name_attr)
      ->save();
    // Handle form submission.
    $this->messenger->addMessage($this->t('Configuration has been saved.'));
  }

}
