<?php

declare(strict_types=1);

namespace Drupal\native_observability\Service;

/**
 * Normalizes stored request-log exclusion rules for runtime matching.
 */
final class RequestLogExclusionRuleNormalizer {

  /**
   * Normalizes one stored rule row.
   *
   * @param array<string, mixed> $rule
   *   Raw rule data loaded from storage.
   *
   * @return array<string, mixed>
   *   Matcher-friendly normalized rule.
   */
  public function normalizeRule(array $rule): array {
    $conditions = $this->decodeConditions((string) ($rule['query_conditions'] ?? ''));

    return [
      'id' => (int) ($rule['id'] ?? 0),
      'label' => (string) ($rule['label'] ?? ''),
      'enabled' => !empty($rule['enabled']),
      'method' => strtoupper((string) ($rule['method'] ?? 'ANY')),
      'path_match_type' => (string) ($rule['path_match_type'] ?? 'exact'),
      'path_pattern' => (string) ($rule['path_pattern'] ?? ''),
      'query_conditions' => $conditions,
    ];
  }

  /**
   * Normalizes multiple stored rules.
   *
   * @param array<int, array<string, mixed>> $rules
   *   Raw rules loaded from storage.
   *
   * @return array<int, array<string, mixed>>
   *   Normalized rules.
   */
  public function normalizeRules(array $rules): array {
    $normalized = [];

    foreach ($rules as $rule) {
      $item = $this->normalizeRule($rule);
      if (empty($item['enabled']) || $item['path_pattern'] === '') {
        continue;
      }
      $normalized[] = $item;
    }

    return $normalized;
  }

  /**
   * Parses and normalizes a textarea definition into condition arrays.
   *
   * Format.
   * - key|exists
   * - key|missing
   * - key|equals|value
   * - key|regex|pattern
   * - key|gte|value
   * - key|lte|value
   * - key|between|min|max.
   *
   * @param string $definition
   *   Multiline definition.
   *
   * @return array<int, array<string, string>>
   *   Normalized condition rows.
   */
  public function parseConditionDefinition(string $definition): array {
    $lines = preg_split('/\R/u', $definition) ?: [];
    $conditions = [];

    foreach ($lines as $line) {
      $line = trim($line);
      if ($line === '') {
        continue;
      }

      $parts = array_map('trim', explode('|', $line));
      $key = (string) ($parts[0] ?? '');
      $operator = strtolower((string) ($parts[1] ?? ''));

      if ($key === '' || $operator === '') {
        continue;
      }

      $condition = [
        'key' => $key,
        'operator' => $operator,
      ];

      if (isset($parts[2]) && $parts[2] !== '') {
        $condition['value'] = $parts[2];
      }

      if (isset($parts[3]) && $parts[3] !== '') {
        $condition['value_to'] = $parts[3];
      }

      $conditions[] = $condition;
    }

    return $conditions;
  }

  /**
   * Encodes normalized conditions for storage.
   *
   * @param array<int, array<string, string>> $conditions
   *   Normalized conditions.
   *
   * @return string
   *   JSON representation.
   */
  public function encodeConditions(array $conditions): string {
    return json_encode($conditions, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) ?: '[]';
  }

  /**
   * Decodes stored JSON condition definitions.
   *
   * @param string $encoded
   *   Stored JSON.
   *
   * @return array<int, array<string, string>>
   *   Decoded conditions.
   */
  public function decodeConditions(string $encoded): array {
    if ($encoded === '') {
      return [];
    }

    $decoded = json_decode($encoded, TRUE);
    if (!is_array($decoded)) {
      return [];
    }

    $conditions = [];
    foreach ($decoded as $condition) {
      if (!is_array($condition)) {
        continue;
      }

      $key = trim((string) ($condition['key'] ?? ''));
      $operator = strtolower(trim((string) ($condition['operator'] ?? '')));
      if ($key === '' || $operator === '') {
        continue;
      }

      $conditions[] = [
        'key' => $key,
        'operator' => $operator,
        'value' => isset($condition['value']) ? (string) $condition['value'] : '',
        'value_to' => isset($condition['value_to']) ? (string) $condition['value_to'] : '',
      ];
    }

    return $conditions;
  }

}
