<?php

declare(strict_types=1);

namespace Drupal\acquia_dam\Drush\Commands;

use Drupal\acquia_dam\AssetUpdater;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drush\Attributes as CLI;
use Drush\Commands\DrushCommands;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Drush commands for Acquia DAM media item operations.
 */
final class AssetUpdateDrushCommands extends DrushCommands {

  use StringTranslationTrait;

  /**
   * Constructs a new AssetUpdateDrushCommands object.
   *
   * @param \Drupal\acquia_dam\AssetUpdater $assetUpdater
   *   The asset update processor service.
   */
  public function __construct(
    private readonly AssetUpdater $assetUpdater
  ) {
    parent::__construct();
  }

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

  /**
   * Update all DAM media items by checking their assets for changes.
   *
   * This command iterates through all media items that use Acquia DAM assets
   * and checks if they need to be updated based on changes in the DAM.
   *
   * @param array $options
   *   An associative array of options whose values come from cli, aliases,
   *   config, etc.
   *
   * @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-update-assets --batch-size=100
   *   Queue in batches of 100 items.
   * @usage acquia-dam:queue-update-assets --media-type=acquia_dam_image_asset
   *   Queue only media items of type acquia_dam_image_asset.
   * @usage acquia-dam:queue-update-assets --finalized-version
   *   Queue only media items if the finalized version differs.
   */
  #[CLI\Command(name: 'acquia-dam:queue-update-assets', aliases: ['adqua'])]
  #[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: 'finalized-version', description: 'Check and queue media for updates if the finalized version differs.')]
  #[CLI\Usage(name: 'acquia-dam:queue-update-assets', description: 'Update all DAM media items')]
  #[CLI\Usage(name: 'acquia-dam:queue-update-assets --batch-size=100', description: 'Update all DAM media items in batches of 100')]
  #[CLI\Usage(name: 'acquia-dam:queue-update-assets --media-type=acquia_dam_image_asset', description: 'Queue only media items of type acquia_dam_image_asset')]
  #[CLI\Usage(name: 'acquia-dam:queue-update-assets --finalized-version', description: 'Queue only media items if the finalized version differs.')]
  public function queueAssets(array $options = [
    'batch-size' => 50,
    'media-type' => NULL,
    'finalized-version' => false,
  ]): void {
    try {
      $result = $this->assetUpdater->queueAssets($options);

      if (empty($result['media_types'])) {
        $this->output()->writeln('<error>No DAM media types found.</error>');
        return;
      }

      $this->output()->writeln(sprintf('<info>Found %d DAM media type(s): %s</info>',
        count($result['media_types']),
        implode(', ', $result['media_types'])
      ));

      // Summary
      $this->output()->writeln('');
      $this->output()->writeln('<info>=== UPDATE SUMMARY ===</info>');
      $this->output()->writeln(sprintf('Media items verified for update: <comment>%d</comment>', $result['total_processed']));
      $this->output()->writeln(sprintf('Media items queued for update: <comment>%d</comment>', $result['total_updated']));

      if ($result['total_errors'] > 0) {
        $this->output()->writeln(sprintf('Errors encountered: <error>%d</error>', $result['total_errors']));
      }

      if ($result['total_updated'] > 0) {
        $this->output()->writeln('<info>Updates have been queued and will be processed during the next cron run or when the queue is manually processed.</info>');
      }

    }
    catch (\Exception $e) {
      $this->output()->writeln(sprintf('<error>An error occurred: %s</error>', $e->getMessage()));
      $this->logger()->error('Error in DAM update command: @message', ['@message' => $e->getMessage()]);
    }
  }

  /**
   * Process the Acquia DAM asset update queue.
   *
   * This command processes the queued media item updates immediately instead
   * of waiting for cron.
   *
   * @command acquia-dam:process-update-queue
   * @aliases adpuq
   * @option limit
   *   Maximum number of queue items to process. Default to 0 (no limit).
   * @usage acquia-dam:process-update-queue
   *   Process all queued DAM media updates.
   * @usage acquia-dam:process-update-queue --limit=100
   *   Process up to 100 queued DAM media updates.
   * @help This command processes the DAM media update queue and provides
   *   detailed progress reporting, including a summary of processed, failed,
   *   and remaining items. Use the --limit option to control the number of
   *   items processed in a single execution.
   */
  #[CLI\Command(name: 'acquia-dam:process-update-queue', aliases: ['adpuq'])]
  #[CLI\Option(name: 'limit', description: 'Maximum number of queue items to process. Defaults to 0 (no limit).')]
  #[CLI\Usage(name: 'acquia-dam:process-update-queue', description: 'Process all queued DAM media updates.')]
  #[CLI\Usage(name: 'acquia-dam:process-update-queue --limit=100', description: 'Process only the first 100 items from the queue.')]
  #[CLI\Help(description: 'This command processes the DAM media update queue and
      provides detailed progress reporting, including a summary of processed,
      failed, and remaining items. Use the --limit option to control the number
      of items processed in a single execution.')]
  public function processQueue(array $options = ['limit' => 0]): void {
    $result = $this->assetUpdater->processQueue($options);

    $this->output()->writeln(sprintf('<info>Processing DAM media update queue (items in queue: %d)</info>', $result['initial_count']));

    // Show progress during processing
    if ($result['processed'] > 0) {
      for ($i = 10; $i <= $result['processed']; $i += 10) {
        if ($i <= $result['processed']) {
          $this->output()->writeln(sprintf('<comment>Processed %d items...</comment>', min($i, $result['processed'])));
        }
      }
    }

    $this->output()->writeln('');
    $this->output()->writeln('<info>=== QUEUE PROCESSING SUMMARY ===</info>');
    $this->output()->writeln(sprintf('Items processed: <comment>%d</comment>', $result['processed']));
    $this->output()->writeln(sprintf('Remaining items in queue: <comment>%d</comment>', $result['remaining']));

    if ($result['errors'] > 0) {
      $this->output()->writeln(sprintf('Errors encountered: <error>%d</error>', $result['errors']));
    }
  }

  /**
   * Update Acquia DAM assets (queue and process in one command).
   *
   * This command first queues all DAM media items for update, then immediately
   * processes the queue instead of waiting for cron.
   *
   * @command acquia-dam:update-assets
   * @alias adua
   * @option batch-size
   *    Number of media items to process in each batch. Defaults to 50.
   * @option limit
   *    Maximum number of queue items to process. Defaults to 0 (no limit).
   * @option media-type
   *    Specific media type to process. If not specified, all DAM media types will be processed.
   * @usage acquia-dam:update-assets
   *   Queue and process all DAM media updates.
   * @usage acquia-dam:update-assets --batch-size=100 --limit=200
   *   Queue in batches of 100 and process up to 200 items.
   * @usage acquia-dam:update-assets --media-type=acquia_dam_image_asset
   *   Update and process only media items of type acquia_dam_image_asset.
   * @usage acquia-dam:update-assets --finalized-version
   *    Update and process only media items if the finalized version differs.
   * @help This command provides a complete end-to-end asset asset update
   *    workflow by combining queue-assets and process-queue commands. Its the
   *    most convenient way to perform a full asset update of Acquia DAM assets.
   */
  #[CLI\Command(name: 'acquia-dam:update-assets', aliases: ['adua'])]
  #[CLI\Option(name: 'batch-size', description: 'Number of media items to process in each batch')]
  #[CLI\Option(name: 'limit', description: 'Maximum number of queue items to process')]
  #[CLI\Option(name: 'media-type', description: 'Specific media type to process')]
  #[CLI\Option(name: 'finalized-version', description: 'Check and queue media for updates if the finalized version differs.')]
  #[CLI\Usage(name: 'acquia-dam:update-assets', description: 'Queue and process all DAM media updates')]
  #[CLI\Usage(name: 'acquia-dam:update-assets --batch-size=100 --limit=200', description: 'Queue in batches of 100 and process up to 200 items')]
  #[CLI\Usage(name: 'acquia-dam:update-assets --media-type=acquia_dam_image_asset', description: 'Update and process only media items of type acquia_dam_image_asset')]
  #[CLI\Usage(name: 'acquia-dam:update-assets --finalized-version', description: 'Update and process only media items if the finalized version differs')]
  #[CLI\Help(description: 'This command provides a complete end-to-end asset asset update workflow by combining
    the queue-assets and process-queue commands. Its the most convenient way to perform a full asset update of Acquia DAM assets.')]
  public function updateAssets(array $options = [
    'batch-size' => 50,
    'limit' => 0,
    'media-type' => NULL,
    'finalized-version' => false,
  ]): void {
    $this->output()->writeln('<info>=== STARTING DAM ASSET UPDATE AND PROCESSING ===</info>');
    $this->output()->writeln('');

    // Set up progress callback for detailed output
    $progress_callback = function($progress_info) {
      $type_map = [
        'info' => 'info',
        'success' => 'info',
        'comment' => 'comment',
        'error' => 'error',
        'progress' => 'comment',
      ];

      $tag = $type_map[$progress_info['type']] ?? 'info';
      $this->output()->writeln(sprintf('<%s>%s</%s>', $tag, $progress_info['message'], $tag));
    };

    try {
      // Queue assets.
      $queue_result = $this->assetUpdater->queueAssets($options);

      // Display queue results
      if (!empty($queue_result['media_types'])) {
        $this->output()->writeln(sprintf('<info>Found %d DAM media type(s): %s</info>',
          count($queue_result['media_types']),
          implode(', ', $queue_result['media_types'])
        ));

        // Process each media type with progress reporting
        foreach ($queue_result['media_types'] as $media_type) {
          $this->output()->writeln(sprintf('<info>Processing media type: %s</info>', $media_type));
          $this->assetUpdater->processMediaType(
            $media_type,
            (int) $options['batch-size'],
            $options['finalized-version'],
            $progress_callback
          );
        }
      }

      // Process the queue
      $process_result = $this->assetUpdater->processQueue($options);
      // Display process results
      $this->output()->writeln('');
      $this->output()->writeln('<info>=== QUEUE PROCESSING SUMMARY ===</info>');
      $this->output()->writeln(sprintf('Items processed: <comment>%d</comment>', $process_result['processed']));
      $this->output()->writeln(sprintf('Remaining items in queue: <comment>%d</comment>', $process_result['remaining']));

      if ($process_result['errors'] > 0) {
        $this->output()->writeln(sprintf('Errors encountered: <error>%d</error>', $process_result['errors']));
      }

    }
    catch (\Exception $e) {
      $this->output()->writeln(sprintf('<error>An error occurred: %s</error>', $e->getMessage()));
      $this->logger()->error('Error in DAM update command: @message', ['@message' => $e->getMessage()]);
    }

    $this->output()->writeln('');
    $this->output()->writeln('<info>=== DAM ASSET UPDATE AND PROCESSING COMPLETED ===</info>');
  }

}
