<?php

namespace Drupal\eb\Plugin\EbOperation;

use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Entity\EntityFieldManagerInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\eb\Attribute\EbOperation;
use Drupal\eb\Exception\ExecutionException;
use Drupal\eb\PluginBase\OperationBase;
use Drupal\eb\Result\ExecutionResult;
use Drupal\eb\Result\PreviewResult;
use Drupal\eb\Result\RollbackResult;
use Drupal\eb\Result\ValidationResult;
use Drupal\eb\Service\DiscoveryServiceInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Operation for deleting entity bundles.
 */
#[EbOperation(
  id: 'delete_bundle',
  label: new TranslatableMarkup('Delete Bundle'),
  description: new TranslatableMarkup('Deletes a bundle and all its fields'),
  operationType: 'delete',
)]
class DeleteBundleOperation extends OperationBase {

  /**
   * Constructor.
   */
  public function __construct(
    array $configuration,
    string $plugin_id,
    mixed $plugin_definition,
    EntityTypeManagerInterface $entityTypeManager,
    LoggerInterface $logger,
    ConfigFactoryInterface $configFactory,
    protected DiscoveryServiceInterface $discoveryService,
    protected EntityFieldManagerInterface $entityFieldManager,
  ) {
    parent::__construct($configuration, $plugin_id, $plugin_definition, $entityTypeManager, $logger, $configFactory);
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition): static {
    /** @var \Psr\Log\LoggerInterface $logger */
    $logger = $container->get('logger.channel.eb');
    return new static(
      $configuration,
      $plugin_id,
      $plugin_definition,
      $container->get('entity_type.manager'),
      $logger,
      $container->get('config.factory'),
      $container->get('eb.discovery_service'),
      $container->get('entity_field.manager'),
    );
  }

  /**
   * {@inheritdoc}
   */
  public function validate(): ValidationResult {
    $result = new ValidationResult();

    $this->validateRequiredFields(['entity_type', 'bundle_id'], $result);

    if (!$result->isValid()) {
      return $result;
    }

    $entity_type = $this->getDataValue('entity_type');
    $bundle_id = $this->getDataValue('bundle_id');

    $validation = $this->discoveryService->validateEntityBundle($entity_type, $bundle_id);
    if (!$validation['valid']) {
      foreach ($validation['errors'] as $error) {
        $result->addError($error, 'bundle_id', 'bundle_not_found');
      }
    }
    else {
      $result->addWarning(
        $this->t('WARNING: Deleting this bundle will delete all content and fields.')
      );
    }

    return $result;
  }

  /**
   * {@inheritdoc}
   */
  public function preview(): PreviewResult {
    $preview = new PreviewResult();

    $entity_type = $this->getDataValue('entity_type');
    $bundle_id = $this->getDataValue('bundle_id');

    $preview->addOperation(
      'delete',
      'bundle',
      $bundle_id,
      $this->t('Delete bundle @bundle from @type', [
        '@bundle' => $bundle_id,
        '@type' => $entity_type,
      ])
    );

    $preview->addDetails([
      'Entity Type' => $entity_type,
      'Bundle ID' => $bundle_id,
      'WARNING' => 'All content and fields will be deleted',
    ]);

    return $preview;
  }

  /**
   * {@inheritdoc}
   */
  public function execute(): ExecutionResult {
    $entity_type = $this->getDataValue('entity_type');
    $bundle_id = $this->getDataValue('bundle_id');

    return $this->executeWithErrorHandling(function () use ($entity_type, $bundle_id) {
      $entity_type_definitions = $this->discoveryService->getAllEntityTypes();
      $bundle_entity_type = $entity_type_definitions[$entity_type]['bundle_entity_type'];

      $bundle_storage = $this->entityTypeManager->getStorage($bundle_entity_type);
      $bundle = $bundle_storage->load($bundle_id);

      if (!$bundle) {
        throw new ExecutionException("Bundle '{$bundle_id}' not found");
      }

      // Store configuration for rollback.
      $bundle_config = $bundle->toArray();

      // Delete the bundle.
      $bundle->delete();

      $this->entityFieldManager->clearCachedFieldDefinitions();

      $result = new ExecutionResult(TRUE);
      $result->addAffectedEntityById($bundle_entity_type, $bundle_id);
      $result->setRollbackData([
        'bundle_entity_type' => $bundle_entity_type,
        'bundle_config' => $bundle_config,
        'entity_type' => $entity_type,
      ]);

      $this->logInfo('Deleted bundle: @bundle', ['@bundle' => $bundle_id]);

      return $result;
    }, 'delete bundle');
  }

  /**
   * {@inheritdoc}
   */
  public function rollback(): RollbackResult {
    $rollback_data = $this->getRequiredRollbackData();

    return $this->rollbackWithErrorHandling(function () use ($rollback_data) {
      $bundle_storage = $this->entityTypeManager->getStorage($rollback_data['bundle_entity_type']);
      $bundle = $bundle_storage->create($rollback_data['bundle_config']);
      $bundle->save();

      $this->entityFieldManager->clearCachedFieldDefinitions();

      $bundle_id = $rollback_data['bundle_config']['id'] ?? 'unknown';
      $this->logInfo('Rolled back bundle deletion: @bundle', ['@bundle' => $bundle_id]);

      $result = new RollbackResult(TRUE);
      $result->addMessage($this->t('Successfully rolled back bundle deletion'));

      return $result;
    }, 'bundle deletion');
  }

}
