'use strict';

const crypto = require('node:crypto');

let stripNoise;
try {
  stripNoise = require('../extraction/noise-stripper').stripNoise;
} catch {
  stripNoise = (value) => value;
}

const BASE64_BLOCK_RE = /\b[A-Za-z0-9+/]{512,}={0,2}\b/g;

const RESERVED_TRANSFORMATIONS = Object.freeze({
  utf8_replace_invalid: {
    name: 'utf8_replace_invalid',
    description: 'Decode bytes as UTF-8 and replace invalid sequences.',
    apply(value) {
      if (Buffer.isBuffer(value)) return value.toString('utf8');
      return String(value ?? '');
    },
  },
  newline_normalize: {
    name: 'newline_normalize',
    description: 'Normalize CRLF/CR newlines to LF.',
    apply(value) {
      return String(value ?? '').replace(/\r\n?/g, '\n');
    },
  },
  whitespace_trim: {
    name: 'whitespace_trim',
    description: 'Trim leading and trailing whitespace.',
    apply(value) {
      return String(value ?? '').trim();
    },
  },
  strip_tool_chrome: {
    name: 'strip_tool_chrome',
    description: 'Remove Claude/Codex/Wall-E tool wrapper chrome from searchable text.',
    apply(value) {
      return stripNoise(String(value ?? ''));
    },
  },
  tool_result_summarize: {
    name: 'tool_result_summarize',
    description: 'Bound very large tool results while keeping their existence visible.',
    apply(value, { maxToolResultChars = 4000 } = {}) {
      const text = String(value ?? '');
      if (text.length <= maxToolResultChars) return text;
      return `${text.slice(0, maxToolResultChars)}\n[tool result truncated: ${text.length - maxToolResultChars} chars omitted]`;
    },
  },
  base64_payload_omit: {
    name: 'base64_payload_omit',
    description: 'Replace large inline base64 payloads with deterministic hashes.',
    apply(value) {
      return String(value ?? '').replace(BASE64_BLOCK_RE, (match) => {
        const hash = crypto.createHash('sha256').update(match).digest('hex').slice(0, 16);
        return `[base64 omitted sha256:${hash} bytes:${Buffer.byteLength(match, 'utf8')}]`;
      });
    },
  },
  exchange_pair_chunk: {
    name: 'exchange_pair_chunk',
    description: 'Content was formed by pairing adjacent user and assistant turns.',
    apply(value) {
      return String(value ?? '');
    },
  },
});

function getTransformation(name) {
  return RESERVED_TRANSFORMATIONS[name] || null;
}

function hasTransformation(name) {
  return !!getTransformation(name);
}

function listReservedTransformations() {
  return Object.keys(RESERVED_TRANSFORMATIONS);
}

function applyTransforms(value, transforms = [], context = {}) {
  let current = value;
  for (const name of transforms || []) {
    const transform = getTransformation(name);
    if (!transform) throw new Error(`Unknown reserved transformation: ${name}`);
    current = transform.apply(current, context);
  }
  return current;
}

module.exports = {
  RESERVED_TRANSFORMATIONS,
  applyTransforms,
  getTransformation,
  hasTransformation,
  listReservedTransformations,
};
