<?php

declare(strict_types=1);

namespace Drupal\ffmpeg_media\Form;

use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Config\TypedConfigManagerInterface;
use Drupal\Core\Form\ConfigFormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\State\StateInterface;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\ffmpeg_media\Cdn\CdnIntegrationBase;
use Drupal\ffmpeg_media\Cdn\CdnManagerInterface;
use Drupal\ffmpeg_media\Cdn\EndpointValidator;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * CDN integration settings form.
 */
final class CdnSettingsForm extends ConfigFormBase {

  /**
   * State key for S3 access key.
   */
  protected const string STATE_ACCESS_KEY = 'ffmpeg_media.s3_access_key';

  /**
   * State key for S3 secret key.
   */
  protected const string STATE_SECRET_KEY = 'ffmpeg_media.s3_secret_key';

  /**
   * Constructs a CdnSettingsForm object.
   *
   * @param \Drupal\Core\Config\ConfigFactoryInterface $configFactory
   *   The config factory.
   * @param \Drupal\Core\Config\TypedConfigManagerInterface $typedConfigManager
   *   The typed config manager.
   * @param \Drupal\ffmpeg_media\Cdn\CdnManagerInterface $cdnManager
   *   CDN manager service.
   * @param \Drupal\Core\State\StateInterface $state
   *   The state service.
   * @param object|null $keyRepository
   *   Optional Key module repository service for secret references.
   */
  public function __construct(
    ConfigFactoryInterface $configFactory,
    TypedConfigManagerInterface $typedConfigManager,
    protected readonly CdnManagerInterface $cdnManager,
    protected readonly StateInterface $state,
    protected readonly ?object $keyRepository = NULL,
  ) {
    parent::__construct($configFactory, $typedConfigManager);
  }

  /**
   * {@inheritdoc}
   */
  #[\Override]
  public static function create(ContainerInterface $container): static {
    return new static(
      $container->get('config.factory'),
      $container->get('config.typed'),
      $container->get(CdnManagerInterface::class),
      $container->get('state'),
      $container->has('key.repository') ? $container->get('key.repository') : NULL,
    );
  }

  /**
   * {@inheritdoc}
   *
   * @phpstan-return array<int, string>
   */
  #[\Override]
  protected function getEditableConfigNames(): array {
    return ['ffmpeg_media.cdn'];
  }

  /**
   * {@inheritdoc}
   */
  #[\Override]
  public function getFormId(): string {
    return 'ffmpeg_media_cdn_settings';
  }

  /**
   * {@inheritdoc}
   *
   * @phpstan-return array<string, mixed>
   */
  #[\Override]
  public function buildForm(array $form, FormStateInterface $form_state): array {
    $config = $this->config('ffmpeg_media.cdn');

    $form['enabled'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Enable <abbr title="Content Delivery Network">CDN</abbr> integration'),
      '#description' => $this->t('Upload converted files to a CDN for faster delivery.'),
      '#default_value' => $config->get('enabled') ?? FALSE,
    ];

    $form['provider'] = [
      '#type' => 'select',
      '#title' => $this->t('CDN provider'),
      '#options' => $this->cdnManager->getAvailableProviders(),
      '#default_value' => $config->get('provider') ?? 's3',
      '#states' => [
        'visible' => [
          ':input[name="enabled"]' => ['checked' => TRUE],
        ],
      ],
    ];

    // S3 settings.
    $form['s3'] = [
      '#type' => 'details',
      '#title' => $this->t('S3 Configuration'),
      '#description' => $this->t('Works with AWS S3 and any S3-compatible provider (Hetzner Object Storage, DigitalOcean Spaces, Backblaze B2, MinIO). Set a custom endpoint below for non-AWS providers.'),
      '#open' => TRUE,
      '#states' => [
        'visible' => [
          ':input[name="enabled"]' => ['checked' => TRUE],
          ':input[name="provider"]' => ['value' => 's3'],
        ],
      ],
    ];

    $form['s3']['bucket'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Bucket name'),
      '#description' => $this->t('S3 bucket name for storing converted files.'),
      '#default_value' => $config->get('s3.bucket') ?? '',
      '#maxlength' => 63,
    ];

    $form['s3']['region'] = [
      '#type' => 'select',
      '#title' => $this->t('Region'),
      '#description' => $this->t('AWS region or leave empty for custom endpoint.'),
      '#options' => $this->getRegionOptions(),
      '#default_value' => $config->get('s3.region') ?? 'us-east-1',
      '#empty_option' => $this->t('- Custom endpoint -'),
    ];

    $form['s3']['endpoint'] = [
      '#type' => 'url',
      '#title' => $this->t('Custom endpoint'),
      '#description' => $this->t('Custom S3-compatible endpoint URL. Supports Hetzner Object Storage, DigitalOcean Spaces, Backblaze B2, MinIO, and other S3-compatible providers. HTTPS is required.'),
      '#default_value' => $config->get('s3.endpoint') ?? '',
      '#placeholder' => 'https://s3.example.com',
    ];

    $envAccessKey = getenv('FFMPEG_MEDIA_S3_ACCESS_KEY');
    $envSecretKey = getenv('FFMPEG_MEDIA_S3_SECRET_KEY');

    if ($envAccessKey !== FALSE || $envSecretKey !== FALSE) {
      $form['s3']['env_notice'] = [
        '#type' => 'container',
        '#attributes' => ['class' => ['messages', 'messages--status']],
        'message' => ['#plain_text' => $this->t('Credentials loaded from environment variables (FFMPEG_MEDIA_S3_ACCESS_KEY, FFMPEG_MEDIA_S3_SECRET_KEY). Form values are ignored when env vars are set.')],
      ];
    }
    else {
      $form['s3']['env_notice'] = [
        '#type' => 'container',
        '#attributes' => ['class' => ['messages', 'messages--warning']],
        'message' => ['#plain_text' => $this->t('Credentials stored in State API (not exported with config). For production, set FFMPEG_MEDIA_S3_ACCESS_KEY and FFMPEG_MEDIA_S3_SECRET_KEY environment variables instead.')],
      ];
    }

    // Secrets are intentionally not read from exportable config.
    $storedAccessKey = $this->state->get(self::STATE_ACCESS_KEY) ?? '';

    $form['s3']['access_key'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Access key'),
      '#description' => $this->t('S3 access key ID. For production, set the <code>FFMPEG_MEDIA_S3_ACCESS_KEY</code> environment variable.'),
      '#default_value' => $storedAccessKey,
      '#maxlength' => 128,
      '#disabled' => $envAccessKey !== FALSE,
    ];

    $form['s3']['access_key_key'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Access key reference (Key module)'),
      '#description' => $this->t('Optional machine name of a Key module key that contains the S3 access key. Used when no environment variable is set.'),
      '#default_value' => $config->get('s3.access_key_key') ?? '',
      '#maxlength' => 255,
    ];

    $form['s3']['secret_key'] = [
      '#type' => 'password',
      '#title' => $this->t('Secret key'),
      '#description' => $this->t('Leave empty to keep current value. For production, set the <code>FFMPEG_MEDIA_S3_SECRET_KEY</code> environment variable.'),
      '#maxlength' => 128,
      '#disabled' => $envSecretKey !== FALSE,
    ];

    $form['s3']['secret_key_key'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Secret key reference (Key module)'),
      '#description' => $this->t('Optional machine name of a Key module key that contains the S3 secret key. Used when no environment variable is set.'),
      '#default_value' => $config->get('s3.secret_key_key') ?? '',
      '#maxlength' => 255,
    ];

    $form['s3']['path_prefix'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Path prefix'),
      '#description' => $this->t('Prefix for all uploaded files (e.g., ffmpeg_media).'),
      '#default_value' => $config->get('s3.path_prefix') ?? 'ffmpeg_media',
      '#maxlength' => 255,
    ];

    $form['s3']['acl'] = [
      '#type' => 'select',
      '#title' => $this->t('Access control'),
      '#options' => [
        'private' => $this->t('Private'),
        'public-read' => $this->t('Public read'),
        'authenticated-read' => $this->t('Authenticated read'),
      ],
      '#default_value' => $config->get('s3.acl') ?? 'private',
    ];

    $form['s3']['path_style'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Use path-style URLs'),
      '#description' => $this->t('Use path-style URLs instead of virtual-hosted style. Required for some S3-compatible services.'),
      '#default_value' => $config->get('s3.path_style') ?? FALSE,
    ];

    // CDN/CloudFront settings.
    $form['cdn'] = [
      '#type' => 'details',
      '#title' => $this->t('CDN URL Settings'),
      '#open' => FALSE,
      '#states' => [
        'visible' => [
          ':input[name="enabled"]' => ['checked' => TRUE],
        ],
      ],
    ];

    $form['cdn']['cdn_url'] = [
      '#type' => 'url',
      '#title' => $this->t('CDN base URL'),
      '#description' => $this->t('CloudFront or other CDN distribution URL. If set, this URL will be used instead of the S3 URL.'),
      '#default_value' => $config->get('s3.cdn_url') ?? '',
      '#placeholder' => 'https://d1234567890.cloudfront.net',
    ];

    $form['cdn']['cloudfront_distribution_id'] = [
      '#type' => 'textfield',
      '#title' => $this->t('CloudFront distribution ID'),
      '#description' => $this->t('Optional: For cache invalidation when files are updated.'),
      '#default_value' => $config->get('s3.cloudfront_distribution_id') ?? '',
      '#maxlength' => 32,
    ];

    $form['cdn']['url_rewriting'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Enable URL rewriting'),
      '#description' => $this->t('Automatically rewrite local file URLs to CDN URLs.'),
      '#default_value' => $config->get('s3.url_rewriting') ?? FALSE,
    ];

    // Upload settings.
    $form['upload'] = [
      '#type' => 'details',
      '#title' => $this->t('Upload Settings'),
      '#open' => FALSE,
      '#states' => [
        'visible' => [
          ':input[name="enabled"]' => ['checked' => TRUE],
        ],
      ],
    ];

    $form['upload']['auto_upload'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Automatic upload'),
      '#description' => $this->t('Automatically upload converted files to CDN after conversion completes.'),
      '#default_value' => $config->get('auto_upload') ?? TRUE,
    ];

    $form['upload']['delete_local'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Delete local files after upload'),
      '#description' => $this->t('Remove local files after successful CDN upload. Requires URL rewriting to be enabled.'),
      '#default_value' => $config->get('delete_local') ?? FALSE,
    ];

    $form['upload']['upload_outputs'] = [
      '#type' => 'checkboxes',
      '#title' => $this->t('Output types to upload'),
      '#description' => $this->t('Select which output types should be uploaded to CDN.'),
      '#options' => [
        'mp4' => $this->t('MP4'),
        'webm' => $this->t('WebM'),
        'hls' => $this->t('<abbr title="HTTP Live Streaming">HLS</abbr> (m3u8 + segments)'),
        'dash' => $this->t('<abbr title="Dynamic Adaptive Streaming over HTTP">DASH</abbr> (mpd + segments)'),
        'thumbnail' => $this->t('Thumbnails'),
        'gif' => $this->t('GIF'),
      ],
      '#default_value' => $config->get('upload_outputs') ?? ['mp4', 'webm', 'hls', 'dash', 'thumbnail'],
    ];

    // Test connection button.
    $form['test'] = [
      '#type' => 'details',
      '#title' => $this->t('Test Connection'),
      '#open' => FALSE,
      '#states' => [
        'visible' => [
          ':input[name="enabled"]' => ['checked' => TRUE],
        ],
      ],
    ];

    $form['test']['test_connection'] = [
      '#type' => 'submit',
      '#value' => $this->t('Test connection'),
      '#submit' => ['::testConnection'],
      '#limit_validation_errors' => [],
    ];

    return parent::buildForm($form, $form_state);
  }

  /**
   * {@inheritdoc}
   */
  #[\Override]
  public function validateForm(array &$form, FormStateInterface $form_state): void {
    parent::validateForm($form, $form_state);

    if ($form_state->getValue('enabled')) {
      $provider = $form_state->getValue('provider');

      if ($provider === 's3') {
        if (empty($form_state->getValue('bucket'))) {
          $form_state->setErrorByName('bucket', $this->t('Bucket name is required when CDN is enabled.'));
        }

        $accessKeyReference = trim((string) ($form_state->getValue('access_key_key') ?? ''));
        $secretKeyReference = trim((string) ($form_state->getValue('secret_key_key') ?? ''));
        $hasKeyReferences = $accessKeyReference !== '' || $secretKeyReference !== '';
        if ($hasKeyReferences && !$this->hasKeyRepository()) {
          $form_state->setErrorByName('access_key_key', $this->t('Key references require the Key module service (<code>key.repository</code>) to be available.'));
        }
        if ($hasKeyReferences && $this->hasKeyRepository()) {
          if ($accessKeyReference !== '' && $this->resolveKeyValue($accessKeyReference) === NULL) {
            $form_state->setErrorByName('access_key_key', $this->t(
              'Key "@key" could not be resolved. Verify the key exists and has a value.',
              ['@key' => $accessKeyReference],
            ));
          }
          if ($secretKeyReference !== '' && $this->resolveKeyValue($secretKeyReference) === NULL) {
            $form_state->setErrorByName('secret_key_key', $this->t(
              'Key "@key" could not be resolved. Verify the key exists and has a value.',
              ['@key' => $secretKeyReference],
            ));
          }
        }

        // Skip credential validation when env vars provide non-empty values.
        $envAccessKey = getenv('FFMPEG_MEDIA_S3_ACCESS_KEY');
        $envSecretKey = getenv('FFMPEG_MEDIA_S3_SECRET_KEY');

        if (($envAccessKey === FALSE || $envAccessKey === '') && empty($form_state->getValue('access_key')) && $accessKeyReference === '') {
          $form_state->setErrorByName('access_key', $this->t('Access key is required when CDN is enabled.'));
        }

        // Secret key is only required for new configurations without env var.
        $storedSecretKey = $this->state->get(self::STATE_SECRET_KEY) ?? '';
        if (($envSecretKey === FALSE || $envSecretKey === '') && empty($form_state->getValue('secret_key')) && empty($storedSecretKey) && $secretKeyReference === '') {
          $form_state->setErrorByName('secret_key', $this->t('Secret key is required when CDN is enabled.'));
        }

        $region = trim((string) ($form_state->getValue('region') ?? ''));
        $endpoint = trim((string) ($form_state->getValue('endpoint') ?? ''));
        if (empty($region) && empty($endpoint)) {
          $form_state->setErrorByName('region', $this->t('Either region or custom endpoint is required.'));
        }
        $endpointValidationError = $this->getEndpointValidationMessage($endpoint);
        if ($endpointValidationError !== NULL) {
          $form_state->setErrorByName('endpoint', $endpointValidationError);
        }

        $pathPrefix = trim((string) ($form_state->getValue('path_prefix') ?? ''));
        if ($pathPrefix !== '' && (str_contains($pathPrefix, '..') || str_contains($pathPrefix, "\0"))) {
          $form_state->setErrorByName('path_prefix', $this->t('Path prefix must not contain path traversal sequences or null bytes.'));
        }
      }
    }

    // Warn about delete_local without url_rewriting.
    if ($form_state->getValue('delete_local') && !$form_state->getValue('url_rewriting')) {
      $this->messenger()->addWarning($this->t('Deleting local files without URL rewriting enabled may cause broken file references.'));
    }
  }

  /**
   * {@inheritdoc}
   */
  #[\Override]
  public function submitForm(array &$form, FormStateInterface $form_state): void {
    $config = $this->config('ffmpeg_media.cdn');

    $config
      ->set('enabled', (bool) $form_state->getValue('enabled'))
      ->set('provider', $form_state->getValue('provider'))
      ->set('auto_upload', (bool) $form_state->getValue('auto_upload'))
      ->set('delete_local', (bool) $form_state->getValue('delete_local'))
      ->set('upload_outputs', array_filter($form_state->getValue('upload_outputs') ?? []));

    // S3 settings.
    $accessKeyReference = trim((string) ($form_state->getValue('access_key_key') ?? ''));
    $secretKeyReference = trim((string) ($form_state->getValue('secret_key_key') ?? ''));

    $config
      ->set('s3.bucket', $form_state->getValue('bucket'))
      ->set('s3.region', $form_state->getValue('region'))
      ->set('s3.endpoint', $form_state->getValue('endpoint'))
      ->set('s3.path_prefix', $form_state->getValue('path_prefix'))
      ->set('s3.access_key_key', $accessKeyReference)
      ->set('s3.secret_key_key', $secretKeyReference)
      ->set('s3.acl', $form_state->getValue('acl'))
      ->set('s3.path_style', (bool) $form_state->getValue('path_style'))
      ->set('s3.cdn_url', $form_state->getValue('cdn_url'))
      ->set('s3.cloudfront_distribution_id', $form_state->getValue('cloudfront_distribution_id'))
      ->set('s3.url_rewriting', (bool) $form_state->getValue('url_rewriting'))
      ->set('s3.access_key', '')
      ->set('s3.secret_key', '');

    // Store credentials in State API (not exportable) instead of config.
    // Prefer environment variables; skip saving when env vars are set.
    $accessKey = $form_state->getValue('access_key');
    if ($accessKey !== NULL && $accessKey !== '') {
      if (getenv('FFMPEG_MEDIA_S3_ACCESS_KEY') !== FALSE) {
        $this->messenger()->addWarning($this->t('S3 access key not saved because the FFMPEG_MEDIA_S3_ACCESS_KEY environment variable is set. The environment variable takes precedence.'));
      }
      else {
        $this->state->set(self::STATE_ACCESS_KEY, $accessKey);
        $this->messenger()->addStatus($this->t('S3 access key stored in State API (not exported with config). For production, use the FFMPEG_MEDIA_S3_ACCESS_KEY environment variable.'));
      }
    }
    $secretKey = $form_state->getValue('secret_key');
    if (!empty($secretKey)) {
      if (getenv('FFMPEG_MEDIA_S3_SECRET_KEY') !== FALSE) {
        $this->messenger()->addWarning($this->t('S3 secret key not saved because the FFMPEG_MEDIA_S3_SECRET_KEY environment variable is set. The environment variable takes precedence.'));
      }
      else {
        $this->state->set(self::STATE_SECRET_KEY, $secretKey);
        $this->messenger()->addStatus($this->t('S3 secret key stored in State API (not exported with config). For production, use the FFMPEG_MEDIA_S3_SECRET_KEY environment variable.'));
      }
    }

    $config->save();

    parent::submitForm($form, $form_state);
  }

  /**
   * Tests the CDN connection.
   *
   * @param array $form
   *   Form array.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   Form state.
   */
  public function testConnection(array &$form, FormStateInterface $form_state): void {
    $bucket = (string) $form_state->getValue('bucket');
    $region = (string) $form_state->getValue('region');
    $endpoint = (string) $form_state->getValue('endpoint');
    $accessKey = (string) $form_state->getValue('access_key');
    $secretKey = (string) $form_state->getValue('secret_key');
    $accessKeyReference = trim((string) (
      $form_state->getValue('access_key_key')
      ?? $this->config('ffmpeg_media.cdn')->get('s3.access_key_key')
      ?? ''
    ));
    $secretKeyReference = trim((string) (
      $form_state->getValue('secret_key_key')
      ?? $this->config('ffmpeg_media.cdn')->get('s3.secret_key_key')
      ?? ''
    ));

    // Resolve configured Key module references before the State API fallback.
    if ($accessKey === '') {
      $keyAccess = $this->resolveKeyValue($accessKeyReference);
      if ($keyAccess !== NULL) {
        $accessKey = $keyAccess;
      }
      else {
        $accessKey = (string) ($this->state->get(self::STATE_ACCESS_KEY) ?? '');
      }
    }

    // Fall back to stored secret if form field is empty.
    if ($secretKey === '') {
      $keySecret = $this->resolveKeyValue($secretKeyReference);
      if ($keySecret !== NULL) {
        $secretKey = $keySecret;
      }
      else {
        $secretKey = (string) ($this->state->get(self::STATE_SECRET_KEY) ?? '');
      }
    }

    // Resolve env vars (same logic as CdnIntegrationBase).
    $envAccessKey = getenv('FFMPEG_MEDIA_S3_ACCESS_KEY');
    if ($envAccessKey !== FALSE && $envAccessKey !== '') {
      $accessKey = $envAccessKey;
    }
    $envSecretKey = getenv('FFMPEG_MEDIA_S3_SECRET_KEY');
    if ($envSecretKey !== FALSE && $envSecretKey !== '') {
      $secretKey = $envSecretKey;
    }

    if ($bucket === '' || $accessKey === '' || $secretKey === '') {
      $this->messenger()->addError($this->t('Bucket, access key, and secret key are required.'));
      return;
    }

    if ($region === '' && $endpoint === '') {
      $this->messenger()->addError($this->t('Either region or custom endpoint is required.'));
      return;
    }
    $endpointValidationError = $this->getEndpointValidationMessage($endpoint);
    if ($endpointValidationError !== NULL) {
      $this->messenger()->addError($endpointValidationError);
      return;
    }

    // Create integration and inject form values without saving.
    $integration = $this->cdnManager->getIntegration('s3');
    if ($integration === NULL) {
      $this->messenger()->addError($this->t('S3 provider not available.'));
      return;
    }

    if (!$integration instanceof CdnIntegrationBase) {
      $this->messenger()->addError($this->t('S3 provider does not support test configuration.'));
      return;
    }

    // Create a test copy with form values without modifying stored config.
    $testIntegration = $integration->withTestConfig([
      'bucket' => $bucket,
      'region' => $region !== '' ? $region : NULL,
      'endpoint' => $endpoint !== '' ? $endpoint : NULL,
      'access_key' => $accessKey,
      'secret_key' => $secretKey,
      'path_style' => (bool) $form_state->getValue('path_style'),
      'cdn_url' => $form_state->getValue('cdn_url'),
      'acl' => $form_state->getValue('acl') ?? 'private',
    ]);

    $validation = $testIntegration->validateConfiguration();
    if ($validation['valid']) {
      $this->messenger()->addStatus($this->t('CDN connection successful!'));
    }
    else {
      foreach ($validation['errors'] as $error) {
        $this->messenger()->addError($error);
      }
    }
  }

  /**
   * Checks whether Key module repository integration is available.
   */
  private function hasKeyRepository(): bool {
    return $this->keyRepository !== NULL
      && method_exists($this->keyRepository, 'getKey');
  }

  /**
   * Resolves a Key module key value for the provided key machine name.
   *
   * @param string $keyName
   *   Key machine name.
   *
   * @return string|null
   *   Resolved key value or NULL when unavailable.
   */
  private function resolveKeyValue(string $keyName): ?string {
    $keyRepository = $this->keyRepository;
    if ($keyName === '' || $keyRepository === NULL || !method_exists($keyRepository, 'getKey')) {
      return NULL;
    }

    try {
      $key = $keyRepository->getKey($keyName);
    }
    catch (\Throwable) {
      return NULL;
    }

    if (!is_object($key) || !method_exists($key, 'getKeyValue')) {
      return NULL;
    }

    try {
      $value = $key->getKeyValue();
    }
    catch (\Throwable) {
      return NULL;
    }

    return is_string($value) && $value !== '' ? $value : NULL;
  }

  /**
   * Maps endpoint validation failures to user-facing form messages.
   */
  private function getEndpointValidationMessage(string $endpoint): TranslatableMarkup|string|null {
    if ($endpoint === '') {
      return NULL;
    }

    return match (EndpointValidator::validatePublicHttpsEndpoint($endpoint)) {
      EndpointValidator::ERROR_INVALID_FORMAT,
      EndpointValidator::ERROR_INSECURE_SCHEME => $this->t('Custom endpoint must be a valid HTTPS URL.'),
      EndpointValidator::ERROR_NON_PUBLIC_HOST => $this->t('Custom endpoint must use a public host. Localhost, loopback, link-local, and private network addresses are not allowed.'),
      default => NULL,
    };
  }

  /**
   * Gets AWS region options.
   *
   * @return array<string, \Drupal\Core\StringTranslation\TranslatableMarkup>
   *   Region options.
   */
  protected function getRegionOptions(): array {
    return [
      'us-east-1' => $this->t('US East (N. Virginia)'),
      'us-east-2' => $this->t('US East (Ohio)'),
      'us-west-1' => $this->t('US West (N. California)'),
      'us-west-2' => $this->t('US West (Oregon)'),
      'af-south-1' => $this->t('Africa (Cape Town)'),
      'ap-east-1' => $this->t('Asia Pacific (Hong Kong)'),
      'ap-south-1' => $this->t('Asia Pacific (Mumbai)'),
      'ap-south-2' => $this->t('Asia Pacific (Hyderabad)'),
      'ap-southeast-1' => $this->t('Asia Pacific (Singapore)'),
      'ap-southeast-2' => $this->t('Asia Pacific (Sydney)'),
      'ap-southeast-3' => $this->t('Asia Pacific (Jakarta)'),
      'ap-northeast-1' => $this->t('Asia Pacific (Tokyo)'),
      'ap-northeast-2' => $this->t('Asia Pacific (Seoul)'),
      'ap-northeast-3' => $this->t('Asia Pacific (Osaka)'),
      'ca-central-1' => $this->t('Canada (Central)'),
      'eu-central-1' => $this->t('Europe (Frankfurt)'),
      'eu-central-2' => $this->t('Europe (Zurich)'),
      'eu-west-1' => $this->t('Europe (Ireland)'),
      'eu-west-2' => $this->t('Europe (London)'),
      'eu-west-3' => $this->t('Europe (Paris)'),
      'eu-north-1' => $this->t('Europe (Stockholm)'),
      'eu-south-1' => $this->t('Europe (Milan)'),
      'eu-south-2' => $this->t('Europe (Spain)'),
      'me-south-1' => $this->t('Middle East (Bahrain)'),
      'me-central-1' => $this->t('Middle East (UAE)'),
      'il-central-1' => $this->t('Israel (Tel Aviv)'),
      'sa-east-1' => $this->t('South America (São Paulo)'),
      'ca-west-1' => $this->t('Canada (Calgary)'),
      'ap-southeast-4' => $this->t('Asia Pacific (Melbourne)'),
      'ap-southeast-5' => $this->t('Asia Pacific (Malaysia)'),
    ];
  }

}
