import type { ChatMessage } from '@genesislcap/foundation-ai';

/**
 * Masks the tool-specific payload of a single message — clears tool call args
 * and replaces tool result content with a placeholder. Used when passing history
 * to an agent that should not see another agent's implementation detail.
 */
function maskToolPayload(msg: ChatMessage): ChatMessage {
  if (msg.toolCalls?.length) {
    return { ...msg, toolCalls: msg.toolCalls.map((tc) => ({ ...tc, args: {} })) };
  }
  if (msg.toolResult) {
    return {
      ...msg,
      toolResult: { ...msg.toolResult, content: "[other agent's tool result omitted]" },
    };
  }
  return msg;
}

/**
 * Prepares history for the LLM only: masks tool call args and results from other
 * agents so the active specialist is not confused by tools it does not have.
 * Canonical history in `ChatDriver` stays unmasked for UI and logging.
 */
export function transformHistoryForAgent(history: ChatMessage[], agentName: string): ChatMessage[] {
  return history.map((msg) => {
    if (!msg.agentName || msg.agentName === agentName) return msg;
    return maskToolPayload(msg);
  });
}

/**
 * Applies a history cap for sub-agent context: the last `cap` messages are passed
 * verbatim; older messages have their tool payloads masked.
 */
export function applyHistoryCap(history: readonly ChatMessage[], cap: number): ChatMessage[] {
  const cutoff = history.length - cap;
  return history.map((msg, i) => (i < cutoff ? maskToolPayload(msg) : msg));
}

// ───────────────────────────── Compaction (GENC-1351 §5.7) ─────────────────────────────

/** Recent messages kept verbatim when compacting; everything earlier is summarized. */
export const COMPACT_KEEP_RECENT_MESSAGES = 4;

/** Don't bother compacting unless at least this many messages would be summarized. */
export const COMPACT_MIN_MESSAGES_TO_COMPACT = 4;

/**
 * Index at which the verbatim tail begins — everything before it gets summarized.
 * The tail starts on a clean turn boundary (a `user` message): a user message
 * never appears between a `tool_use` and its `tool_result`, so cutting there
 * guarantees the summarized region is tool-pair-balanced (compaction only runs
 * when idle, so history is turn-complete). Returns `null` when there is nothing
 * worth compacting (too short, or no earlier user boundary) — e.g. a freshly
 * restored session whose only user turn is the current one.
 */
export function findCompactionCut(history: readonly ChatMessage[]): number | null {
  if (history.length < COMPACT_KEEP_RECENT_MESSAGES + COMPACT_MIN_MESSAGES_TO_COMPACT) {
    return null;
  }
  const target = history.length - COMPACT_KEEP_RECENT_MESSAGES;
  for (let i = target; i > 0; i -= 1) {
    if (history[i].role === 'user') {
      return i >= COMPACT_MIN_MESSAGES_TO_COMPACT ? i : null;
    }
  }
  return null;
}

/** One-line rendering of a message for the summarizer transcript. */
function renderMessageForSummary(m: ChatMessage): string {
  switch (m.role) {
    case 'compacted-summary':
      return `[Earlier summary] ${m.content}`;
    case 'user':
      return m.content ? `User: ${m.content}` : '';
    case 'assistant': {
      // Reasoning ("Thinking") and narration ("Working") are display-only assistant splits
      // (GENC-1410) with no tool calls of their own — fold them into the summary too, labelled
      // the same as the UI so the summarizer knows they were internal, not a final answer.
      if (m.category === 'reasoning') {
        return m.content ? `Thinking: ${m.content}` : '';
      }
      if (m.category === 'narration') {
        return m.content ? `Working: ${m.content}` : '';
      }
      if (m.toolCalls?.length) {
        const calls = m.toolCalls.map((t) => t.name).join(', ');
        return m.content
          ? `Assistant: ${m.content} (called: ${calls})`
          : `Assistant called: ${calls}`;
      }
      return m.content ? `Assistant: ${m.content}` : '';
    }
    case 'tool':
      return m.toolResult ? `Tool result: ${m.toolResult.content}` : '';
    default:
      return ''; // system-event / synthetic-user — not part of the model transcript
  }
}

/**
 * Build the one-shot summarizer prompt for a run of older messages (used with
 * `AIProvider.prompt`). Mirrors the `<conversation_history>` block convention
 * that suggestions use. Any existing `compacted-summary` at the head is folded
 * in (rendered as prior-summary context), so rolling re-compaction produces one
 * combined summary.
 */
export function buildCompactionSummaryPrompt(toCompact: readonly ChatMessage[]): {
  systemPrompt: string;
  userMessage: string;
} {
  const transcript = toCompact.map(renderMessageForSummary).filter(Boolean).join('\n');
  const systemPrompt =
    'You compress a conversation transcript into a concise summary that lets an AI ' +
    'assistant continue the conversation seamlessly. Preserve key facts, decisions, ' +
    'what the user wants, entity names and IDs, and any unresolved threads. Write ' +
    'plain prose. Never roleplay or continue the conversation.';
  const userMessage =
    `<conversation_history>\n${transcript}\n</conversation_history>\n\n` +
    'Summarize the conversation above so it can be dropped from context while ' +
    'preserving everything needed to continue. Output only the summary prose.';
  return { systemPrompt, userMessage };
}

/**
 * Normalize history for a provider request (GENC-1351 §5.7): translate each
 * `compacted-summary` message into a `user` message that wraps its summary in a
 * `<conversation_summary>` block, so the raw display-only role never reaches a
 * transport. Other roles pass through untouched. Pure — returns a new array.
 *
 * Applied at the request-build chokepoint *before* per-agent masking, so the
 * guarantee holds for every provider/transport regardless of any optional
 * per-agent history transform.
 */
export function normalizeForProvider(history: readonly ChatMessage[]): ChatMessage[] {
  return history.map((m) => {
    if (m.role !== 'compacted-summary') return m;
    return {
      ...m,
      role: 'user',
      content:
        `<conversation_summary>\n${m.content}\n</conversation_summary>\n\n` +
        'The above summarizes earlier parts of this conversation that were compacted. ' +
        'Continue naturally from it.',
      compaction: undefined,
    };
  });
}

/** Human-facing divider label for a `compacted-summary` message. */
export function compactionDividerLabel(m: ChatMessage): string {
  const n = m.compaction?.compactedCount ?? 0;
  return `Compacted ${n} earlier message${n === 1 ? '' : 's'}`;
}
