import { stripAstraFormattingForAgentMode } from '../../lib/contextBuilders/systemPromptShaping';
import { estimateTokens } from '../../lib/contextManager';
import { logInfo } from '../../utils';
import { buildSelfIdentityBlock } from '../../lib/contextBuilders/selfIdentity';

export interface BuildAgentModeSystemPromptInput {
    /** Base system prompt — `Astra: …` block etc. */
    systemPrompt: string;
    /** Agent skill content the user selected. */
    agentSkillContext: string;
    /** Pre-built mode-bridge context (or ''). */
    modeBridgeCtx: string;
    /** [PRIOR TURN CONCLUSION] 블록 — 직전 assistant 답변의 첫 문장 (또는 ''). */
    priorConclusionCtx: string;
    designerCtx: string;
    secondBrainTraceCtx: string;
    memoryCtx: string;
    knowledgeContextForPrompt: string;
    contextBlock: string;
    negativeCtx: string;
    /** For token-cost logging. */
    actualModel: string;
    /** For token-cost logging — getConfig().contextLength. */
    contextLength: number;
    /**
     * 행동 제약·동적 블록 (behavior-constraints / cove-checklist 등) — Astra 모드와
     * 동일하게 [CONTEXT] *밖* 보호 구역에 join. 없으면 옛 동작 그대로.
     */
    dynamicBlocks?: Map<string, string>;
}

export function buildAgentModeSystemPrompt(input: BuildAgentModeSystemPromptInput): string {
    const {
        systemPrompt,
        agentSkillContext,
        modeBridgeCtx,
        priorConclusionCtx,
        designerCtx,
        secondBrainTraceCtx,
        memoryCtx,
        knowledgeContextForPrompt,
        contextBlock,
        negativeCtx,
        actualModel,
        contextLength,
        dynamicBlocks,
    } = input;

    // The Agent's prompt IS the primary directive (role / persona / tone / output format),
    // so it LEADS the system prompt — models anchor on the first persona they see, not the
    // last, especially small ones. The Astra base prompt is reduced to neutral scaffolding
    // (action tags, current date, anti-leak rules) and follows; a short reminder at the very
    // end keeps the model from drifting back to a generic assistant.
    const strippedSystemPrompt = stripAstraFormattingForAgentMode(systemPrompt);
    const agentPromptText = (agentSkillContext || '').trim();
    if (estimateTokens(agentPromptText) > Math.floor(contextLength * 0.5)) {
        logInfo('Agent prompt is unusually large relative to the context window.', {
            model: actualModel, agentPromptTokens: estimateTokens(agentPromptText), contextLength: contextLength,
        });
    }

    const agentBlock = [
        '[AGENT MODE — PRIMARY DIRECTIVE]',
        'A specialized Agent has been selected by the user. The Agent System Prompt below is your',
        'PRIMARY directive: it defines your role, persona, tone, and output format. Follow it exactly.',
        'Everything after the Agent block (action-tag reference, date, brain/project context) is technical',
        'scaffolding — use it only as the Agent\'s task requires. Do NOT impose a generic assistant',
        'format (e.g. ## 요약 / ## 상세 설명 / ## 제안) unless the Agent explicitly asks for one.',
        '',
        '--- AGENT SYSTEM PROMPT START ---',
        agentPromptText || '(this agent has no instructions yet — fall back to being a concise, direct assistant)',
        '--- AGENT SYSTEM PROMPT END ---',
    ].join('\n');
    const agentTailReminder = '\n\n[REMINDER] You are operating as the Agent defined above. Keep its role, persona, and output format. Do not fall back to a default assistant style or section format.';

    // [CONTEXT] … [/CONTEXT] 사이만 컨텍스트 초과 시 trim 대상 — agentBlock(앞)·reminder(뒤)·negative 는 보호.
    // memoryCtx(RAG/메모리/lessons)도 [CONTEXT] 안에 넣어 토큰이 빡빡할 때 대화 기록보다 먼저 잘리게 한다.
    // 순서 = 잘림 우선순위 (truncation 은 body *뒤*부터 자름): contextBlock(사용자가
    // 지금 가리킨 실데이터 — URL 본문/열린 파일/일정)을 맨 앞에 둬 최후까지 보존하고,
    // 배경 지식(brain RAG)과 memory 는 그보다 먼저 잘리게 한다.
    const priorConclusionBlock = priorConclusionCtx ? '\n\n' + priorConclusionCtx : '';
    // [자기 지식 + 1인칭] Astra 모드와 공용 — Agent 모드에서도 자기 오보고/3인칭 화법 방지.
    const selfIdentityBlock = '\n\n' + buildSelfIdentityBlock();
    // 동적 블록 (행동 제약·CoVe 등) — [CONTEXT] 밖에 join 해 truncation 보호.
    let dynamicBlocksJoined = '';
    if (dynamicBlocks && dynamicBlocks.size > 0) {
        for (const body of dynamicBlocks.values()) {
            if (body && body.trim()) dynamicBlocksJoined += '\n\n' + body;
        }
    }
    const fullSystemPrompt = `${agentBlock}${modeBridgeCtx ? '\n\n' + modeBridgeCtx : ''}${priorConclusionBlock}\n\n${strippedSystemPrompt}${selfIdentityBlock}${designerCtx}${secondBrainTraceCtx}${dynamicBlocksJoined}\n\n[CONTEXT]\n${contextBlock}\n${knowledgeContextForPrompt}\n${memoryCtx}\n[/CONTEXT]\n${negativeCtx}${agentTailReminder}`;

    return fullSystemPrompt;
}
