/**
 * Centralized Message Sanitization
 *
 * Defense-in-depth layer that catches any JSON/code artifacts before
 * they reach clients. All outgoing WebSocket messages pass through here.
 *
 * This is the SINGLE place to add new sanitization patterns.
 */

// Fields that contain user-facing text and should be sanitized
const TEXT_FIELDS = ['message', 'question', 'title', 'content', 'text', 'description'];

// Patterns to strip from message content
const SANITIZE_PATTERNS: RegExp[] = [
  // JSON function/tool call syntax: {"function": "...", "parameters": {...}}
  /\{[^{}]*"(function|tool|parameters|tool_calls)"[^{}]*\}/gi,

  // Nested JSON with tool-related keys
  /\{\s*"[^"]+"\s*:\s*\{[^{}]*"(message|sentiment)"[^{}]*\}\s*\}/gi,

  // Python-style function calls: send_message(message="...", ...)
  /[a-z_]+\s*\(\s*message\s*=\s*"[^"]*"[^)]*\)/gi,

  // Tool name followed by parentheses: send_message(...)
  /\b(send_message|suggest_activity|express_feeling|ask_for_date|share_news|request_favor|give_gift|confess_feelings|ask_to_be_official|accept_relationship|accept_date|accept_activity|accept_confession|initiate_breakup|accept_breakup)\s*\([^)]*\)/gi,

  // Standalone tool names at end of message
  /\s+(send_message|suggest_activity|express_feeling|ask_for_date|share_news|request_favor|give_gift|confess_feelings|ask_to_be_official|accept_relationship|accept_date|accept_activity|accept_confession|initiate_breakup|accept_breakup)\s*$/gi,

  // JSON key-value at end: "message": "text", "sentiment": "positive"
  /,?\s*"(message|sentiment|mood|function|parameters)"\s*:\s*"[^"]*"\s*,?\s*}?\s*$/gi,

  // Partial JSON at start: {"message": " or "message": "
  /^\s*\{?\s*"message"\s*:\s*"?/gi,

  // Trailing JSON closing: ", "} or just }
  /"\s*,?\s*\}?\s*$/g,
];

// Patterns that indicate the entire string is just JSON (not text with JSON)
const PURE_JSON_PATTERN = /^\s*\{[\s\S]*\}\s*$/;

/**
 * Sanitize an outgoing WebSocket message
 * Recursively processes objects and arrays, sanitizing text fields
 */
export function sanitizeOutgoingMessage<T>(message: T): T {
  if (message === null || message === undefined) {
    return message;
  }

  return deepSanitize(message) as T;
}

/**
 * Recursively sanitize an object, array, or primitive
 */
function deepSanitize(obj: unknown): unknown {
  // Handle strings
  if (typeof obj === 'string') {
    return obj; // Don't sanitize all strings, only specific fields
  }

  // Handle arrays
  if (Array.isArray(obj)) {
    return obj.map(item => deepSanitize(item));
  }

  // Handle objects
  if (obj && typeof obj === 'object') {
    const result: Record<string, unknown> = {};

    for (const [key, value] of Object.entries(obj)) {
      // Sanitize text fields
      if (TEXT_FIELDS.includes(key) && typeof value === 'string') {
        result[key] = sanitizeString(value);
      } else {
        // Recursively process nested objects/arrays
        result[key] = deepSanitize(value);
      }
    }

    return result;
  }

  // Return primitives unchanged
  return obj;
}

/**
 * Sanitize a string by removing JSON/code artifacts
 */
function sanitizeString(str: string): string {
  if (!str || str.length === 0) {
    return str;
  }

  let result = str;

  // If the entire string looks like pure JSON, try to extract the message
  if (PURE_JSON_PATTERN.test(result)) {
    try {
      const parsed = JSON.parse(result);
      if (parsed.message && typeof parsed.message === 'string') {
        result = parsed.message;
      }
    } catch {
      // Not valid JSON, continue with pattern removal
    }
  }

  // Apply all sanitization patterns
  for (const pattern of SANITIZE_PATTERNS) {
    // Reset lastIndex for global patterns
    pattern.lastIndex = 0;
    result = result.replace(pattern, '').trim();
  }

  // Remove surrounding quotes (from failed JSON extraction)
  if (result.length >= 2 && result.startsWith('"') && result.endsWith('"')) {
    result = result.slice(1, -1).trim();
  }

  // Remove leading quote if message ends naturally
  if (result.startsWith('"') && /[.!?)\u{1F300}-\u{1F9FF}]$/u.test(result)) {
    result = result.slice(1).trim();
  }

  // Clean up any double spaces created by removals
  result = result.replace(/\s{2,}/g, ' ').trim();

  // Remove trailing punctuation artifacts
  result = result.replace(/[,;:]\s*$/, '').trim();

  return result;
}

/**
 * Add a new sanitization pattern at runtime
 * Useful for adding patterns discovered in production
 */
export function addSanitizePattern(pattern: RegExp): void {
  SANITIZE_PATTERNS.push(pattern);
}

/**
 * Get current pattern count (for monitoring/debugging)
 */
export function getPatternCount(): number {
  return SANITIZE_PATTERNS.length;
}
