import type { ChatMessage } from '../../agent';

/**
 * 모델에게 보낼 직전 history 변환 모음. 두 stage:
 *   1) sanitizeHistoryAssistantContent — 옛 답변에 박혀 있던 *디버그/내부* 섹션
 *      (Second Brain Trace, candidate records 등) 을 제거. 모델이 자기 옛 답변에서
 *      쓸데없는 메타 정보를 재학습해 다음 답변에 또 박는 회귀 방지.
 *   2) buildRequestHistory — 그걸 모든 assistant 메시지에 적용해 새 배열 반환.
 *
 * 둘 다 stateless — agent.ts 의 private 메서드를 그대로 추출. 새 sanitize 규칙
 * 추가 시 god-file 변경 없이 이 모듈만 수정.
 */
export function buildRequestHistory(history: ChatMessage[]): ChatMessage[] {
    return history.map((message) => {
        if (message.role !== 'assistant' || typeof message.content !== 'string') {
            return message;
        }
        return {
            ...message,
            content: sanitizeHistoryAssistantContent(message.content),
        };
    });
}

/**
 * In-memory chat history 가 무한 성장하지 않도록 두 단계로 정리:
 *   1) `recentFullMessages` 이전의 *내부 tool-result* 메시지 (read_file /
 *      list_files / list_brain / read_brain) 본문을 `oldToolResultCap` 자로
 *      truncate — 최근 메시지는 그대로 둬서 진행 중 흐름은 영향 없음.
 *   2) 전체 길이가 `maxRetained` 초과면 가장 오래된 메시지부터 drop. 단 선두가
 *      system 메시지면 그것만 보존 (세션 복원/대화 framing 깨짐 방지).
 *
 * 매개변수에 cap 값을 다 받아 stateless — agent.ts 의 옛 private 메서드가 class
 * static 상수를 직접 읽던 걸 인수로 옮김.
 *
 * 주의: history 를 *in-place mutate* 한다 (splice + content 직접 수정). 호출자는
 * 같은 배열을 그대로 사용하면 됨. 새 배열을 만들지 않으므로 reference 가 그대로
 * 유지돼야 하는 케이스에 안전.
 */
export function capChatHistory(
    history: ChatMessage[],
    opts: { maxRetained: number; recentFullMessages: number; oldToolResultCap: number },
): void {
    if (history.length === 0) return;

    const recentStart = Math.max(0, history.length - opts.recentFullMessages);
    for (let i = 0; i < recentStart; i++) {
        const msg = history[i];
        if (msg.role !== 'system' || !msg.internal || typeof msg.content !== 'string') continue;
        if (!/^\[Result of (read_file|list_files|list_brain|read_brain)\b/.test(msg.content)) continue;
        if (msg.content.length <= opts.oldToolResultCap) continue;
        msg.content = msg.content.slice(0, opts.oldToolResultCap)
            + '\n…[이전 도구 결과는 컨텍스트 절약을 위해 축약되었습니다]';
    }

    if (history.length > opts.maxRetained) {
        const first = history[0];
        const preserveFirst = first.role === 'system';
        const overflow = history.length - opts.maxRetained;
        if (preserveFirst) {
            history.splice(1, overflow);
        } else {
            history.splice(0, overflow);
        }
    }
}

export function sanitizeHistoryAssistantContent(content: string): string {
    return content
        .replace(/<details>\s*<summary>2nd Brain Trace:[\s\S]*?<\/details>/gi, '')
        .replace(/## Second Brain Debug JSON[\s\S]*?(?=\n## |\n# |$)/gi, '')
        .replace(/## Candidate records for this discussion[\s\S]*?(?=\n## |\n# |$)/gi, '')
        .replace(/## 후보 기록[\s\S]*?(?=\n## |\n# |$)/gi, '')
        .replace(/## 프로젝트 기록 검토[\s\S]*?(?=\n## |\n# |$)/gi, '')
        .replace(/\n{3,}/g, '\n\n')
        .trim();
}
