'use strict';

// src/platform/token-optimizer/strip-ansi.ts
var ANSI_REGEX = new RegExp(
  String.raw`\u001B\[[0-9;]*[a-zA-Z]|\u001B\].*?(?:\u0007|\u001B\\)`,
  "g"
);
var stripAnsi = (text) => {
  return text.replace(ANSI_REGEX, "");
};

// src/platform/token-optimizer/token-counter.ts
var countTokens = (text) => {
  if (!text) {
    return 0;
  }
  return text.split(/\s+/).filter(Boolean).length;
};

// src/platform/token-optimizer/truncate.ts
var truncateText = (text, maxLength) => {
  const charCount = [...text].length;
  if (charCount <= maxLength) {
    return text;
  }
  if (maxLength < 3) {
    return "...";
  }
  return [...text].slice(0, maxLength - 3).join("") + "...";
};
var truncateLines = (text, options) => {
  const { maxCharsPerLine, headLines, tailLines, maxLines } = options;
  let lines = text.split("\n");
  if (headLines !== void 0 && tailLines !== void 0 && lines.length > headLines + tailLines) {
    const head = lines.slice(0, headLines);
    const tail = lines.slice(-tailLines);
    const omittedCount = lines.length - headLines - tailLines;
    lines = [...head, `... (${omittedCount}\uC904 \uC0DD\uB7B5)`, ...tail];
  } else if (headLines !== void 0 && lines.length > headLines) {
    const omittedCount = lines.length - headLines;
    lines = [...lines.slice(0, headLines), `... (${omittedCount}\uC904 \uC0DD\uB7B5)`];
  } else if (tailLines !== void 0 && lines.length > tailLines) {
    const omittedCount = lines.length - tailLines;
    lines = [`... (${omittedCount}\uC904 \uC0DD\uB7B5)`, ...lines.slice(-tailLines)];
  }
  if (maxCharsPerLine !== void 0) {
    lines = lines.map((line) => truncateText(line, maxCharsPerLine));
  }
  if (maxLines !== void 0 && lines.length > maxLines) {
    if (maxLines <= 0) {
      return "";
    }
    const preservedLineCount = Math.max(maxLines - 1, 0);
    const omittedCount = lines.length - preservedLineCount;
    lines = preservedLineCount === 0 ? [`... (${omittedCount}\uC904 \uC0DD\uB7B5)`] : [...lines.slice(0, preservedLineCount), `... (${omittedCount}\uC904 \uC0DD\uB7B5)`];
  }
  return lines.join("\n");
};

// src/platform/token-optimizer/line-filter.ts
function matchesLine(pattern, line) {
  const safePattern = pattern.global || pattern.sticky ? new RegExp(pattern.source, pattern.flags) : pattern;
  safePattern.lastIndex = 0;
  return safePattern.test(line);
}
var filterLines = (text, options) => {
  const { keepPatterns, stripPatterns, stripEmptyLines } = options;
  let lines = text.split("\n");
  if (keepPatterns && keepPatterns.length > 0) {
    lines = lines.filter((line) => keepPatterns.some((pattern) => matchesLine(pattern, line)));
  }
  if (stripPatterns && stripPatterns.length > 0) {
    lines = lines.filter((line) => !stripPatterns.some((pattern) => matchesLine(pattern, line)));
  }
  if (stripEmptyLines) {
    lines = lines.filter((line) => line.trim().length > 0);
  }
  return lines.join("\n");
};

// src/platform/token-optimizer/deduplication.ts
var NORMALIZATION_RULES = [
  // ISO 타임스탬프 (2026-04-09T10:00:01.123 또는 2026-04-09 10:00:01)
  [/\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}[.\d]*/g, "<TIMESTAMP>"],
  // 대괄호 타임스탬프 ([10:00:01], [2026-04-09 10:00:01])
  [/\[\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}[.\d]*\]/g, "[<TIMESTAMP>]"],
  // UUID
  [/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/gi, "<UUID>"],
  // IP 주소
  [/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/g, "<IP>"],
  // 16진수 해시 (7자 이상)
  [/\b[0-9a-f]{7,}\b/gi, "<HEX>"],
  // 큰 숫자 (4자리 이상)
  [/\b\d{4,}\b/g, "<NUM>"]
];
var normalizeLine = (line) => {
  let normalized = line;
  for (const [pattern, replacement] of NORMALIZATION_RULES) {
    normalized = normalized.replace(pattern, replacement);
  }
  return normalized;
};
var deduplicateLines = (text) => {
  const lines = text.split("\n");
  const groups = /* @__PURE__ */ new Map();
  const orderedKeys = [];
  for (const line of lines) {
    if (line.trim().length === 0) {
      const emptyKey = `__EMPTY_${orderedKeys.length}__`;
      groups.set(emptyKey, { count: 1, originalLine: line });
      orderedKeys.push(emptyKey);
      continue;
    }
    const normalized = normalizeLine(line);
    if (groups.has(normalized)) {
      groups.get(normalized).count += 1;
    } else {
      groups.set(normalized, { count: 1, originalLine: line });
      orderedKeys.push(normalized);
    }
  }
  return orderedKeys.map((key) => {
    const group = groups.get(key);
    if (group.count > 1) {
      return `[x${group.count}] ${normalizeLine(group.originalLine)}`;
    }
    return group.originalLine;
  }).join("\n");
};

// src/platform/token-optimizer/optimize.ts
var optimizeText = (text, options = {}) => {
  const originalTokens = countTokens(text);
  if (!text) {
    return { text: "", originalTokens: 0, optimizedTokens: 0, savingsPercent: 0 };
  }
  const {
    stripAnsi: shouldStripAnsi = true,
    maxCharsPerLine,
    maxLines,
    headLines,
    tailLines,
    deduplicate = false,
    keepPatterns,
    stripPatterns,
    stripEmptyLines = true
  } = options;
  let result = shouldStripAnsi ? stripAnsi(text) : text;
  const hasFilterOptions = keepPatterns && keepPatterns.length > 0 || stripPatterns && stripPatterns.length > 0 || stripEmptyLines;
  if (hasFilterOptions) {
    result = filterLines(result, { keepPatterns, stripPatterns, stripEmptyLines });
  }
  if (deduplicate) {
    result = deduplicateLines(result);
  }
  const hasTruncateOptions = maxCharsPerLine !== void 0 || maxLines !== void 0 || headLines !== void 0 || tailLines !== void 0;
  if (hasTruncateOptions) {
    result = truncateLines(result, { maxCharsPerLine, maxLines, headLines, tailLines });
  }
  const optimizedTokens = countTokens(result);
  const savingsPercent = originalTokens > 0 ? Math.round((1 - optimizedTokens / originalTokens) * 1e3) / 10 : 0;
  return {
    text: result,
    originalTokens,
    optimizedTokens,
    savingsPercent
  };
};

exports.countTokens = countTokens;
exports.deduplicateLines = deduplicateLines;
exports.filterLines = filterLines;
exports.optimizeText = optimizeText;
exports.stripAnsi = stripAnsi;
exports.truncateLines = truncateLines;
exports.truncateText = truncateText;
