import { logError } from '../../utils';
import { getConfig, BrainProfile } from '../../config';
import { stripMarkdownFormatting, looksCutOff } from '../../core/responseRecovery';
import {
    sanitizeAssistantContent,
    parseRationale,
} from '../../lib/contextBuilders/outputSanitization';
import {
    isSecondBrainInventoryRequest,
    isNoBrainDataRefusal,
} from '../../lib/contextBuilders/promptDetection';
import { buildSecondBrainInventoryFallbackAnswer } from '../../lib/contextBuilders/secondBrainInventory';
import { isProjectKnowledgeCreationRequest } from '../../lib/contextBuilders/localProjectIntent';
import {
    buildProjectKnowledgeFallbackAnswer,
    writeProjectKnowledgeRecord,
} from '../../lib/contextBuilders/projectKnowledge';
import { enforceLocalPathReviewAnswer } from '../../lib/contextBuilders/localProjectPath';
import { isBlockingProjectKnowledgeAnswer } from '../../lib/contextBuilders/recentProjectKnowledge';
import {
    enforceProjectClaimPolicyInAnswer,
    SecondBrainTrace,
} from '../../features/secondBrainTrace';
import {
    estimateTokens,
    classifyStopReason,
    truncationNotice,
    shouldShowTruncationNotice,
} from '../../lib/contextManager';

export interface ProcessFinalAnswerInput {
    /** Raw `cleaned.visible` from extractVisibleFinal(). */
    visibleAnswer: string;
    prompt: string | null;
    secondBrainTrace: SecondBrainTrace | null;
    localPathContext: string;
    activeBrain: BrainProfile;
    brainFiles: string[];
    finishStopReason: string | undefined;
    maxOutputTokens: number;
    /** From earlier phases — used in logError noise. */
    actualModel: string;
    engine: string;
    inputTokens: number;
}

export interface ProcessFinalAnswerResult {
    /** post-stripMarkdown 1차 — agent.ts 의 `executeActions(cleanedVisible, …)` 호출에 그대로 전달. */
    cleanedVisible: string;
    /** post-enforcers, pre-final-stripMarkdown — used for executeActions and history. */
    assistantContent: string;
    /** post-stripMarkdown-FINAL — emitted to webview. */
    finalAssistantContent: string;
    rationale: ReturnType<typeof parseRationale>;
    outputTokens: number;
    stopKind: ReturnType<typeof classifyStopReason>;
}

export function processFinalAnswer(input: ProcessFinalAnswerInput): ProcessFinalAnswerResult {
    const {
        visibleAnswer,
        prompt,
        secondBrainTrace,
        localPathContext,
        activeBrain,
        brainFiles,
        finishStopReason,
        maxOutputTokens,
        actualModel,
        engine,
        inputTokens,
    } = input;

    // [Plain Text Output] outputFormat='plain' (기본)이면 모델이 무심코 내보낸
    // 마크다운 마커(`##`, `**`, `> `, `* ` …) 를 후처리로 모두 제거. 라벨 텍스트는 유지.
    // markdown 모드면 legacy 그대로 통과.
    const cleanedVisible = getConfig().outputFormat === 'plain'
        ? stripMarkdownFormatting(visibleAnswer)
        : visibleAnswer;

    // 5. Execute Actions
    const rationale = parseRationale(cleanedVisible);
    let assistantContent = enforceLocalPathReviewAnswer(
        enforceProjectClaimPolicyInAnswer(
            sanitizeAssistantContent(cleanedVisible),
            secondBrainTrace
        ),
        localPathContext
    );
    if (prompt && isSecondBrainInventoryRequest(prompt) && brainFiles.length > 0 && isNoBrainDataRefusal(assistantContent)) {
        assistantContent = buildSecondBrainInventoryFallbackAnswer(activeBrain, brainFiles, secondBrainTrace);
    }
    // Note: a previous implementation replaced LLM review answers with a
    // hardcoded Korean template whenever the answer didn't match enough
    // keywords. That made every review feel canned and project-agnostic
    // (the template was Datacollector-flavored). We now let the LLM's
    // answer stand — the system prompt for review-evaluation
    // (buildLocalProjectIntentGuidance / buildAstraStanceContext) is
    // strong enough to keep the response concrete.
    if (prompt && localPathContext && isProjectKnowledgeCreationRequest(prompt)) {
        const record = writeProjectKnowledgeRecord(localPathContext);
        if (isBlockingProjectKnowledgeAnswer(assistantContent)) {
            assistantContent = buildProjectKnowledgeFallbackAnswer(localPathContext, record);
        } else if (record && !assistantContent.includes(record.filePath)) {
            assistantContent = [
                assistantContent,
                '',
                '## 생성된 기록',
                `프로젝트 지식 기록을 생성했습니다: \`${record.filePath}\``
            ].join('\n');
        }
    }
    // Surface truncated/abnormal generation so the user knows the answer is incomplete.
    const stopKind = classifyStopReason(finishStopReason);
    if (stopKind === 'output-limit' || stopKind === 'context-overflow' || stopKind === 'error') {
        logError('Generation stopped abnormally.', {
            model: actualModel, engine, stopReason: finishStopReason, stopKind,
            inputTokens, maxOutputTokens, answerChars: assistantContent.length,
        });
    }
    const outputTokens = estimateTokens(assistantContent);
    // Show the "incomplete" notice when the engine said output-limit/context-overflow/error,
    // OR when (after all auto-continuation rounds) the answer still plainly ends mid-sentence.
    const notice =
        shouldShowTruncationNotice(stopKind, outputTokens, maxOutputTokens) ? truncationNotice(stopKind)
        : looksCutOff(assistantContent) ? truncationNotice('output-limit')
        : '';
    if (notice && assistantContent.trim()) {
        assistantContent = assistantContent.trimEnd() + notice;
    }
    // [Plain Text Output — FINAL pass] enforcer 들이 `## 경로 확인 결과` 같은 하드코딩 헤더를
    // 다시 prepend 한 후에도 마커가 남지 않도록, webview / chatHistory 에 들어가는 최종 문자열을
    // 한 번 더 sanitize. cleanedVisible 단계의 1차 sanitize 는 model 출력 자체를 정리하고,
    // 이 2차 sanitize 는 enforcer 출력까지 모두 청소한다.
    const finalAssistantContent = getConfig().outputFormat === 'plain'
        ? stripMarkdownFormatting(assistantContent)
        : assistantContent;

    return {
        cleanedVisible,
        assistantContent,
        finalAssistantContent,
        rationale,
        outputTokens,
        stopKind,
    };
}
