<?php

declare(strict_types=1);

namespace Drupal\acquia_dam\Drush\Commands;

use Consolidation\AnnotatedCommand\CommandError;
use Drupal\acquia_dam\AssetUpdater;
use Drupal\acquia_dam\Plugin\media\Source\Asset;
use Drupal\acquia_dam\Service\IntegrationLinksBatchProcessor;
use Drupal\acquia_dam\Service\IntegrationLinksQueueService;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drush\Attributes as CLI;
use Drush\Commands\DrushCommands;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Drush commands for Acquia DAM integration link operations.
 */
final class IntegrationLinksDrushCommands extends DrushCommands {

  use StringTranslationTrait;

  /**
   * Constructs a new IntegrationLinksDrushCommands object.
   *
   * @param \Drupal\acquia_dam\Service\IntegrationLinksQueueService $queueService
   *   The integration links queue service.
   * @param \Drupal\acquia_dam\Service\IntegrationLinksBatchProcessor $batchProcessor
   *   The integration links batch processor service.
   * @param \Drupal\acquia_dam\AssetUpdater $assetUpdater
   *   The asset updater service.
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
   *   The entity type manager.
   */
  public function __construct(
    private readonly IntegrationLinksQueueService $queueService,
    private readonly IntegrationLinksBatchProcessor $batchProcessor,
    private readonly AssetUpdater $assetUpdater,
    private readonly EntityTypeManagerInterface $entityTypeManager,
  ) {
    parent::__construct();
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container): self {
    return new static(
      $container->get('acquia_dam.integration_links_queue_service'),
      $container->get('acquia_dam.integration_links_batch_processor'),
      $container->get('acquia_dam.asset_updater'),
      $container->get('entity_type.manager')
    );
  }

  /**
   * Queue integration link registration for all DAM media items.
   *
   * This command scans all media items that use Acquia DAM assets and queues
   * them for integration link registration with the DAM API.
   *
   * @param array $options
   *   An associative array of options.
   *
   * @command acquia-dam:queue-integration-links
   * @aliases adqil
   *
   * @option batch-size
   *   Number of media items to process in each batch. Defaults to 50.
   * @option media-type
   *   Specific media type to process.
   *   If not specified, all DAM media types will be processed.
   * @usage acquia-dam:queue-integration-links
   *   Queue integration links for all DAM media items.
   * @usage acquia-dam:queue-integration-links --batch-size=100
   *   Queue in batches of 100 items.
   * @usage acquia-dam:queue-integration-links --media-type=acquia_dam_image_asset
   *   Queue only media items of type acquia_dam_image_asset.
   * @help This command queues all DAM media items for integration link
   *   registration. Integration links help DAM track where assets are used
   *   in Drupal. The links will be registered during the next cron run or
   *   when the queue is manually processed.
   */
  #[CLI\Command(name: 'acquia-dam:queue-integration-links', aliases: ['adqil'])]
  #[CLI\Option(name: 'batch-size', description: 'Number of media items to process in each batch')]
  #[CLI\Option(name: 'media-type', description: 'Specific media type to process')]
  #[CLI\Usage(name: 'acquia-dam:queue-integration-links', description: 'Queue integration links for all DAM media items')]
  #[CLI\Usage(name: 'acquia-dam:queue-integration-links --batch-size=100', description: 'Queue in batches of 100 items')]
  #[CLI\Usage(name: 'acquia-dam:queue-integration-links --media-type=acquia_dam_image_asset', description: 'Queue only specific media type')]
  #[CLI\Help(description: 'This command queues all DAM media items for integration
  link registration. Integration links help DAM track where assets are used in
  Drupal. The links will be registered during the next cron run or when the
  queue is manually processed.')]
  public function queueIntegrationLinks(
    array $options = [
      'batch-size' => 50,
      'media-type' => NULL,
    ],
  ) {
    $batch_size = (int) ($options['batch-size'] ?? 50);
    $media_type_filter = $options['media-type'] ?? NULL;

    // Validate batch size.
    if ($batch_size <= 0) {
      return new CommandError('Invalid batch-size. Must be greater than 0.');
    }

    // Validate media type if specified.
    if ($media_type_filter) {
      $error = $this->isValidDamMediaType($media_type_filter);
      if ($error !== NULL) {
        return new CommandError(sprintf('Cannot queue integration links: ' . $error));
      }
    }

    $enhanced_mode = $this->batchProcessor->isEnhancedModeEnabled();
    if ($enhanced_mode) {
      $this->output()->writeln('<info>Enhanced mode enabled - acquia_dam_integration_links submodule detected</info>');
      $this->output()->writeln('<comment>Will process both media entities and content entities with DAM references</comment>');
    }
    else {
      $this->output()->writeln('<info>Basic mode - processing media entities only</info>');
    }
    $this->output()->writeln('');

    // Get all DAM media types using AssetUpdater service.
    $media_types = $this->assetUpdater->getDamMediaTypes($media_type_filter);
    $this->output()->writeln(sprintf('<info>Found %d DAM media type(s): %s</info>',
      count($media_types),
      implode(', ', $media_types)
    ));

    // Process media entities using service.
    $this->output()->writeln('<info>Processing media entities...</info>');

    $media_results = $this->batchProcessor->processMediaEntities(
      $batch_size,
      $media_type_filter,
      function ($media_type_id, $current, $total, $percentage) {
        $this->output()->writeln(sprintf('  %s: batch %d/%d (%d%%)',
          $media_type_id,
          $current,
          $total,
          $percentage
        ));
      }
    );

    // Process content entities if enhanced mode is enabled.
    $content_results = ['content_queued' => 0, 'content_processed' => 0];
    if ($enhanced_mode) {
      $this->output()->writeln('');
      $this->output()->writeln('<info>Processing content entities with DAM references...</info>');

      $content_results = $this->batchProcessor->processContentEntities(
        $batch_size,
        function ($entity_type_id, $current, $total, $percentage) {
          $this->output()->writeln(sprintf('  %s: batch %d/%d (%d%%)',
            $entity_type_id,
            $current,
            $total,
            $percentage
          ));
        }
      );
    }

    // Summary.
    $total_queued = $media_results['total_queued'] + $content_results['content_queued'];
    $total_processed = $media_results['total_processed'] + $content_results['content_processed'];

    $this->output()->writeln('');
    $this->output()->writeln('<info>=== QUEUE SUMMARY ===</info>');
    $this->output()->writeln(sprintf('Total entities processed: <comment>%d</comment>', $total_processed));
    $this->output()->writeln(sprintf('Integration links queued: <comment>%d</comment>', $total_queued));

    if ($enhanced_mode) {
      $this->output()->writeln('<comment>Enhanced mode: Queued links for media + content entities</comment>');
    }

    if ($total_queued > 0) {
      $this->output()->writeln('<info>Integration links have been queued and will be registered during the next cron run or when the queue is manually processed.</info>');
    }
    else {
      $this->output()->writeln('<comment>No integration links were queued. All entities may already have integration links registered.</comment>');
    }
  }

  /**
   * Process the integration links queue.
   *
   * This command processes queued integration link registrations immediately
   * instead of waiting for cron.
   *
   * @param array $options
   *   An associative array of options.
   *
   * @command acquia-dam:process-integration-links-queue
   * @aliases adpilq
   *
   * @option process-limit
   *   Maximum number of queue items to process. Defaults to 0 (no limit).
   * @usage acquia-dam:process-integration-links-queue
   *   Process all queued integration links.
   * @usage acquia-dam:process-integration-links-queue --process-limit=100
   *   Process up to 100 queued integration links.
   * @help This command processes the integration links queue and provides
   *   detailed progress reporting. Use the --process-limit option to control
   *   the number of items processed in a single execution.
   */
  #[CLI\Command(name: 'acquia-dam:process-integration-links-queue', aliases: ['adpilq'])]
  #[CLI\Option(name: 'process-limit', description: 'Maximum number of queue items to process. Defaults to 0 (no limit).')]
  #[CLI\Usage(name: 'acquia-dam:process-integration-links-queue', description: 'Process all queued integration links')]
  #[CLI\Usage(name: 'acquia-dam:process-integration-links-queue --process-limit=100', description: 'Process only the first 100 items')]
  #[CLI\Help(description: 'This command processes the integration links queue and
  provides detailed progress reporting. Use the --process-limit option to control the
  number of items processed in a single execution.')]
  public function processIntegrationLinksQueue(array $options = ['process-limit' => 0]) {
    $limit = (int) ($options['process-limit'] ?? 0);

    // Validate limit parameter.
    if ($limit < 0) {
      return new CommandError('Invalid process-limit. Must be 0 (no limit) or a positive number.');
    }

    $initial_count = $this->queueService->getQueueCount();
    $this->output()->writeln(sprintf('<info>Processing integration links queue (items in queue: %d)</info>', $initial_count));

    if ($initial_count === 0) {
      $this->output()->writeln('<comment>Queue is empty. Nothing to process.</comment>');
      return;
    }

    // Process queue using service with progress callback.
    $results = $this->queueService->processQueue($limit, function ($processed, $failed, $skipped, $remaining) {
      // Show progress every 10 items.
      $this->output()->writeln(sprintf('  Processed: %d | Failed: %d | Skipped: %d | Remaining: %d',
        $processed,
        $failed,
        $skipped,
        $remaining
      ));
    });

    // Final summary.
    $this->output()->writeln('');
    $this->output()->writeln('<info>=== PROCESSING SUMMARY ===</info>');
    $this->output()->writeln(sprintf('Items processed: <comment>%d</comment>', $results['processed']));
    $this->output()->writeln(sprintf('Items failed: <comment>%d</comment>', $results['failed']));
    if ($results['skipped'] > 0) {
      $this->output()->writeln(sprintf('Items skipped (stuck/max retries): <comment>%d</comment>', $results['skipped']));
    }
    $this->output()->writeln(sprintf('Items remaining: <comment>%d</comment>', $results['remaining']));

    if (!empty($results['limit_reached'])) {
      $this->output()->writeln(sprintf('<info>Reached processing limit of %d items.</info>', $limit));
    }

    if ($results['remaining'] > 0) {
      $this->output()->writeln('<comment>There are still items in the queue. Run this command again to continue processing.</comment>');
    }
    else {
      $this->output()->writeln('<info>✓ Queue processing complete!</info>');
    }
  }

  /**
   * Register integration links for all DAM media items (queue and process).
   *
   * This is a convenience command that combines queueing and processing
   * integration links in a single operation.
   *
   * @param array $options
   *   An associative array of options.
   *
   * @command acquia-dam:register-integration-links
   * @aliases adril
   *
   * @option batch-size
   *   Number of media items to process in each batch. Defaults to 50.
   * @option media-type
   *   Specific media type to process.
   * @option process-limit
   *   Maximum number of queue items to process. Defaults to 0 (no limit).
   * @usage acquia-dam:register-integration-links
   *   Queue and register integration links for all DAM media.
   * @usage acquia-dam:register-integration-links --batch-size=100 --process-limit=500
   *   Queue in batches of 100 and process up to 500 items.
   * @usage acquia-dam:register-integration-links --media-type=acquia_dam_image_asset
   *   Register links only for specific media type.
   * @help This command combines queueing and processing of integration links
   *   in a single operation. It first queues all media items for integration
   *   link registration, then immediately processes the queue.
   */
  #[CLI\Command(name: 'acquia-dam:register-integration-links', aliases: ['adril'])]
  #[CLI\Option(name: 'batch-size', description: 'Number of media items to process in each batch')]
  #[CLI\Option(name: 'media-type', description: 'Specific media type to process')]
  #[CLI\Option(name: 'process-limit', description: 'Maximum number of queue items to process')]
  #[CLI\Usage(name: 'acquia-dam:register-integration-links', description: 'Queue and register all integration links')]
  #[CLI\Usage(name: 'acquia-dam:register-integration-links --batch-size=100', description: 'Queue in larger batches')]
  #[CLI\Usage(name: 'acquia-dam:register-integration-links --media-type=acquia_dam_image_asset', description: 'Register links for specific type')]
  #[CLI\Help(description: 'This command combines queueing and processing of
  integration links in a single operation. It first queues all media items for
  integration link registration, then immediately processes the queue.')]
  public function registerIntegrationLinks(
    array $options = [
      'batch-size' => 50,
      'media-type' => NULL,
      'process-limit' => 0,
    ],
  ) {
    $media_type_filter = $options['media-type'] ?? NULL;

    if ((int) ($options['batch-size'] ?? 50) <= 0) {
      return new CommandError('Invalid batch-size. Must be greater than 0.');
    }

    if ((int) ($options['process-limit'] ?? 0) < 0) {
      return new CommandError('Invalid process-limit. Must be 0 (no limit) or a positive number.');
    }

    // Validate media type if specified.
    if ($media_type_filter) {
      $error = $this->isValidDamMediaType($media_type_filter);
      if ($error !== NULL) {
        return new CommandError(sprintf('Cannot queue integration links: ' . $error));
      }
    }

    $this->output()->writeln('<info>=== STEP 1: QUEUEING INTEGRATION LINKS ===</info>');
    $this->output()->writeln('');

    // Step 1: Queue integration links.
    $this->queueIntegrationLinks([
      'batch-size' => $options['batch-size'],
      'media-type' => $options['media-type'],
    ]);

    $this->output()->writeln('');
    $this->output()->writeln('<info>=== STEP 2: PROCESSING QUEUE ===</info>');
    $this->output()->writeln('');

    // Step 2: Process the queue.
    $this->processIntegrationLinksQueue([
      'process-limit' => $options['process-limit'],
    ]);
  }

  /**
   * Validates that a media type exists and is an Acquia DAM media type.
   *
   * @param string $media_type_id
   *   The media type ID to validate.
   *
   * @return string|null
   *   Returns an error message string if invalid, or NULL if valid.
   */
  private function isValidDamMediaType(string $media_type_id): ?string {
    $media_type = $this->entityTypeManager->getStorage('media_type')->load($media_type_id);

    if (!$media_type) {
      return sprintf('The media type "%s" does not exist.', $media_type_id);
    }

    if (!($media_type->getSource() instanceof Asset)) {
      return sprintf('The media type "%s" is not associated with the Acquia DAM source plugin.', $media_type_id);
    }

    return NULL;
  }

}
