<?php

namespace Drupal\eb\Form;

use Drupal\Core\File\FileExists;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\TempStore\PrivateTempStoreFactory;
use Drupal\eb\PluginInterfaces\PreviewableOperationInterface;
use Drupal\eb\Service\DefinitionFactory;
use Drupal\eb\Service\OperationBuilder;
use Drupal\eb\Service\OperationDataBuilderInterface;
use Drupal\eb\Service\PreviewGenerator;
use Drupal\eb\Service\ValidationManager;
use Drupal\eb\Service\YamlParser;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Form for uploading and validating entity architecture definitions.
 */
class EbImportForm extends FormBase {

  /**
   * Bytes per megabyte for unit conversion.
   */
  protected const BYTES_PER_MB = 1048576;

  /**
   * Constructor.
   *
   * @param \Drupal\eb\Service\YamlParser $yamlParser
   *   The YAML parser service.
   * @param \Drupal\eb\Service\OperationBuilder $operationBuilder
   *   The operation builder service.
   * @param \Drupal\eb\Service\OperationDataBuilderInterface $operationDataBuilder
   *   The operation data builder service.
   * @param \Drupal\eb\Service\ValidationManager $validationManager
   *   The validation manager service.
   * @param \Drupal\eb\Service\PreviewGenerator $previewGenerator
   *   The preview generator service.
   * @param \Drupal\eb\Service\DefinitionFactory $definitionFactory
   *   The definition factory service.
   * @param \Drupal\Core\TempStore\PrivateTempStoreFactory $tempStoreFactory
   *   The tempstore factory.
   */
  public function __construct(
    protected YamlParser $yamlParser,
    protected OperationBuilder $operationBuilder,
    protected OperationDataBuilderInterface $operationDataBuilder,
    protected ValidationManager $validationManager,
    protected PreviewGenerator $previewGenerator,
    protected DefinitionFactory $definitionFactory,
    protected PrivateTempStoreFactory $tempStoreFactory,
  ) {
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container): self {
    return new self(
      $container->get('eb.yaml_parser'),
      $container->get('eb.operation_builder'),
      $container->get('eb.operation_data_builder'),
      $container->get('eb.validation_manager'),
      $container->get('eb.preview_generator'),
      $container->get('eb.definition_factory'),
      $container->get('tempstore.private'),
    );
  }

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

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state): array {
    $form['help'] = [
      '#type' => 'item',
      '#markup' => $this->t('Upload an entity architecture definition file. By default, the import creates a reusable definition that can be applied later.'),
    ];

    $form['file'] = [
      '#type' => 'file',
      '#title' => $this->t('Architecture Definition File'),
      '#description' => $this->t('Upload a YAML file (.yml or .yaml)'),
      '#required' => TRUE,
    ];

    $form['execute_immediately'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Execute operations immediately after import'),
      '#description' => $this->t('If unchecked, the definition will be saved but not applied. You can apply it later from the definitions list.'),
      '#default_value' => FALSE,
    ];

    $form['force_overwrite'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Overwrite existing definition if ID matches'),
      '#description' => $this->t('If a definition with the same ID already exists, it will be updated instead of creating a new one.'),
      '#default_value' => FALSE,
    ];

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

    $form['actions']['submit'] = [
      '#type' => 'submit',
      '#value' => $this->t('Upload and Validate'),
      '#button_type' => 'primary',
    ];

    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function validateForm(array &$form, FormStateInterface $form_state): void {
    // Drupal 11 uses constraint-based validators.
    $max_file_size = $this->configFactory()->get('eb.settings')->get('import_max_file_size') * self::BYTES_PER_MB;
    $validators = [
      'FileExtension' => ['extensions' => 'yml yaml'],
      'FileSizeLimit' => ['fileLimit' => $max_file_size],
    ];

    $file = file_save_upload('file', $validators, FALSE, 0, FileExists::Replace);

    if (!$file) {
      $form_state->setErrorByName('file', $this->t('Please upload a valid file.'));
      return;
    }

    // Read file content.
    $file_path = $file->getFileUri();
    $content = file_get_contents($file_path);

    if (empty($content)) {
      $form_state->setErrorByName('file', $this->t('The uploaded file is empty.'));
      return;
    }

    // Validate file extension.
    $filename = $file->getFilename();
    if (!$this->yamlParser->validateExtension($filename)) {
      $form_state->setErrorByName('file', $this->t('Invalid file extension. Only .yml and .yaml files are supported.'));
      return;
    }

    // Parse content to definition data.
    try {
      $parsed_data = $this->yamlParser->parse($content);
    }
    catch (\Exception $e) {
      $form_state->setErrorByName(
        'file',
        $this->t('Error parsing file: @message', ['@message' => $e->getMessage()])
      );
      return;
    }

    // Raw data is the same as parsed data (no normalization needed).
    $raw_data = $parsed_data;

    // Convert definition data to operation arrays.
    // OperationDataBuilder handles both core and extension definitions.
    if ($this->operationDataBuilder->isDefinitionFormat($parsed_data)) {
      $operations_data = $this->operationDataBuilder->build($parsed_data);
    }
    else {
      // Data is already in operation format (has 'operation' keys).
      $operations_data = $parsed_data;
    }

    // Build operation plugin instances.
    $operations = $this->operationBuilder->buildBatch($operations_data);

    if (empty($operations)) {
      $form_state->setErrorByName('file', $this->t('No valid operations found in file.'));
      return;
    }

    // Validate operations with batch context awareness.
    $batch_result = $this->validationManager->validateBatch($operations);

    if (!$batch_result->isValid()) {
      $error_messages = [];
      foreach ($batch_result->getErrors() as $error) {
        if (is_array($error)) {
          $error_message = $error['message'] ?? '';
        }
        else {
          $error_message = (string) $error;
        }
        $error_messages[] = $error_message;
      }
      $form_state->setErrorByName('file', implode('<br>', $error_messages));
      return;
    }

    // Generate preview.
    $preview_data = [];
    foreach ($operations as $operation) {
      if ($operation instanceof PreviewableOperationInterface) {
        $preview = $this->previewGenerator->generatePreview($operation);
        $preview_data[] = [
          $operation->getOperationType(),
          $preview->getSummary(),
          $this->t('Ready'),
        ];
      }
    }

    // Create definition from raw YAML to extract metadata.
    $definition = $this->definitionFactory->createFromYaml($raw_data, $file->getFilename());
    $definition_id = $definition->id();

    // Check if definition already exists.
    $force_overwrite = $form_state->getValue('force_overwrite');
    $existing_definition = $this->definitionFactory->loadDefinition($definition_id);
    if ($existing_definition && !$force_overwrite) {
      $form_state->setErrorByName(
            'file', $this->t(
                'A definition with ID "@id" already exists. Enable "Overwrite existing definition" to update it.', [
                  '@id' => $definition_id,
                ]
            )
        );
      return;
    }

    // Store data in form state for submit handler.
    $form_state->set('import_data', [
      'operations' => $operations,
      'preview_data' => $preview_data,
      'filename' => $file->getFilename(),
      'format' => 'yaml',
      'mode' => $form_state->getValue('mode') ?? 'sync',
      'raw_data' => $raw_data,
      'definition_id' => $definition_id,
      'definition_label' => $definition->label(),
      'definition_exists' => $existing_definition !== NULL,
      'execute_immediately' => (bool) $form_state->getValue('execute_immediately'),
      'force_overwrite' => (bool) $force_overwrite,
    ]);
  }

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

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

    // Store in tempstore for the confirm form.
    $tempstore = $this->tempStoreFactory->get('eb_import');
    $tempstore->set('import_data', $import_data);

    // Redirect to confirmation form.
    $form_state->setRedirect('eb.import.confirm');
  }

}
