/**
 * Claude-Mem SDK - Standalone module for external consumers
 *
 * This is a self-contained module that exports parsing and prompt utilities
 * without internal dependencies on the main claude-mem codebase.
 *
 * Usage:
 *   import { parseObservations, buildObservationPrompt } from 'claude-mem/sdk';
 */

// ============================================================================
// Parser Functions
// ============================================================================

/**
 * Parse observation XML blocks from text
 * Returns all observations found in the text
 *
 * @param {string} text - The text containing observation XML blocks
 * @param {Object} [options] - Optional configuration
 * @param {string[]} [options.validTypes] - Array of valid observation types. If provided, validates types.
 * @param {string} [options.fallbackType='observation'] - Type to use if type is missing or invalid
 * @returns {ParsedObservation[]} Array of parsed observations
 */
export function parseObservations(text, options = {}) {
  const observations = [];
  const { validTypes, fallbackType = 'observation' } = options;

  // Match <observation>...</observation> blocks (non-greedy)
  const observationRegex = /<observation>([\s\S]*?)<\/observation>/g;

  let match;
  while ((match = observationRegex.exec(text)) !== null) {
    const obsContent = match[1];

    // Extract all fields
    const type = extractField(obsContent, 'type');
    const title = extractField(obsContent, 'title');
    const subtitle = extractField(obsContent, 'subtitle');
    const narrative = extractField(obsContent, 'narrative');
    const facts = extractArrayElements(obsContent, 'facts', 'fact');
    const concepts = extractArrayElements(obsContent, 'concepts', 'concept');
    const files_read = extractArrayElements(obsContent, 'files_read', 'file');
    const files_modified = extractArrayElements(obsContent, 'files_modified', 'file');

    // Determine final type
    let finalType = fallbackType;
    if (type) {
      const trimmedType = type.trim();
      if (validTypes) {
        finalType = validTypes.includes(trimmedType) ? trimmedType : fallbackType;
      } else {
        finalType = trimmedType;
      }
    }

    // Filter out type from concepts array (types and concepts are separate dimensions)
    const cleanedConcepts = concepts.filter(c => c !== finalType);

    observations.push({
      type: finalType,
      title,
      subtitle,
      facts,
      narrative,
      concepts: cleanedConcepts,
      files_read,
      files_modified
    });
  }

  return observations;
}

/**
 * Parse summary XML block from text
 * Returns null if no valid summary found or if summary was skipped
 *
 * @param {string} text - The text containing summary XML block
 * @returns {ParsedSummary|null} Parsed summary or null
 */
export function parseSummary(text) {
  // Check for skip_summary first
  const skipRegex = /<skip_summary\s+reason="([^"]+)"\s*\/>/;
  const skipMatch = skipRegex.exec(text);

  if (skipMatch) {
    return null;
  }

  // Match <summary>...</summary> block (non-greedy)
  const summaryRegex = /<summary>([\s\S]*?)<\/summary>/;
  const summaryMatch = summaryRegex.exec(text);

  if (!summaryMatch) {
    return null;
  }

  const summaryContent = summaryMatch[1];

  return {
    request: extractField(summaryContent, 'request'),
    investigated: extractField(summaryContent, 'investigated'),
    learned: extractField(summaryContent, 'learned'),
    completed: extractField(summaryContent, 'completed'),
    next_steps: extractField(summaryContent, 'next_steps'),
    notes: extractField(summaryContent, 'notes')
  };
}

/**
 * Extract a simple field value from XML content
 * Returns null for missing or empty/whitespace-only fields
 */
function extractField(content, fieldName) {
  const regex = new RegExp(`<${fieldName}>([^<]*)</${fieldName}>`);
  const match = regex.exec(content);
  if (!match) return null;

  const trimmed = match[1].trim();
  return trimmed === '' ? null : trimmed;
}

/**
 * Extract array of elements from XML content
 */
function extractArrayElements(content, arrayName, elementName) {
  const elements = [];

  // Match the array block
  const arrayRegex = new RegExp(`<${arrayName}>(.*?)</${arrayName}>`, 's');
  const arrayMatch = arrayRegex.exec(content);

  if (!arrayMatch) {
    return elements;
  }

  const arrayContent = arrayMatch[1];

  // Extract individual elements
  const elementRegex = new RegExp(`<${elementName}>([^<]+)</${elementName}>`, 'g');
  let elementMatch;
  while ((elementMatch = elementRegex.exec(arrayContent)) !== null) {
    elements.push(elementMatch[1].trim());
  }

  return elements;
}

// ============================================================================
// Prompt Building Functions
// ============================================================================

/**
 * Build prompt to send tool observation to SDK agent
 *
 * @param {Observation} obs - The observation object containing tool data
 * @returns {string} Formatted XML prompt string
 */
export function buildObservationPrompt(obs) {
  // Safely parse tool_input and tool_output - they may be JSON strings
  let toolInput;
  let toolOutput;

  try {
    toolInput = typeof obs.tool_input === 'string' ? JSON.parse(obs.tool_input) : obs.tool_input;
  } catch {
    toolInput = obs.tool_input;
  }

  try {
    toolOutput = typeof obs.tool_output === 'string' ? JSON.parse(obs.tool_output) : obs.tool_output;
  } catch {
    toolOutput = obs.tool_output;
  }

  return `<observed_from_primary_session>
  <what_happened>${obs.tool_name}</what_happened>
  <occurred_at>${new Date(obs.created_at_epoch).toISOString()}</occurred_at>${obs.cwd ? `\n  <working_directory>${obs.cwd}</working_directory>` : ''}
  <parameters>${JSON.stringify(toolInput, null, 2)}</parameters>
  <outcome>${JSON.stringify(toolOutput, null, 2)}</outcome>
</observed_from_primary_session>`;
}
