<?php

namespace Drupal\eb\Drush\Commands\Traits;

use Drupal\eb\PluginInterfaces\PreviewableOperationInterface;
use Drupal\eb\Service\PreviewGenerator;

/**
 * Trait for preview display helper methods in Drush commands.
 */
trait PreviewHelperTrait {

  /**
   * The preview generator service.
   */
  protected PreviewGenerator $previewGenerator;

  /**
   * Displays a summary preview for import command (no hint).
   *
   * @param array $operations
   *   Array of operations.
   */
  protected function displayImportSummaryPreview(array $operations): void {
    $this->displaySummaryPreview($operations, FALSE);
  }

  /**
   * Displays a summary preview grouped by entity type and bundle.
   *
   * @param array $operations
   *   Array of operations.
   * @param bool $showHint
   *   Whether to show the --full hint.
   */
  protected function displaySummaryPreview(array $operations, bool $showHint = TRUE): void {
    // Group operations by type for summary table.
    $byType = [];
    // Group by entity type and bundle for detailed breakdown.
    $byEntity = [];
    // Collect all warnings.
    $allWarnings = [];

    foreach ($operations as $operation) {
      $pluginId = $operation->getPluginId();
      $byType[$pluginId] = ($byType[$pluginId] ?? 0) + 1;

      $opData = $operation->getData();
      // Get entity type - varies by operation type.
      $entityType = $opData['entity_type'] ?? 'other';
      // Get bundle ID - 'bundle_id' for bundles or 'bundle' for fields.
      $bundleId = $opData['bundle_id'] ?? $opData['bundle'] ?? NULL;

      // Categorize the operation.
      if (in_array($pluginId, ['create_bundle', 'update_bundle', 'delete_bundle'])) {
        $byEntity[$entityType][$bundleId]['bundle'] = $opData['label'] ?? $bundleId;
        $byEntity[$entityType][$bundleId]['bundle_op'] = $pluginId;
      }
      elseif (in_array($pluginId, ['create_field', 'update_field', 'delete_field'])) {
        $byEntity[$entityType][$bundleId]['fields'] = ($byEntity[$entityType][$bundleId]['fields'] ?? 0) + 1;
      }
      elseif (str_contains($pluginId, 'display') || str_contains($pluginId, 'form_display')) {
        $byEntity[$entityType][$bundleId]['displays'] = ($byEntity[$entityType][$bundleId]['displays'] ?? 0) + 1;
      }
      elseif ($pluginId === 'create_menu') {
        $menuId = $opData['menu_id'] ?? 'unknown';
        $byEntity['menus'][$menuId]['bundle'] = $opData['label'] ?? $menuId;
        $byEntity['menus'][$menuId]['bundle_op'] = $pluginId;
      }
      elseif ($pluginId === 'create_menu_link') {
        $menuId = $opData['menu_id'] ?? 'unknown';
        $byEntity['menus'][$menuId]['links'] = ($byEntity['menus'][$menuId]['links'] ?? 0) + 1;
      }
      elseif (str_contains($pluginId, 'pathauto') || str_contains($pluginId, 'auto_entitylabel')) {
        $byEntity[$entityType][$bundleId]['settings'] = ($byEntity[$entityType][$bundleId]['settings'] ?? 0) + 1;
      }

      // Collect warnings from previewable operations.
      if ($operation instanceof PreviewableOperationInterface) {
        $preview = $this->previewGenerator->generatePreview($operation);
        if ($preview->hasWarnings()) {
          foreach ($preview->getWarnings() as $warning) {
            $allWarnings[] = $warning;
          }
        }
      }
    }

    // Display summary table.
    $this->output()->writeln('');
    $this->output()->writeln('<info>Summary by Operation Type:</info>');
    $this->output()->writeln(str_repeat('-', 45));
    $this->output()->writeln(sprintf('  %-30s %s', 'Operation Type', 'Count'));
    $this->output()->writeln(str_repeat('-', 45));

    $total = 0;
    ksort($byType);
    foreach ($byType as $type => $count) {
      $label = $this->formatPluginIdLabel($type);
      $this->output()->writeln(sprintf('  %-30s %5d', $label, $count));
      $total += $count;
    }

    $this->output()->writeln(str_repeat('-', 45));
    $this->output()->writeln(sprintf('  %-30s %5d', 'Total', $total));
    $this->output()->writeln('');

    // Display grouped by entity type.
    $this->output()->writeln('<info>Breakdown by Entity Type:</info>');
    $this->output()->writeln('');

    // Define display order.
    $entityOrder = ['taxonomy_term', 'node', 'paragraph', 'media', 'user', 'menus', 'roles'];
    $sortedEntities = [];

    foreach ($entityOrder as $entityType) {
      if (isset($byEntity[$entityType])) {
        $sortedEntities[$entityType] = $byEntity[$entityType];
        unset($byEntity[$entityType]);
      }
    }
    // Append any remaining entity types.
    $sortedEntities = array_merge($sortedEntities, $byEntity);

    foreach ($sortedEntities as $entityType => $bundles) {
      $entityLabel = $this->formatEntityTypeLabel($entityType);
      $this->output()->writeln(sprintf('<comment>%s:</comment>', $entityLabel));

      foreach ($bundles as $bundleId => $info) {
        $bundleLabel = $info['bundle'] ?? $bundleId;
        $parts = [];

        if (isset($info['fields']) && $info['fields'] > 0) {
          $parts[] = $info['fields'] . ' field' . ($info['fields'] > 1 ? 's' : '');
        }
        if (isset($info['displays']) && $info['displays'] > 0) {
          $parts[] = $info['displays'] . ' display' . ($info['displays'] > 1 ? 's' : '');
        }
        if (isset($info['links']) && $info['links'] > 0) {
          $parts[] = $info['links'] . ' link' . ($info['links'] > 1 ? 's' : '');
        }
        if (isset($info['settings']) && $info['settings'] > 0) {
          $parts[] = $info['settings'] . ' setting' . ($info['settings'] > 1 ? 's' : '');
        }

        $details = !empty($parts) ? ' (' . implode(', ', $parts) . ')' : '';
        $this->output()->writeln(sprintf('  - %s%s', $bundleLabel, $details));
      }
      $this->output()->writeln('');
    }

    // Display warnings if any.
    if (!empty($allWarnings)) {
      $this->output()->writeln('<error>Warnings:</error>');
      $uniqueWarnings = array_unique($allWarnings);
      foreach ($uniqueWarnings as $warning) {
        $this->output()->writeln(sprintf('  ⚠ %s', $warning));
      }
      $this->output()->writeln('');
    }

    if ($showHint) {
      $this->output()->writeln('<info>Use --full to see detailed list of all operations.</info>');
    }
  }

  /**
   * Displays verbose preview with all operations listed.
   *
   * @param array $operations
   *   Array of operations.
   */
  protected function displayVerbosePreview(array $operations): void {
    $operationNumber = 0;
    foreach ($operations as $operation) {
      $operationNumber++;
      // Only generate verbose previews for operations that support it.
      if ($operation instanceof PreviewableOperationInterface) {
        $preview = $this->previewGenerator->generatePreview($operation);
        $this->output()->writeln('');
        $this->output()->writeln(sprintf('Operation %d:', $operationNumber));
        $this->output()->writeln(sprintf('  Type: %s', $preview->getOperationType()));
        $this->output()->writeln(sprintf('  Summary: %s', $preview->getSummary()));

        if (!empty($preview->getWarnings())) {
          $this->output()->writeln('  Warnings:');
          foreach ($preview->getWarnings() as $warning) {
            $this->output()->writeln(sprintf('    - %s', $warning));
          }
        }
      }
    }
  }

  /**
   * Formats a plugin ID into a human-readable label.
   *
   * @param string $pluginId
   *   The plugin ID.
   *
   * @return string
   *   Human-readable label.
   */
  protected function formatPluginIdLabel(string $pluginId): string {
    return ucwords(str_replace('_', ' ', $pluginId));
  }

  /**
   * Formats an entity type into a human-readable label.
   *
   * @param string $entityType
   *   The entity type.
   *
   * @return string
   *   Human-readable label.
   */
  protected function formatEntityTypeLabel(string $entityType): string {
    $labels = [
      'taxonomy_term' => 'Taxonomy Vocabularies',
      'node' => 'Content Types',
      'paragraph' => 'Paragraph Types',
      'media' => 'Media Types',
      'user' => 'User',
      'menus' => 'Menus',
      'roles' => 'Roles',
    ];

    return $labels[$entityType] ?? ucwords(str_replace('_', ' ', $entityType));
  }

}
