<?php

namespace Drupal\csc_taxonomy\Drush;

use Drupal\taxonomy\Entity\Term;
use Drush\Attributes as CLI;
use Drush\Commands\DrushCommands;

/**
 * Custom Drush commands for CSC Taxonomy.
 */
final class CscTaxonomyDrushCommands extends DrushCommands {

  /**
   * Command to load data from CSV to taxonomy.
   */
  #[CLI\Command(name: 'csc_taxonomy:load', description: 'Load taxonomy data from CSV')]
  #[CLI\Argument(name: 'taxonomy', description: 'Taxonomy to load: countries, states, or cities')]
  public function loadTaxonomy($taxonomy) {
    if (!in_array($taxonomy, ['countries', 'states', 'cities'])) {
      $this->output()->writeln('Invalid taxonomy. Valid options: countries, states, cities.');
      return;
    }

    $config = $this->getTaxonomyConfig()[$taxonomy];
    $csv_data = $this->readCsv($config['file']);

    if (empty($csv_data)) {
      $this->output()->writeln('Error reading CSV or file does not exist.');
      return;
    }

    if ($taxonomy === 'countries') {
      foreach ($csv_data as $row) {
        if (!$this->getCountryTermId($row[0])) {
          $this->createTerm('countries', $row[1], [$config['id_field'] => $row[0]]);
        }
      }
      $this->output()->writeln('Countries were loaded successfully.');
    }
    else {
      $relations = $this->loadAllTermsByVocabulary($taxonomy === 'states' ? 'countries' : 'states');
      $countries_terms = $taxonomy === 'cities' ? $this->loadAllTermsByVocabulary('countries') : [];

      foreach ($csv_data as $row) {
        $fields = [$config['id_field'] => $row[0]];

        if ($config['reference_field'] && isset($relations[$row[2]])) {
          $fields[$config['reference_field']] = $relations[$row[2]];
        }

        if ($config['needs_country_reference'] && isset($countries_terms[$row[3]])) {
          $fields['field_country_reference'] = $countries_terms[$row[3]];
        }

        $this->createTerm($taxonomy, $row[1], $fields);
      }

      $this->output()->writeln('Data was successfully loaded for: ' . $taxonomy);
    }
  }

  /**
   * Command to delete terms from a taxonomy.
   */
  #[CLI\Command(name: 'csc_taxonomy:delete', description: 'Delete terms from a taxonomy')]
  #[CLI\Argument(name: 'taxonomy', description: 'Taxonomy to delete: countries, states, or cities')]
  public function deleteTaxonomy($taxonomy) {
    if (!in_array($taxonomy, ['countries', 'states', 'cities'])) {
      $this->output()->writeln('Invalid taxonomy. Valid options: countries, states, cities.');
      return;
    }

    $term_ids = \Drupal::entityTypeManager()
      ->getStorage('taxonomy_term')
      ->getQuery()
      ->condition('vid', $taxonomy)
      ->accessCheck(FALSE)
      ->execute();

    if (empty($term_ids)) {
      $this->output()->writeln('No terms found to delete in taxonomy: ' . $taxonomy);
      return;
    }

    $chunks = array_chunk($term_ids, 100);
    $deleted_count = 0;

    foreach ($chunks as $chunk) {
      $this->processDeleteChunk($chunk);
      $deleted_count += count($chunk);
    }

    $this->output()->writeln('Successfully deleted ' . $deleted_count . ' terms from taxonomy: ' . $taxonomy);
  }

  /**
   * Deletes a group of terms.
   */
  protected function processDeleteChunk(array $term_ids) {
    $storage = \Drupal::entityTypeManager()->getStorage('taxonomy_term');
    $terms = $storage->loadMultiple($term_ids);
    $storage->delete($terms);
  }

  /**
   * Reads the CSV from the module directory.
   */
  protected function readCsv(string $file_name): ?array {
    $module_path = \Drupal::service('module_handler')->getModule('csc_taxonomy')->getPath();
    $csv_file_path = $module_path . '/csv/' . $file_name;

    if (!file_exists($csv_file_path)) {
      return NULL;
    }

    $csv_data = [];
    if (($handle = fopen($csv_file_path, 'r')) !== FALSE) {
      $is_first_row = TRUE;

      while (($data = fgetcsv($handle, 1000, ',')) !== FALSE) {
        if ($is_first_row) {
          $is_first_row = FALSE;
          continue;
        }
        $csv_data[] = $data;
      }

      fclose($handle);
    }

    return $csv_data;
  }

  /**
   * Creates a term in the taxonomy.
   */
  protected function createTerm(string $vocabulary, string $name, array $fields = []) {
    $term = Term::create([
      'vid' => $vocabulary,
      'name' => $name,
    ] + $fields);

    $term->save();
  }

  /**
   * Gets the country term ID.
   */
  protected function getCountryTermId($country_id) {
    $terms = \Drupal::entityTypeManager()
      ->getStorage('taxonomy_term')
      ->loadByProperties([
        'vid' => 'countries',
        'field_country_id' => $country_id,
      ]);

    return $terms ? reset($terms)->id() : NULL;
  }

  /**
   * Loads all terms from a vocabulary and indexes them by the corresponding field.
   */
  protected function loadAllTermsByVocabulary($vocabulary_id) {
    $terms = \Drupal::entityTypeManager()
      ->getStorage('taxonomy_term')
      ->loadByProperties(['vid' => $vocabulary_id]);

    $terms_by_field = [];
    foreach ($terms as $term) {
      $field_key = $vocabulary_id === 'countries' ? 'field_country_id' : 'field_state_id';
      $terms_by_field[$term->get($field_key)->value] = $term->id();
    }

    return $terms_by_field;
  }

  /**
   * Centralized taxonomy configuration (same as the form).
   */
  protected function getTaxonomyConfig() {
    return [
      'countries' => [
        'file' => 'countries.csv',
        'id_field' => 'field_country_id',
        'reference_field' => NULL,
        'needs_country_reference' => FALSE,
      ],
      'states' => [
        'file' => 'states.csv',
        'id_field' => 'field_state_id',
        'reference_field' => 'field_country_reference',
        'needs_country_reference' => FALSE,
      ],
      'cities' => [
        'file' => 'cities.csv',
        'id_field' => 'field_city_id',
        'reference_field' => 'field_state_reference',
        'needs_country_reference' => TRUE,
      ],
    ];
  }

}
