<?php

namespace Drupal\acquia_contenthub\Commands;

use Acquia\ContentHubClient\Settings;
use Drupal\acquia_contenthub\Client\ClientFactory;
use Drupal\acquia_contenthub\Event\AcquiaContentHubSettingsEvent;
use Drupal\acquia_contenthub\EventSubscriber\GetSettings\GetSettingsFromCoreConfig;
use Drupal\acquia_contenthub\EventSubscriber\GetSettings\GetSettingsFromCoreSettings;
use Drupal\acquia_contenthub\EventSubscriber\GetSettings\GetSettingsFromEnvVar;
use Drupal\acquia_contenthub\Settings\ConnectionDetailsInterface;
use Drupal\acquia_contenthub\Settings\ContentHubConfigurationInterface;
use Drupal\Core\Messenger\MessengerInterface;
use Drush\Commands\DrushCommands;
use Psr\Log\LoggerInterface;
use Symfony\Component\Console\Helper\Table;

/**
 * Drush commands for getting the Settings used for Acquia Content Hub.
 *
 * @package Drupal\acquia_contenthub\Commands
 */
class AcquiaContentHubSettingsCommands extends DrushCommands {

  /**
   * The client factory.
   *
   * @var \Drupal\acquia_contenthub\Client\ClientFactory
   */
  protected $clientFactory;

  /**
   * CH configurations.
   *
   * @var \Drupal\acquia_contenthub\Settings\ContentHubConfigurationInterface
   */
  protected ContentHubConfigurationInterface $achConfigurations;

  /**
   * Acquia ContentHub logger channel.
   *
   * @var \Psr\Log\LoggerInterface
   */
  protected $loggerChannel;

  /**
   * Drupal messenger.
   *
   * @var \Drupal\Core\Messenger\MessengerInterface
   */
  protected $messenger;

  /**
   * AcquiaContentHubSiteCommands constructor.
   *
   * @param \Drupal\acquia_contenthub\Client\ClientFactory $client_factory
   *   The client factory.
   * @param \Psr\Log\LoggerInterface $logger_channel
   *   Acquia ContentHub logger channel.
   * @param \Drupal\Core\Messenger\MessengerInterface $messenger
   *   Drupal messenger interface.
   * @param \Drupal\acquia_contenthub\Settings\ContentHubConfigurationInterface $ach_configuration
   *   CH configuration.
   */
  public function __construct(ClientFactory $client_factory, LoggerInterface $logger_channel, MessengerInterface $messenger, ContentHubConfigurationInterface $ach_configuration) {
    $this->clientFactory = $client_factory;
    $this->achConfigurations = $ach_configuration;
    $this->loggerChannel = $logger_channel;
    $this->messenger = $messenger;
  }

  /**
   * Get Content Hub settings.
   *
   * @option $show-secret-key
   *   Show the unmasked secret key in output.
   * @default $show-secret-key false
   *
   * @command acquia:contenthub-settings
   * @aliases ach-chs,acquia-contenthub-settings
   *
   * @usage acquia:contenthub-settings
   *   Displays Content Hub settings with masked secret key.
   * @usage acquia:contenthub-settings --show-secret-key
   *   Displays Content Hub settings with unmasked secret key.
   */
  public function getContentHubSettings(): void {
    $is_config_overridden = FALSE;
    $show_secret_key = $this->input->getOption('show-secret-key');
    $this->output->writeln('Content Hub Credentials being used and if there have been any overrides:');
    $in_use_provider = $this->achConfigurations->getProvider();
    $config_settings = $this->getSettingsFromCoreConfig();
    $core_settings = $this->getSettingsFromCoreSettings();
    $env_var_settings = $this->getSettingsFromEnvVar();
    $content = [];
    foreach ([$config_settings, $core_settings, $env_var_settings] as $setting_obj) {
      $settings = $setting_obj['settings'];
      $provider = $setting_obj['provider'];
      if (($settings instanceof Settings) && !empty($provider)) {
        $content[] = [
          $settings->getUrl() ?? '',
          $settings->getName() ?? '',
          $settings->getApiKey() ?? '',
          $show_secret_key ? $settings->getSecretKey() : '********',
          $settings->getUuid() ?? '',
          $settings->getSharedSecret() ?? '',
          $provider,
          $in_use_provider === $provider ? 'Yes' : 'No',
        ];
      }
    }
    if ($in_use_provider === GetSettingsFromCoreConfig::PROVIDER) {
      // Get CH connection details.
      $ch_connection = $this->achConfigurations->getConnectionDetails();
      /** @var \Acquia\ContentHubClient\Settings $settings_from_config */
      $settings_from_config = $config_settings['settings'];
      $is_config_overridden = $this->isConfigOverridden($settings_from_config, $ch_connection);
      if ($is_config_overridden) {
        $overridden_config = [
          $ch_connection->getOriginal('hostname') !== $settings_from_config->getUrl() ? $ch_connection->getOriginal('hostname') : '-',
          $ch_connection->getOriginal('client_name') !== $settings_from_config->getName() ? $ch_connection->getOriginal('client_name') : '-',
          $ch_connection->getOriginal('api_key') !== $settings_from_config->getApiKey() ? $ch_connection->getOriginal('api_key') : '-',
          $ch_connection->getOriginal('secret_key') !== $settings_from_config->getSecretKey() ? $this->getSecretKey($ch_connection->getOriginal('secret_key'), $show_secret_key) : '-',
          $ch_connection->getOriginal('origin') !== $settings_from_config->getUuid() ? $ch_connection->getOriginal('origin') : '-',
          $ch_connection->getOriginal('shared_secret') !== $settings_from_config->getSharedSecret() ? $ch_connection->getOriginal('shared_secret') : '-',
        ];
        $content[] = $overridden_config;
      }
    }

    $table = new Table($this->output);
    $table
      ->setHeaders([
        'Hostname',
        'Name',
        'API Key',
        'Secret Key',
        'Origin UUID',
        'Shared Secret',
        'Settings Provider',
        'In Use',
      ])
      ->setRows($content);
    if ($is_config_overridden) {
      $table->setFooterTitle('Configuration is being overridden.');
    }
    $table->render();
  }

  /**
   * Get settings from Drupal Configuration.
   *
   * @return array
   *   Array of settings object and settings provider.
   */
  protected function getSettingsFromCoreConfig(): array {
    $event = new AcquiaContentHubSettingsEvent();
    $config_setter = new GetSettingsFromCoreConfig($this->achConfigurations);
    $config_setter->onGetSettings($event);
    return $this->returnSettings($event);
  }

  /**
   * Returns masked or unmasked secret key based on option.
   *
   * @param string $secret_key
   *   Secret key.
   * @param bool $show_secret_key
   *   Whether to show masked secret key or unmasked.
   *
   * @return string
   *   Masked or unmasked secret key.
   */
  protected function getSecretKey(string $secret_key, bool $show_secret_key): string {
    return $show_secret_key ? $secret_key : '********';
  }

  /**
   * Get settings from Drupal Core Settings.
   *
   * @return array
   *   Array of settings object and settings provider.
   */
  protected function getSettingsFromCoreSettings(): array {
    $event = new AcquiaContentHubSettingsEvent();
    $core_settings_setter = new GetSettingsFromCoreSettings();
    $core_settings_setter->onGetSettings($event);
    return $this->returnSettings($event);
  }

  /**
   * Get settings from Environment variables.
   *
   * @return array
   *   Array of settings object and settings provider.
   */
  protected function getSettingsFromEnvVar(): array {
    $event = new AcquiaContentHubSettingsEvent();
    $env_var_setter = new GetSettingsFromEnvVar($this->loggerChannel, $this->messenger);
    $env_var_setter->onGetSettings($event);
    return $this->returnSettings($event);
  }

  /**
   * Extract settings from event.
   *
   * @param \Drupal\acquia_contenthub\Event\AcquiaContentHubSettingsEvent $event
   *   The settings event.
   *
   * @return array
   *   Array of settings object and settings provider.
   */
  protected function returnSettings(AcquiaContentHubSettingsEvent $event): array {
    return [
      'settings' => $event->getSettings(),
      'provider' => $event->getProvider() ?? '',
    ];
  }

  /**
   * Checks if there have been overrides in CH config object.
   *
   * @param \Acquia\ContentHubClient\Settings $settings
   *   Settings coming from Core Config with overrides(if any).
   * @param \Drupal\acquia_contenthub\Settings\ConnectionDetailsInterface $ch_connection
   *   Ch connection details.
   *
   * @return bool
   *   True if config is overridden else false.
   */
  protected function isConfigOverridden(Settings $settings, ConnectionDetailsInterface $ch_connection): bool {
    return (
      ($ch_connection->getOriginal('hostname') !== $settings->getUrl()) ||
      ($ch_connection->getOriginal('client_name') !== $settings->getName()) ||
      ($ch_connection->getOriginal('api_key') !== $settings->getApiKey()) ||
      ($ch_connection->getOriginal('secret_key') !== $settings->getSecretKey()) ||
      ($ch_connection->getOriginal('origin') !== $settings->getUuid()) ||
      ($ch_connection->getOriginal('shared_secret') !== $settings->getSharedSecret())
    );
  }

}
