// @lifecycle canonical - Barrel exports for text reference utilities.
/**
 * Text Reference System (Canonical Chain Step Store)
 *
 * Provides a single source of truth for chain step results so every pipeline
 * stage, session manager, and template renderer reads from the same snapshot.
 */

import type { Logger } from '../../shared/types/index.js';

type StoredStepResult = {
  content: string;
  timestamp: number;
  metadata?: Record<string, any>;
};

export class TextReferenceStore {
  private readonly logger: Logger;
  private readonly chainStepResults: Record<string, Record<number, StoredStepResult>> = {};
  // Named outputs from outputMapping (e.g., { "chainId": { "findings": "content" } })
  private readonly namedOutputs: Record<string, Record<string, string>> = {};

  constructor(logger: Logger) {
    this.logger = logger;
  }

  /**
   * Store a chain step result.
   * Canonical entrypoint for pipeline stages to persist user or placeholder output.
   *
   * If metadata.outputMapping is provided (e.g., { "findings": "output" }),
   * the result will also be stored under those named keys for semantic access.
   */
  storeChainStepResult(
    chainId: string,
    stepNumber: number,
    content: string,
    metadata?: Record<string, any>
  ): void {
    if (!this.chainStepResults[chainId]) {
      this.chainStepResults[chainId] = {};
    }

    const stepResult: StoredStepResult = {
      content,
      timestamp: Date.now(),
    };
    if (metadata) {
      stepResult.metadata = metadata;
    }
    this.chainStepResults[chainId][stepNumber] = stepResult;

    this.logger.debug(
      `[TextReferenceStore] Stored step ${stepNumber} result for chain ${chainId} (${content.length} chars)`
    );

    // Store under named outputs if outputMapping is provided
    const outputMapping = metadata?.['outputMapping'] as Record<string, string> | undefined;
    if (outputMapping) {
      if (!this.namedOutputs[chainId]) {
        this.namedOutputs[chainId] = {};
      }
      for (const outputName of Object.keys(outputMapping)) {
        this.namedOutputs[chainId][outputName] = content;
        this.logger.debug(
          `[TextReferenceStore] Stored named output '${outputName}' for chain ${chainId}`
        );
      }
    }
  }

  /**
   * Retrieve all step results for a chain as a map of step -> content.
   */
  getChainStepResults(chainId: string): Record<number, string> {
    const chainResults = this.chainStepResults[chainId] || {};
    const results: Record<number, string> = {};

    Object.entries(chainResults).forEach(([stepNum, stepData]) => {
      results[Number(stepNum)] = stepData.content;
    });

    return results;
  }

  /**
   * Retrieve a specific step result.
   */
  getChainStepResult(chainId: string, stepNumber: number): string | null {
    return this.chainStepResults[chainId]?.[stepNumber]?.content ?? null;
  }

  /**
   * Build template variables for downstream execution ({{stepN_result}}, {{previous_step_result}}, etc.).
   * Also includes any named outputs from outputMapping (e.g., {{findings}}).
   */
  buildChainVariables(chainId: string): Record<string, any> {
    const stepResults = this.getChainStepResults(chainId);
    const variables: Record<string, any> = {};

    Object.entries(stepResults).forEach(([stepNum, content]) => {
      const stepIndex = Number(stepNum);
      variables[`step${stepIndex + 1}_result`] = content;
      variables[`previous_step_result`] = content;
    });

    variables['chain_id'] = chainId;
    variables['step_results'] = stepResults;

    // Include named outputs from outputMapping
    const namedOutputs = this.namedOutputs[chainId];
    if (namedOutputs) {
      Object.assign(variables, namedOutputs);
    }

    return variables;
  }

  /**
   * Retrieve metadata stored for a specific step result.
   */
  getChainStepMetadata(chainId: string, stepNumber: number): Record<string, any> | null {
    return this.chainStepResults[chainId]?.[stepNumber]?.metadata ?? null;
  }

  /**
   * Clear all stored step results for a chain (used when sessions reset).
   */
  clearChainStepResults(chainId: string): void {
    delete this.chainStepResults[chainId];
    delete this.namedOutputs[chainId];
    this.logger.debug(`[TextReferenceStore] Cleared all step results for chain ${chainId}`);
  }

  /**
   * Aggregate statistics about stored chains and steps.
   */
  getChainStats(): {
    totalChains: number;
    totalSteps: number;
    chainsWithSteps: string[];
  } {
    const chainIds = Object.keys(this.chainStepResults);
    let totalSteps = 0;

    chainIds.forEach((chainId) => {
      const chainSteps = this.chainStepResults[chainId];
      if (chainSteps) {
        totalSteps += Object.keys(chainSteps).length;
      }
    });

    return {
      totalChains: chainIds.length,
      totalSteps,
      chainsWithSteps: chainIds,
    };
  }

  /**
   * Canonical stats accessor used by diagnostics.
   */
  getStats(): ReturnType<TextReferenceStore['getChainStats']> {
    return this.getChainStats();
  }
}

export { ArgumentHistoryTracker } from './argument-history-tracker.js';
export type { ArgumentHistoryEntry, ReviewContext, PersistedArgumentHistory } from './types.js';
