/**
 * Post-answer hook registry — 답변 완료 후 실행되는 부가 작업 모음.
 *
 * 새 hook 추가 = 1 객체 push. agent.ts 는 이 배열을 iterate 만 함.
 *
 * 현재 등록 순서 (v2.2.197):
 *  1. devilRebuttal — Devil Agent 반박 카드 (비활성 시 silent skip)
 *  2. postHocSelfCheck — 답변 검증 LLM 호출 (opt-in, 기본 OFF)
 *  3. termValidator — 결정론적 글로서리 forbidden 검사 (기본 ON)
 */

import type { PostAnswerHook, PostAnswerHookContext } from './types';
import { maybeEmitDevilRebuttal as maybeEmitDevilRebuttalFn } from '../llm/devilRebuttal';
import { postHocSelfCheck, formatSelfCheckFooter, DEFAULT_SELF_CHECK_OPTIONS } from '../postHocSelfCheck';
import { validateTermUsage, formatTermValidatorFooter } from '../termValidator';
import { getConfig } from '../../config';

const devilRebuttalHook: PostAnswerHook = {
    id: 'devil-rebuttal',
    runAsync: true,
    async run(ctx: PostAnswerHookContext): Promise<void> {
        await maybeEmitDevilRebuttalFn(
            {
                getAbortSignal: ctx.getAbortSignal,
                callNonStreaming: ctx.callNonStreaming,
                // agent.ts 에서 vscode.Webview 를 통과시키므로 실런타임 호환. 타입 cast 로 hook 일반화.
                getWebview: ctx.getWebview as any,
            },
            {
                userPrompt: ctx.userPrompt,
                assistantAnswer: ctx.assistantAnswer,
                baseUrl: ctx.baseUrl,
                modelName: ctx.modelName,
                contextLength: ctx.contextLength,
                engine: ctx.engine,
            },
        );
    },
};

const postHocSelfCheckHook: PostAnswerHook = {
    id: 'self-check',
    runAsync: true,
    async run(ctx: PostAnswerHookContext): Promise<void> {
        const cfg = getConfig();
        if (!cfg.selfCheckEnabled) return;
        if (!ctx.userPrompt.trim() || !ctx.assistantAnswer.trim()) return;
        const model = (cfg.selfCheckModel || '').trim() || cfg.defaultModel;
        if (!model || !cfg.ollamaUrl) return;

        const result = await postHocSelfCheck(ctx.userPrompt, ctx.assistantAnswer, ctx.selfCheckSources, {
            ollamaUrl: cfg.ollamaUrl,
            model,
            timeoutMs: (cfg.selfCheckTimeoutSec ?? 6) * 1000,
            excerptLength: DEFAULT_SELF_CHECK_OPTIONS.excerptLength,
            maxSources: DEFAULT_SELF_CHECK_OPTIONS.maxSources,
        });
        const footer = formatSelfCheckFooter(result, model);
        ctx.getWebview()?.postMessage({ type: 'streamChunk', value: footer });
    },
};

const termValidatorHook: PostAnswerHook = {
    id: 'term-validator',
    runAsync: false,
    run(ctx: PostAnswerHookContext): void {
        const cfg = getConfig();
        if (cfg.termValidatorEnabled === false) return;
        if (!ctx.assistantAnswer || !ctx.assistantAnswer.trim()) return;
        const result = validateTermUsage(ctx.assistantAnswer, cfg.glossaryPath || '.astra/glossary.md');
        if (!result.ran || result.dictionarySize === 0) return;
        const footer = formatTermValidatorFooter(result);
        if (footer) ctx.getWebview()?.postMessage({ type: 'streamChunk', value: footer });
    },
};

export const POST_ANSWER_HOOKS: PostAnswerHook[] = [
    devilRebuttalHook,
    postHocSelfCheckHook,
    termValidatorHook,
];

/** 모든 hook 을 안전하게 실행 — 한 hook 의 throw 가 다른 hook 막지 않음. */
export function runPostAnswerHooks(ctx: PostAnswerHookContext): void {
    for (const hook of POST_ANSWER_HOOKS) {
        try {
            if (hook.runAsync) {
                void Promise.resolve(hook.run(ctx)).catch(() => { /* swallow */ });
            } else {
                hook.run(ctx);
            }
        } catch { /* hook never breaks the turn */ }
    }
}

export type { PostAnswerHook, PostAnswerHookContext } from './types';
