<?php

namespace Drupal\user_provisioning\Form;

use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\RedirectCommand;
use Drupal\Core\Ajax\ReplaceCommand;
use Drupal\Core\Config\ImmutableConfig;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Url;
use Drupal\user\Entity\User;
use Drupal\user_provisioning\Helpers\moUserProvisioningLogger;
use Drupal\user_provisioning\moUserProvisioningConstants;
use Drupal\user_provisioning\moUserProvisioningOperationsHandler;

/**
 *
 */
class MoUserProvisioningManualSync extends FormBase {

  /**
   * {@inheritDoc}
   */
  public function getFormId(): string
  {
    return 'mo_provisioning_manual_sync';
  }

  private string $base_url;
  private ImmutableConfig $config;
  private moUserProvisioningLogger $mo_logger;

  /**
   *
   */
  public function __construct() {
    $this->base_url = \Drupal::request()->getSchemeAndHttpHost() . \Drupal::request()->getBaseUrl();
    $this->config = \Drupal::config('user_provisioning.settings');
    $this->messenger = \Drupal::messenger();
    $this->mo_logger = new moUserProvisioningLogger();
  }

  /**
   * {@inheritDoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state): array
  {
    $form['#prefix'] = '<div id="modal_example_form">';
    $form['#suffix'] = '</div>';
    $form['status_messages'] = [
      '#type' => 'status_messages',
      '#weight' => -10,
    ];

    $manual_prov = $this->config->get('manual_provisioning');
    $create_user = $this->config->get('mo_user_provisioning_create_user');

    if ($manual_prov && $create_user) {

      $form['mo_user_prov_manual_sync'] = [
        '#type' => 'table',
        '#responsive' => TRUE,
      ];

      $form['mo_user_prov_manual_sync']['sync_table'] = $this->moProvisioningManualProvTable();
    }
    else {
      $form['mo_user_prov_manual_sync'] = [
        '#markup' => $this->t('It seems that you have not checked the <strong>Manual/On-Demand Provisioning</strong> or <strong>Create user</strong> checkbox. You can enable it in the <a href="provisioning?summary=configuration">Edit Configurations</a> section and then perform the Manual Sync.'),
      ];
    }

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

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

    return $form;
  }

  /**
   * {@inheritDoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {
    // @todo Implement submitForm() method.
  }

  /**
   *
   */
  private function moProvisioningManualProvTable(): array
  {
    $row['drupal_username'] = [
      '#markup' => $this->t('<b>Enter the Drupal Username:</b>'),
    ];

    $row['search_user'] = [
      '#type' => 'entity_autocomplete',
      '#target_type' => 'user',
    ];

    $row['actions']['send'] = [
      '#type' => 'submit',
      '#value' => $this->t('Submit'),
      '#attributes' => [
        'class' => [
          'use-ajax',
          'button--primary',
        ],
      ],
      '#ajax' => [
        'callback' => [$this, 'performProvisionOnDemand'],
        'event' => 'click',
      ],
      '#states' => ['disabled' => [':input[name = "mo_user_prov_manual_sync[sync_table][search_user]"]' => ['value' => '']]],
    ];

    return $row;
  }

  /**
   *
   */
  public function performProvisionOnDemand(array &$form, FormStateInterface $form_state) {
    $configFactory = \Drupal::configFactory()->getEditable('user_provisioning.settings');

    // @todo Provision user or role on-demand
    $response = new AjaxResponse();
    $redirect_to = isset($_SERVER['HTTP_REFERER']) && !empty($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : Url::fromRoute('user_provisioning.provisioning')->toString();

    if ($form_state->hasAnyErrors()) {
      $response->addCommand(new ReplaceCommand('#modal_support_form', $form));
    }
    else {
      $entity_name = trim((string) $form_state->getValues()['mo_user_prov_manual_sync']['sync_table']['search_user']);

      $this->mo_logger->addLog('Provisioning on demand. Entered entity name is :' . $entity_name, __LINE__, __FUNCTION__, __FILE__);
      $entity = User::load($entity_name);

      if (is_null($entity)) {
        $this->messenger->addError('"' . $entity_name . '"' . $this->t(' can not be recognized as a valid User or Role. Enter a valid entity (User or Role) to provision.'));
        $response->addCommand(new RedirectCommand($redirect_to));
        return $response;
      }

      $mo_entity_handler = new moUserProvisioningOperationsHandler($entity);

      try {
        $result = $mo_entity_handler->insert();
        if (is_null($result)) {
          $this->messenger->addError($this->t('An error occurred while provisioning the user, please refer to <a href="' . $this->base_url . moUserProvisioningConstants::DRUPAL_LOGS_PATH . '">drupal logs</a> for more information.'));
          $response->addCommand(new RedirectCommand($redirect_to));
          return $response;
        }
        $this->messenger->addMessage($this->t($entity->label() . ' successfully created at the configured application.'));
      }
      catch (\Exception $exception) {
        if ($exception->getCode() == moUserProvisioningConstants::STATUS_CONFLICT) {
          $this->messenger->addError($this->t('The application has returned 409 conflict i.e., the user already exists at the configured application.'));
        }
        else {
          $this->messenger->addError($exception->getMessage());
        }
        // @todo PUT operation will be called following this event to update the user fields.
      }
    }
    $response->addCommand(new RedirectCommand($redirect_to));
    return $response;
  }

  /**
   *
   */
  private function getEntityToProvision(string $entity_name) {
    $user = user_load_by_name($entity_name);
    return $user && $user->id() ? $user : NULL;
  }

}
