/**
 * Wake-up context builder for palace-augmented sessions.
 *
 * Builds a layered context string (L0/L1/L2) within a token budget.
 * Products provide the raw data; this module assembles and truncates.
 */

export interface WakeUpLayer {
  label: string;
  content: string;
  priority: number;
}

export interface WakeUpConfig {
  totalBudget: number;
  l0Budget: number;
  l1Budget: number;
  l2Budget: number;
}

export interface WakeUpContext {
  text: string;
  layers: { label: string; charCount: number }[];
  totalChars: number;
  truncated: boolean;
}

/**
 * Approximate token count for a string.
 * Uses the rough heuristic of ~4 characters per token.
 */
export function estimateTokens(text: string): number {
  return Math.ceil(text.length / 4);
}

/**
 * Truncate text to fit within a token budget.
 *
 * @param text - Input text
 * @param maxTokens - Maximum tokens allowed
 * @returns Truncated text (with "..." appended if truncated)
 */
export function truncateToTokenBudget(text: string, maxTokens: number): string {
  if (!text) return '';

  const maxChars = maxTokens * 4;
  if (text.length <= maxChars) return text;

  // Truncate at word boundary
  const truncated = text.slice(0, maxChars);
  const lastSpace = truncated.lastIndexOf(' ');
  const cutPoint = lastSpace > maxChars * 0.8 ? lastSpace : maxChars;

  return truncated.slice(0, cutPoint) + '...';
}

/**
 * Build a wake-up context from L0/L1/L2 layers within a total token budget.
 *
 * Layer priority:
 * - L0 (identity/project context) — always included, smallest budget
 * - L1 (critical facts from recent memories) — high priority
 * - L2 (semantically relevant memories) — fills remaining budget
 *
 * @param l0 - Identity/project context string
 * @param l1 - Critical facts string
 * @param l2 - Semantically relevant memories string
 * @param config - Token budget configuration
 * @returns Assembled wake-up context with metadata
 */
export function buildWakeUpLayers(
  l0: string,
  l1: string,
  l2: string,
  config: WakeUpConfig
): WakeUpContext {
  const layers: { label: string; charCount: number }[] = [];
  const parts: string[] = [];
  let truncated = false;

  // L0: identity (always included)
  const l0Truncated = truncateToTokenBudget(l0, config.l0Budget);
  if (l0Truncated) {
    parts.push(`[Identity]\n${l0Truncated}`);
    layers.push({ label: 'L0:identity', charCount: l0Truncated.length });
    if (l0Truncated.endsWith('...')) truncated = true;
  }

  // L1: critical facts
  const l1Truncated = truncateToTokenBudget(l1, config.l1Budget);
  if (l1Truncated) {
    parts.push(`[Critical Facts]\n${l1Truncated}`);
    layers.push({ label: 'L1:facts', charCount: l1Truncated.length });
    if (l1Truncated.endsWith('...')) truncated = true;
  }

  // L2: semantic context (gets remaining budget)
  const usedTokens = estimateTokens(parts.join('\n\n'));
  const remainingBudget = Math.max(0, config.totalBudget - usedTokens);
  const l2Budget = Math.min(config.l2Budget, remainingBudget);

  const l2Truncated = truncateToTokenBudget(l2, l2Budget);
  if (l2Truncated) {
    parts.push(`[Relevant Memories]\n${l2Truncated}`);
    layers.push({ label: 'L2:semantic', charCount: l2Truncated.length });
    if (l2Truncated.endsWith('...')) truncated = true;
  }

  const text = parts.join('\n\n');

  return {
    text,
    layers,
    totalChars: text.length,
    truncated,
  };
}

/**
 * Default wake-up configs for each product.
 */
export const WAKEUP_PRESETS: Record<string, WakeUpConfig> = {
  notelett: { totalBudget: 600, l0Budget: 50, l1Budget: 150, l2Budget: 400 },
  mindlyst: { totalBudget: 800, l0Budget: 80, l1Budget: 200, l2Budget: 500 },
  coding: { totalBudget: 800, l0Budget: 80, l1Budget: 200, l2Budget: 500 },
};
