<?php

namespace Drupal\dkan_dataset_archiver\Drush\Commands;

use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\dkan_dataset_archiver\Service\ArchiveService;
use Drupal\dkan_dataset_archiver\Service\ProviderService;
use Drush\Attributes as CLI;
use Drush\Commands\DrushCommands;
use Drush\Utils\StringUtils;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Filesystem\Filesystem;

/**
 * Archives Drush command file.
 */
final class ArchiveCommands extends DrushCommands implements ContainerInjectionInterface {

  const YEARS_OF_ARCHIVES = 10;

  /**
   * The provider service.
   *
   * @var \Drupal\dkan_dataset_archiver\Service\ProviderService
   */
  protected $providerService;

  /**
   * The archive service.
   *
   * @var \Drupal\dkan_dataset_archiver\Service\ArchiveService
   */
  private $archiveService;

  /**
   * ProviderCommands constructor.
   *
   * @param \Drupal\dkan_dataset_archiver\Service\ProviderService $providerService
   *   Provider service.
   * @param \Drupal\dkan_dataset_archiver\Service\ArchiveService $archiveService
   *   Archive service.
   */
  public function __construct(ProviderService $providerService, ArchiveService $archiveService) {
    parent::__construct();
    $this->providerService = $providerService;
    $this->archiveService = $archiveService;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('dkan_dataset_archiver.provider_service'),
      $container->get('dkan_dataset_archiver.archive_service')
    );
  }

  /**
   * Fetch all providers' archives from the archive bucket.
   */
  #[CLI\Command(name: 'dkan_dataset_archiver:archive:fetch', aliases: ['get-archive'])]
  #[CLI\Usage(name: 'dkan_dataset_archiver:archive:fetch', description: 'Fetch archives from the archive bucket.')]
  public function fetch() {
    $this->archiveService->fetch();
  }

  /**
   * Archive a provider's current files, either now (default) or later (queue).
   *
   * @param string $ids
   *   (Optional) Any number of comma-separated provider identifiers, no spaces.
   * @param array $options
   *   An array of options. The 'later' option, indicates to do later.
   *
   * @todo Rework this to be about Theme, not provider
   */
  #[CLI\Command(name: 'dkan_dataset_archiver:archive:provider', aliases: [
    'dkan_dataset_archiver:provider:archive',
    'dkan_dataset_archiver:current-zip',
    'dkan_dataset_archiver:current-zip-all',
  ])]
  #[CLI\Argument(name: 'ids', description: '(Optional) Any number of comma-separated provider identifiers, no spaces.')]
  #[CLI\Option(name: 'later', description: 'Archive later rather than now.')]
  #[CLI\Usage(name: 'dkan_dataset_archiver:archive:provider', description: 'Archive current files for every provider.')]
  #[CLI\Usage(name: 'dkan_dataset_archiver:archive:provider home_health', description: "Archive provider home_health's files now.")]
  #[CLI\Usage(name: 'dkan_dataset_archiver:archive:provider --later home_health', description: "Queue the archiving of home_health's files for later processing.")]
  #[CLI\Usage(name: 'dkan_dataset_archiver:archive:provider home_health,hospital', description: "Archive files for multiple providers, separated by a comma, no spaces.")]
  #[CLI\Usage(name: 'dkan_dataset_archiver:archive:provider home_health,hospital', description: "Archive files for multiple providers, separated by a comma, no spaces.")]
  public function archiveProvider(string $ids = '', $options = ['later' => FALSE]) {
    $ids = StringUtils::csvToArray($ids);
    foreach ($this->providerService->get($ids) as $provider) {
      $this->archiveService->scheduleArchiving($provider, $options['later']);
    }
  }

  /**
   * Create annual archives for every providers.
   */
  #[CLI\Command(name: 'dkan_dataset_archiver:archive:annual', aliases: ['dkan_dataset_archiver:annual-archives'])]
  #[CLI\Usage(name: 'dkan_dataset_archiver:archive:annual', description: 'Archive current data of each providers.')]
  public function createAnnualArchives() {
    $this->archiveService->createAnnualArchives();
  }

  /**
   * Create dummy archives to be used for local testing.
   */
  #[CLI\Command(name: 'dkan_dataset_archiver:generate:dummy-archives', aliases: ['dkan_dataset_archiver:generate-dummy-archives'])]
  #[CLI\Usage(name: 'dkan_dataset_archiver:generate:dummy-archives', description: 'Create dummy archives in sites/files/archives to be used for local testing.')]
  public function generateDummyArchives() {
    $archive_dir = DRUPAL_ROOT . '/../src/site/files/archive';
    if (!file_exists($archive_dir)) {
      mkdir($archive_dir);
    }
    // @todo This needs major reworking because topics must not be hardcoded.
    // @todo Maybe we pass a list in via the command line?
    $topics = [
      "Dialysis facilities",
      "Doctors and clinicians",
      "Home health services",
      "Hospice care",
      "Hospitals",
      "Inpatient rehabilitation facilities",
      "Long-term care hospitals",
      "Nursing homes including rehab services",
      "Physician office visit costs",
      "Supplier directory",
    ];
    $current_year = (int) date('Y');

    foreach ($topics as $topic) {
      for ($year = $current_year; $year > $current_year - self::YEARS_OF_ARCHIVES; $year--) {
        $machine_name = strtolower(str_replace(' ', '_', $topic));
        $partial_path = "{$archive_dir}/{$topic}/{$year}/{$machine_name}";
        $this->generateMonthlyTopicArchives($partial_path, $year);
      }
    }
  }

  /**
   * Generate monthly archives for a topic and year.
   *
   * @param string $path
   *   The path to the archive without month and year.
   * @param int $year
   *   The year to generate the monthly archives for.
   */
  private function generateMonthlyTopicArchives(string $path, int $year): void {
    $fs = new Filesystem();
    $current_year = (int) date('Y');
    // For the current year, do not generate future monthly archives.
    $max_month = $year != $current_year ? 12 : (int) date('m');
    // Dummy monthly archives.
    for ($month = 1; $month <= $max_month; $month++) {
      $monthlyArchiveFilename = sprintf("{$path}_%02d_{$year}.zip", $month);
      // Do not overwrite existing archives.
      if (!$fs->exists($monthlyArchiveFilename)) {
        $fs->dumpFile($monthlyArchiveFilename, "");
      }
    }
  }

  /**
   * Create current download-all archives for one or more providers.
   *
   * @param string $ids
   *   (Optional) Any number of comma-separated provider identifiers, no spaces.
   */
  #[CLI\Command(name: 'dkan_dataset_archiver:archive:download-all', aliases: [])]
  #[CLI\Argument(name: 'ids', description: '(Optional) Any number of comma-separated provider identifiers, no spaces.')]
  #[CLI\Usage(name: 'dkan_dataset_archiver:archive::download-all', description: 'Create current download-all zip for every provider.')]
  #[CLI\Usage(name: 'dkan_dataset_archiver:archive:download-all home_health', description: 'Create current download-all zip for Home Health')]
  #[CLI\Usage(name: '@usage dkan_dataset_archiver:archive::download-all home_health,hospital', description: 'Create current download-all zip for multiple providers, separated by a comma, no spaces.')]
  public function currentArchive(string $ids = '') {
    $ids = StringUtils::csvToArray($ids);
    foreach ($this->providerService->get($ids) as $provider) {
      $this->archiveService->createDownloadAll($provider);
    }
  }

  /**
   * Create individual zips for published datasets belonging to providers.
   *
   * @param string $ids
   *   (Optional) Any number of comma-separated provider identifiers, no spaces.
   * @param array $options
   *   An array of options. The 'later' option, indicates to do later.
   */
  #[CLI\Command(name: 'dkan_dataset_archiver:archive:individual-zips', aliases: [])]
  #[CLI\Argument(name: 'ids', description: '(Optional) Any number of comma-separated provider identifiers, no spaces.')]
  #[CLI\Option(name: 'later', description: 'Archive later rather than now.')]
  #[CLI\Usage(name: 'dkan_dataset_archiver:archive:individual-zips', description: 'Create individual zips for published datasets belonging to providers.')]
  public function createIndividualZips(string $ids = '', $options = ['later' => FALSE]) {
    $ids = StringUtils::csvToArray($ids);
    foreach ($this->providerService->get($ids) as $provider) {
      $this->archiveService->createIndividualZips($provider, $options['later']);
    }
  }

  /**
   * Create individual zip for a published dataset by uuid.
   *
   * @param string $uuid
   *   The uuid of the dataset to create the zip for.
   *
   * @command dkan_dataset_archiver:archive:individual-zip-by-uuid
   */
  #[CLI\Command(name: 'dkan_dataset_archiver:archive:individual-zip-by-uuid', aliases: [])]
  #[CLI\Argument(name: 'uuid', description: 'The uuid of the dataset to create the zip for.')]
  #[CLI\Usage(name: 'dkan_dataset_archiver:archive:individual-zip-by-uuid <uuid>', description: 'Create individual zip for a published dataset by uuid.')]
  public function createIndividualZipByUuid(string $uuid) {
    $this->archiveService->createIndividualZipByUuid($uuid);
  }

}
