<?php

namespace Drupal\eb\Form;

use Drupal\Component\Datetime\TimeInterface;
use Drupal\Core\Form\ConfirmFormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\Core\TempStore\PrivateTempStoreFactory;
use Drupal\Core\Url;
use Drupal\eb\Service\DefinitionFactory;
use Drupal\eb\Service\EbLogManagerInterface;
use Drupal\eb\Service\OperationProcessor;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Confirmation form for importing entity architecture definitions.
 */
class EbImportConfirmForm extends ConfirmFormBase {

  /**
   * The tempstore data.
   *
   * @var array|null
   */
  protected ?array $tempstoreData = NULL;

  /**
   * Constructor.
   *
   * @param \Drupal\Core\TempStore\PrivateTempStoreFactory $tempStoreFactory
   *   The tempstore factory.
   * @param \Drupal\eb\Service\OperationProcessor $operationProcessor
   *   The operation processor service.
   * @param \Drupal\eb\Service\EbLogManagerInterface $ebLogManager
   *   The EbLog manager service.
   * @param \Drupal\Component\Datetime\TimeInterface $time
   *   The time service.
   * @param \Drupal\eb\Service\DefinitionFactory $definitionFactory
   *   The definition factory service.
   */
  public function __construct(
    protected PrivateTempStoreFactory $tempStoreFactory,
    protected OperationProcessor $operationProcessor,
    protected EbLogManagerInterface $ebLogManager,
    protected TimeInterface $time,
    protected DefinitionFactory $definitionFactory,
  ) {
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container): self {
    return new self(
          $container->get('tempstore.private'),
          $container->get('eb.operation_processor'),
          $container->get('eb.eb_log_manager'),
          $container->get('datetime.time'),
          $container->get('eb.definition_factory'),
      );
  }

  /**
   * {@inheritdoc}
   */
  public function getFormId(): string {
    return 'eb_import_confirm_form';
  }

  /**
   * {@inheritdoc}
   */
  public function getQuestion() {
    $data = $this->getTempstoreData();
    $label = $data['definition_label'] ?? 'Unknown';
    return $this->t('Import definition %name?', ['%name' => $label]);
  }

  /**
   * {@inheritdoc}
   */
  public function getDescription(): TranslatableMarkup {
    $data = $this->getTempstoreData();
    if (!$data) {
      return $this->t('No import data found. Please start the import process again.');
    }

    $operations = $data['operations'] ?? [];
    $execute_immediately = $data['execute_immediately'] ?? FALSE;
    $definition_exists = $data['definition_exists'] ?? FALSE;

    $parts = [];
    $parts[] = $this->t('@count operation(s) will be saved.', [
      '@count' => count($operations),
    ]);

    if ($definition_exists) {
      $parts[] = $this->t('An existing definition will be updated.');
    }
    else {
      $parts[] = $this->t('A new definition will be created.');
    }

    if ($execute_immediately) {
      $parts[] = $this->t('<strong>Operations will be executed immediately.</strong>');
    }

    return $this->t('@description', ['@description' => implode(' ', $parts)]);
  }

  /**
   * {@inheritdoc}
   */
  public function getCancelUrl() {
    return new Url('eb.import');
  }

  /**
   * {@inheritdoc}
   */
  public function getConfirmText() {
    $data = $this->getTempstoreData();
    $execute_immediately = $data['execute_immediately'] ?? FALSE;

    return $execute_immediately
        ? $this->t('Save and Execute')
        : $this->t('Save Definition');
  }

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state): array {
    $data = $this->getTempstoreData();

    if (!$data) {
      $this->messenger()->addError($this->t('No import data found. Please upload a file first.'));
      return $this->redirect('eb.import')->send() ? [] : $form;
    }

    $form = parent::buildForm($form, $form_state);

    // Definition info section.
    $form['definition_info'] = [
      '#type' => 'details',
      '#title' => $this->t('Definition Details'),
      '#open' => TRUE,
      '#weight' => -10,
    ];

    $definition_id = $data['definition_id'] ?? '';
    $definition_label = $data['definition_label'] ?? '';
    $definition_exists = $data['definition_exists'] ?? FALSE;

    $status_message = $definition_exists
        ? $this->t('Update existing')
        : $this->t('Create new');

    $form['definition_info']['details'] = [
      '#theme' => 'item_list',
      '#items' => [
        $this->t('<strong>ID:</strong> @id', ['@id' => $definition_id]),
        $this->t('<strong>Label:</strong> @label', ['@label' => $definition_label]),
        $this->t('<strong>Status:</strong> @status', ['@status' => $status_message]),
      ],
    ];

    // Preview section.
    $form['preview'] = [
      '#type' => 'details',
      '#title' => $this->t('Operations Preview'),
      '#open' => TRUE,
      '#weight' => 0,
    ];

    $preview_data = $data['preview_data'] ?? [];
    $operations = $data['operations'] ?? [];

    $form['preview']['summary'] = [
      '#markup' => $this->t(
          '<p><strong>@count operations</strong> will be processed.</p>', [
            '@count' => count($operations),
          ]
      ),
    ];

    if (!empty($preview_data)) {
      $form['preview']['operations'] = [
        '#type' => 'table',
        '#header' => [
          $this->t('Operation'),
          $this->t('Description'),
          $this->t('Status'),
        ],
        '#rows' => $preview_data,
      ];
    }

    // Execution mode indicator.
    $execute_immediately = $data['execute_immediately'] ?? FALSE;
    if ($execute_immediately) {
      $form['execution_notice'] = [
        '#type' => 'container',
        '#attributes' => ['class' => ['messages', 'messages--warning']],
        '#weight' => 5,
        'message' => [
          '#markup' => $this->t('Operations will be executed immediately after the definition is saved. This will modify your Drupal site configuration.'),
        ],
      ];
    }
    else {
      $form['save_notice'] = [
        '#type' => 'container',
        '#attributes' => ['class' => ['messages', 'messages--status']],
        '#weight' => 5,
        'message' => [
          '#markup' => $this->t('The definition will be saved but not applied. You can apply it later from the definitions list.'),
        ],
      ];
    }

    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state): void {
    $data = $this->getTempstoreData();

    if (!$data) {
      $this->messenger()->addError($this->t('No import data found.'));
      $form_state->setRedirectUrl($this->getCancelUrl());
      return;
    }

    $operations = $data['operations'] ?? [];
    $raw_data = $data['raw_data'] ?? [];
    $definition_id = $data['definition_id'] ?? '';
    $definition_exists = $data['definition_exists'] ?? FALSE;
    $execute_immediately = $data['execute_immediately'] ?? FALSE;
    $filename = $data['filename'] ?? 'unknown';

    if (empty($operations)) {
      $this->messenger()->addError($this->t('No operations to execute.'));
      $this->clearTempstore();
      $form_state->setRedirectUrl($this->getCancelUrl());
      return;
    }

    // Create or update the definition entity.
    try {
      if ($definition_exists) {
        $existing_definition = $this->definitionFactory->loadDefinition($definition_id);
        if ($existing_definition) {
          $definition = $this->definitionFactory->updateFromYaml($existing_definition, $raw_data);
        }
        else {
          $definition = $this->definitionFactory->createFromYaml($raw_data, $filename);
        }
      }
      else {
        $definition = $this->definitionFactory->createFromYaml($raw_data, $filename);
      }

      $definition->save();
      $this->messenger()->addStatus(
            $this->t(
                'Definition "@id" saved successfully.', [
                  '@id' => $definition->id(),
                ]
            )
        );
    }
    catch (\Exception $e) {
      $this->messenger()->addError(
            $this->t(
                'Failed to save definition: @error', [
                  '@error' => $e->getMessage(),
                ]
            )
        );
      $this->clearTempstore();
      $form_state->setRedirectUrl($this->getCancelUrl());
      return;
    }

    // If not executing immediately, redirect to definition page.
    if (!$execute_immediately) {
      $this->clearTempstore();
      $this->messenger()->addStatus(
            $this->t(
                'You can apply this definition from the <a href="@url">definitions list</a>.', [
                  '@url' => Url::fromRoute('entity.eb_definition.collection')->toString(),
                ]
            )
        );
      $form_state->setRedirectUrl(Url::fromRoute('entity.eb_definition.collection'));
      return;
    }

    // Log import start.
    $eb_log = $this->ebLogManager->log([
      'label' => $filename . ' (import)',
      'definition_id' => $definition->id(),
      'action' => 'import',
      'operation_count' => count($operations),
      'status' => 'pending',
    ]);

    // Execute operations with definition context for rollback grouping.
    $context = ['definition_id' => $definition->id()];
    $results = $this->operationProcessor->executeBatch($operations, TRUE, $context);

    // Display results and count successes/failures.
    $success_count = 0;
    $error_count = 0;
    $errors = [];

    foreach ($results as $result) {
      if ($result->isSuccess()) {
        $success_count++;
      }
      else {
        $error_count++;
        foreach ($result->getErrors() as $error) {
          $this->messenger()->addError($error);
          $errors[] = $error;
        }
      }
    }

    // Determine final status.
    $status = 'success';
    if ($error_count > 0 && $success_count === 0) {
      $status = 'failed';
    }
    elseif ($error_count > 0 && $success_count > 0) {
      $status = 'partial';
    }

    // Update history record.
    $this->ebLogManager->complete($eb_log, $status, $success_count, $error_count);

    // Mark definition as applied if successful.
    if ($error_count === 0) {
      $definition->markAsApplied();
      $definition->save();
    }

    if ($success_count > 0) {
      $this->messenger()->addStatus(
            $this->t(
                'Successfully executed @count operations.', [
                  '@count' => $success_count,
                ]
            )
        );
    }

    if ($error_count > 0) {
      $this->messenger()->addError(
            $this->t(
                '@count operations failed.', [
                  '@count' => $error_count,
                ]
            )
        );
    }

    // Clear tempstore and redirect.
    $this->clearTempstore();
    $form_state->setRedirectUrl(Url::fromRoute('entity.eb_definition.collection'));
  }

  /**
   * Gets the tempstore data.
   *
   * @return array|null
   *   The tempstore data or NULL if not found.
   */
  protected function getTempstoreData(): ?array {
    if ($this->tempstoreData === NULL) {
      $tempstore = $this->tempStoreFactory->get('eb_import');
      $this->tempstoreData = $tempstore->get('import_data');
    }
    return $this->tempstoreData;
  }

  /**
   * Clears the tempstore data.
   */
  protected function clearTempstore(): void {
    $tempstore = $this->tempStoreFactory->get('eb_import');
    $tempstore->delete('import_data');
    $this->tempstoreData = NULL;
  }

}
