<?php

namespace Drupal\dfg_3dviewer\Service;

use Drupal\Core\Config\ConfigFactoryInterface;

/**
 * Applies DFG 3D Viewer module settings to config storage.
 */
class Dfg3dViewerConfigApplier {

  /**
   * All config keys managed by the settings form and configure command.
   */
  public const SETTING_KEYS = [
    'dfg_3dviewer_main_url',
    'dfg_3dviewer_basenamespace',
    'dfg_3dviewer_metadata_url',
    'dfg_3dviewer_json_export_base_url',
    'dfg_3dviewer_container',
    'dfg_3dviewer_entitybundle',
    'dfg_3dviewer_viewer_file_upload',
    'dfg_3dviewer_viewer_file_name',
    'dfg_3dviewer_api_3d_file_field',
    'dfg_3dviewer_image_generation',
    'dfg_3dviewer_field_df',
    'dfg_3dviewer_export_viewer',
    'dfg_3dviewer_export_viewer_url',
    'dfg_3dviewer_lightweight',
    'dfg_3dviewer_scale_container_x',
    'dfg_3dviewer_scale_container_y',
    'dfg_3dviewer_gallery_container',
    'dfg_3dviewer_gallery_image_class',
    'dfg_3dviewer_gallery_image_id',
    'dfg_3dviewer_base_module_path',
    'dfg_3dviewer_entity_id_uri',
    'dfg_3dviewer_view_entity_path',
    'dfg_3dviewer_attribute_id',
  ];

  /**
   * Config keys that must be non-empty when saving settings.
   */
  public const REQUIRED_KEYS = [
    'dfg_3dviewer_main_url',
    'dfg_3dviewer_container',
    'dfg_3dviewer_entitybundle',
    'dfg_3dviewer_viewer_file_upload',
    'dfg_3dviewer_viewer_file_name',
    'dfg_3dviewer_scale_container_x',
    'dfg_3dviewer_scale_container_y',
    'dfg_3dviewer_base_module_path',
    'dfg_3dviewer_view_entity_path',
    'dfg_3dviewer_attribute_id',
  ];

  /**
   * Keys cleared when lightweight mode is enabled.
   */
  public const LIGHTWEIGHT_OPTIONAL_KEYS = [
    'dfg_3dviewer_metadata_url',
    'dfg_3dviewer_json_export_base_url',
    'dfg_3dviewer_api_3d_file_field',
    'dfg_3dviewer_image_generation',
    'dfg_3dviewer_field_df',
    'dfg_3dviewer_export_viewer',
    'dfg_3dviewer_export_viewer_url',
    'dfg_3dviewer_gallery_container',
    'dfg_3dviewer_gallery_image_class',
    'dfg_3dviewer_gallery_image_id',
  ];

  public function __construct(
    protected ConfigFactoryInterface $configFactory,
  ) {}

  /**
   * Returns the local development preset used by the configure command.
   */
  public function getDevPreset(): array {
    return [
      'dfg_3dviewer_main_url' => 'http://dev.wisski.local/',
      'dfg_3dviewer_basenamespace' => '',
      'dfg_3dviewer_metadata_url' => '',
      'dfg_3dviewer_json_export_base_url' => '',
      'dfg_3dviewer_container' => 'DFG_3DViewer',
      'dfg_3dviewer_entitybundle' => 'bd3d7baa74856d141bcff7b4193fa128',
      'dfg_3dviewer_viewer_file_upload' => 'fbf95bddee5160d515b982b3fd2e05f7',
      'dfg_3dviewer_viewer_file_name' => 'faa602a0be629324806aef22892cdbe5',
      'dfg_3dviewer_api_3d_file_field' => '',
      'dfg_3dviewer_image_generation' => '',
      'dfg_3dviewer_field_df' => '',
      'dfg_3dviewer_export_viewer' => '',
      'dfg_3dviewer_export_viewer_url' => '',
      'dfg_3dviewer_lightweight' => TRUE,
      'dfg_3dviewer_scale_container_x' => '1',
      'dfg_3dviewer_scale_container_y' => '1.4',
      'dfg_3dviewer_gallery_container' => '',
      'dfg_3dviewer_gallery_image_class' => '',
      'dfg_3dviewer_gallery_image_id' => '',
      'dfg_3dviewer_base_module_path' => '/libraries/dfg-3dviewer/assets',
      'dfg_3dviewer_entity_id_uri' => '/wisski/navigate/(.*)/view',
      'dfg_3dviewer_view_entity_path' => '/wisski/navigate/',
      'dfg_3dviewer_attribute_id' => 'wisski_id',
    ];
  }

  /**
   * Validates required settings and returns missing keys.
   *
   * @return string[]
   *   Missing required config keys.
   */
  public function validateRequired(array $values): array {
    $missing = [];
    foreach (self::REQUIRED_KEYS as $key) {
      if (!array_key_exists($key, $values) || trim((string) $values[$key]) === '') {
        $missing[] = $key;
      }
    }
    return $missing;
  }

  /**
   * Saves settings to config, mirroring the admin form submit behavior.
   */
  public function apply(array $values): void {
    $values = array_intersect_key($values, array_flip(self::SETTING_KEYS));
    $values = $this->prepareValues($values);
    $missing = $this->validateRequired($values);
    if ($missing !== []) {
      throw new \InvalidArgumentException('Missing required settings: ' . implode(', ', $missing));
    }

    $settings = $this->configFactory->getEditable('dfg_3dviewer.settings');
    foreach ($values as $key => $value) {
      $settings->set($key, $value);
    }
    $settings->save();
  }

  /**
   * Normalizes values before persistence.
   */
  public function prepareValues(array $values): array {
    if (!empty($values['dfg_3dviewer_lightweight'])) {
      foreach (self::LIGHTWEIGHT_OPTIONAL_KEYS as $key) {
        $values[$key] = '';
      }
    }

    if (isset($values['dfg_3dviewer_base_module_path'])) {
      $values['dfg_3dviewer_base_module_path'] = $this->normalizeBaseModulePath((string) $values['dfg_3dviewer_base_module_path']);
    }

    return $values;
  }

  /**
   * Normalizes the viewer module path to a path-first value.
   */
  public function normalizeBaseModulePath(string $value): string {
    $value = trim($value);

    if ($value === '') {
      return $value;
    }

    if (preg_match('@^https?://@i', $value)) {
      $parts = parse_url($value);
      if (!empty($parts['path'])) {
        $value = $parts['path'];
      }
    }
    elseif (preg_match('@^/[^/]+\.[^/]+/.+@', $value)) {
      $segments = array_values(array_filter(explode('/', $value), 'strlen'));
      array_shift($segments);
      $value = '/' . implode('/', $segments);
    }
    elseif (preg_match('@^[^/]+\.[^/]+/.+@', $value)) {
      $segments = explode('/', $value);
      array_shift($segments);
      $value = '/' . implode('/', $segments);
    }

    $value = preg_replace('@/{2,}@', '/', $value);

    if ($value !== '' && $value[0] !== '/') {
      $value = '/' . $value;
    }

    return rtrim($value, '/');
  }

}
