<?php
namespace PayCal\Connector;

defined('ABSPATH') || exit;

class ConnectorStore {
  private const OPTION = 'paycal_connector_settings';
  private const VERSION_OPTION = 'paycal_connector_settings_version';
  private const BASENAME_OPTION = 'paycal_connector_plugin_basename';
  private const DIAGNOSTICS_OPTION = 'paycal_connector_update_diagnostics';

  public static function defaults(): array {
    return [
      'platform_url' => 'https://paycal.online',
      'checkout_base_url' => 'https://pay.aspaclaria.co.il',
      'use_checkout_sessions' => 'no',
      'merchant_id' => '',
      'public_key' => '',
      'terminal_id' => '',
      'mode' => 'production',
      'last_sync' => '',
      'access_token' => '',
    ];
  }

  public static function get(): array {
    $saved = get_option(self::OPTION, []);
    return wp_parse_args(is_array($saved) ? $saved : [], self::defaults());
  }

  public static function maybe_migrate(): void {
    $saved = get_option(self::OPTION, null);
    $previous_version = (string) get_option(self::VERSION_OPTION, '');
    $current_version = defined('PAYCAL_VERSION') ? PAYCAL_VERSION : 'unknown';
    $previous_basename = (string) get_option(self::BASENAME_OPTION, '');
    $current_basename = self::plugin_basename();
    $before = self::diagnostic_snapshot($saved, 'before_migration');
    $legacy = self::legacy_settings();
    self::maybe_migrate_license_data();

    if (!is_array($saved)) {
      $initial = !empty($legacy) ? self::sanitize_settings($legacy, self::defaults()) : self::defaults();
      update_option(self::OPTION, $initial, false);
      update_option(self::VERSION_OPTION, $current_version, false);
      update_option(self::BASENAME_OPTION, $current_basename, false);
      self::record_diagnostic($before, self::diagnostic_snapshot($initial, !empty($legacy) ? 'after_migration_recovered_legacy' : 'after_migration_created_defaults'), !empty($legacy) ? 'recovered_legacy_settings' : 'created_defaults');
      return;
    }

    $merged = self::merge_preserving_current($saved, $legacy);
    $merged = wp_parse_args($merged, self::defaults());
    $clean = array_merge($saved, self::sanitize_settings($merged, $saved));

    if ($clean !== $saved) {
      update_option(self::OPTION, $clean, false);
    }

    update_option(self::VERSION_OPTION, $current_version, false);
    update_option(self::BASENAME_OPTION, $current_basename, false);

    if ($previous_version !== $current_version || $previous_basename !== $current_basename || $clean !== $saved || empty(self::last_diagnostics())) {
      self::record_diagnostic($before, self::diagnostic_snapshot($clean, 'after_migration_preserved_settings'), $clean !== $saved ? 'merged_missing_defaults_or_legacy' : 'no_change');
    }
  }

  public static function save(array $data): void {
    $current = self::get();
    $clean = self::sanitize_settings($data, $current);
    update_option(self::OPTION, $clean, false);
  }

  private static function sanitize_settings(array $data, array $current): array {
    $mode = (string) ($data['mode'] ?? $current['mode'] ?? 'production');
    if (!in_array($mode, ['production', 'sandbox'], true)) {
      $mode = 'production';
    }

    return [
      'platform_url' => esc_url_raw((string) ($data['platform_url'] ?? $current['platform_url'] ?? '')),
      'checkout_base_url' => esc_url_raw((string) ($data['checkout_base_url'] ?? $current['checkout_base_url'] ?? '')),
      'use_checkout_sessions' => (($data['use_checkout_sessions'] ?? $current['use_checkout_sessions'] ?? 'no') === 'yes') ? 'yes' : 'no',
      'merchant_id' => sanitize_text_field((string) ($data['merchant_id'] ?? $current['merchant_id'] ?? '')),
      'public_key' => sanitize_text_field((string) ($data['public_key'] ?? $current['public_key'] ?? '')),
      'terminal_id' => sanitize_text_field((string) ($data['terminal_id'] ?? $current['terminal_id'] ?? '')),
      'mode' => $mode,
      'last_sync' => sanitize_text_field((string) ($data['last_sync'] ?? $current['last_sync'] ?? '')),
      'access_token' => sanitize_text_field((string) ($data['access_token'] ?? $current['access_token'] ?? '')),
    ];
  }

  private static function merge_preserving_current(array $current, array $fallback): array {
    $merged = $current;
    foreach (self::defaults() as $key => $default) {
      $current_value = $merged[$key] ?? '';
      $fallback_value = $fallback[$key] ?? '';
      if (self::is_empty_setting($current_value) && !self::is_empty_setting($fallback_value)) {
        $merged[$key] = $fallback_value;
      }
    }
    return $merged;
  }

  private static function is_empty_setting($value): bool {
    return $value === null || $value === '' || $value === [];
  }

  private static function legacy_settings(): array {
    $candidates = [];
    foreach (self::legacy_option_keys() as $option_key) {
      $value = get_option($option_key, null);
      if (is_array($value)) {
        $normalized = self::normalize_legacy_settings($value);
        if (!empty(array_filter($normalized, static fn($item) => $item !== '' && $item !== null && $item !== []))) {
          $candidates[] = $normalized;
        }
      }
    }

    $scalar = [];
    foreach (self::legacy_scalar_option_map() as $option_key => $setting_key) {
      $value = get_option($option_key, null);
      if (is_scalar($value) && (string) $value !== '') {
        $scalar[$setting_key] = (string) $value;
      }
    }
    if (!empty($scalar)) {
      $candidates[] = $scalar;
    }

    $merged = [];
    foreach ($candidates as $candidate) {
      $merged = self::merge_preserving_current($merged, $candidate);
    }

    return self::sanitize_settings($merged, self::defaults());
  }

  private static function legacy_option_keys(): array {
    return [
      'paycal_settings',
      'paycal_connection_settings',
      'paycal_connector',
      'paycal_connector_options',
      'paycal_gateway_settings',
      'paycal_api_settings',
      'paycal_merchant_settings',
      'klamra_paycal_settings',
      'klamra_paycal_connector_settings',
      'aspaclaria_paycal_settings',
      'aspaclaria_paycal_connector_settings',
      'asp_paycal_settings',
      'woocommerce_paycal_settings',
      'woocommerce_paycal_hosted_settings',
      'woocommerce_paycal_gateway_settings',
      'woocommerce_klamra_paycal_settings',
      'woocommerce_klamra_paycal_for_aspaclaria_settings',
    ];
  }

  private static function legacy_scalar_option_map(): array {
    return [
      'paycal_platform_url' => 'platform_url',
      'paycal_checkout_base_url' => 'checkout_base_url',
      'paycal_generic_checkout_enabled' => 'use_checkout_sessions',
      'paycal_use_checkout_sessions' => 'use_checkout_sessions',
      'paycal_merchant_id' => 'merchant_id',
      'paycal_terminal_id' => 'terminal_id',
      'paycal_public_key' => 'public_key',
      'paycal_api_key' => 'public_key',
      'paycal_access_token' => 'access_token',
      'paycal_api_token' => 'access_token',
      'paycal_token' => 'access_token',
      'paycal_mode' => 'mode',
      'paycal_environment' => 'mode',
    ];
  }

  private static function normalize_legacy_settings(array $data): array {
    $aliases = [
      'platform_url' => ['platform_url', 'paycal_platform_url', 'api_url', 'base_url', 'endpoint', 'platform_endpoint'],
      'checkout_base_url' => ['checkout_base_url', 'hosted_checkout_url', 'checkout_url', 'paycal_checkout_base_url'],
      'use_checkout_sessions' => ['use_checkout_sessions', 'generic_checkout_enabled', 'session_checkout_enabled'],
      'merchant_id' => ['merchant_id', 'merchant', 'paycal_merchant_id', 'merchant_uid', 'mrc_id'],
      'public_key' => ['public_key', 'paycal_public_key', 'api_key', 'public_api_key', 'pk'],
      'terminal_id' => ['terminal_id', 'terminal', 'paycal_terminal_id', 'terminal_uid', 'trm_id'],
      'mode' => ['mode', 'environment', 'paycal_mode'],
      'last_sync' => ['last_sync', 'synced_at'],
      'access_token' => ['access_token', 'api_token', 'token', 'paycal_token', 'connector_token'],
    ];

    $normalized = [];
    foreach ($aliases as $target => $keys) {
      foreach ($keys as $key) {
        if (isset($data[$key]) && is_scalar($data[$key]) && (string) $data[$key] !== '') {
          $normalized[$target] = (string) $data[$key];
          break;
        }
      }
    }

    if (empty($normalized['access_token']) && !empty($data['license_token']) && is_scalar($data['license_token']) && str_starts_with((string) $data['license_token'], 'pct_')) {
      $normalized['access_token'] = (string) $data['license_token'];
    }

    return $normalized;
  }

  private static function maybe_migrate_license_data(): void {
    $current = get_option('paycal_license_data', []);
    if (is_array($current) && !empty($current['license_key'])) {
      return;
    }

    $license_key = '';
    foreach ([
      'paycal_license_key',
      'paycal_license_token',
      'klamra_paycal_license_key',
      'klamra_paycal_license_token',
    ] as $option_key) {
      $value = get_option($option_key, '');
      if (is_scalar($value) && (string) $value !== '') {
        $license_key = sanitize_text_field((string) $value);
        break;
      }
    }

    foreach ([
      'paycal_license',
      'paycal_license_settings',
      'klamra_paycal_license_data',
      'klamra_paycal_license_settings',
    ] as $option_key) {
      if ($license_key !== '') {
        break;
      }
      $value = get_option($option_key, []);
      if (!is_array($value)) {
        continue;
      }
      foreach (['license_key', 'license_token', 'key', 'token'] as $field) {
        if (!empty($value[$field]) && is_scalar($value[$field])) {
          $license_key = sanitize_text_field((string) $value[$field]);
          break;
        }
      }
    }

    if ($license_key !== '') {
      update_option('paycal_license_data', [
        'license_key' => $license_key,
        'status' => 'pending',
        'valid' => false,
        'checked_at' => '',
        'message' => 'Migrated from previous PayCal settings.',
      ], false);
    }
  }

  public static function last_diagnostics(): array {
    $events = get_option(self::DIAGNOSTICS_OPTION, []);
    return is_array($events) ? $events : [];
  }

  private static function record_diagnostic(array $before, array $after, string $result): void {
    $events = self::last_diagnostics();
    array_unshift($events, [
      'time' => current_time('mysql'),
      'version' => defined('PAYCAL_VERSION') ? PAYCAL_VERSION : 'unknown',
      'plugin_basename' => self::plugin_basename(),
      'plugin_path' => defined('PAYCAL_PATH') ? basename(rtrim(PAYCAL_PATH, '/\\')) : '',
      'result' => sanitize_key($result),
      'before' => $before,
      'after' => $after,
    ]);

    $events = array_slice($events, 0, 10);
    update_option(self::DIAGNOSTICS_OPTION, $events, false);
    \paycal_debug_log('[PayCal] Connector migration diagnostics: ' . wp_json_encode($events[0]));
  }

  private static function plugin_basename(): string {
    return function_exists('plugin_basename') && defined('PAYCAL_PLUGIN_FILE') ? plugin_basename(PAYCAL_PLUGIN_FILE) : '';
  }

  private static function diagnostic_snapshot($settings, string $phase): array {
    $settings = is_array($settings) ? $settings : [];
    $license = get_option('paycal_license_data', []);
    $last_sync = get_option('paycal_connector_last_sync', []);

    return [
      'phase' => $phase,
      'settings_exist' => !empty($settings),
      'settings_keys' => array_values(array_map('sanitize_key', array_keys($settings))),
      'license_data_exists' => is_array($license) && !empty($license),
      'license_token_exists' => is_array($license) && !empty($license['license_key']),
      'license_valid' => is_array($license) && !empty($license['valid']),
      'merchant_id_exists' => !empty($settings['merchant_id']),
      'terminal_id_exists' => !empty($settings['terminal_id']),
      'public_key_exists' => !empty($settings['public_key']),
      'access_token_exists' => !empty($settings['access_token']),
      'checkout_base_url_exists' => !empty($settings['checkout_base_url']),
      'use_checkout_sessions' => (($settings['use_checkout_sessions'] ?? 'no') === 'yes') ? 'yes' : 'no',
      'mode' => in_array(($settings['mode'] ?? ''), ['production', 'sandbox'], true) ? $settings['mode'] : '',
      'last_sync_exists' => is_array($last_sync) && !empty($last_sync),
    ];
  }

  public static function is_connected(): bool {
    $s = self::get();
    return !empty($s['platform_url']) && !empty($s['merchant_id']) && !empty($s['public_key']);
  }

  public static function masked_public_key(): string {
    $s = self::get();
    $key = (string) $s['public_key'];
    if ($key === '') {
      return '';
    }
    return substr($key, 0, 6) . '••••' . substr($key, -4);
  }
}
