/**
 * <calculate> 액션 — 수학·수치 계산의 Python 위임 검증.
 *
 * 소형 모델 추론 강화 전략의 1축: "모델은 코드로 변환만, 계산은 도구가".
 * 실행 결과/에러가 chatHistory 에 internal system 메시지로 재주입되어
 * agent 의 자동 후속 턴(자가수정 루프)을 트리거하는 계약을 검증한다.
 */
import { execFileSync } from 'child_process';
import { applyCalculateActions, _resetPythonCache } from '../src/agent/actions/calculate';

// vscode 런타임 의존 없음(type-only import) — 별도 mock 불필요.

function hasPython(): boolean {
    for (const cmd of ['python3', 'python', 'py']) {
        try { execFileSync(cmd, ['--version'], { timeout: 3000 }); return true; } catch { /* next */ }
    }
    return false;
}
const PY = hasPython();
const itPy = PY ? it : it.skip;

function makeCtx(aiMessage: string): any {
    return { aiMessage, report: [], chatHistory: [] };
}

describe('applyCalculateActions', () => {
    beforeEach(() => _resetPythonCache());

    it('calculate 태그가 없으면 아무것도 하지 않는다', async () => {
        const ctx = makeCtx('그냥 일반 답변입니다. 2+2=4 입니다.');
        await applyCalculateActions(ctx);
        expect(ctx.report).toEqual([]);
        expect(ctx.chatHistory).toEqual([]);
    });

    itPy('정상 계산: stdout 이 internal system 메시지로 재주입된다', async () => {
        const ctx = makeCtx('<calculate>print(1234 * 5678)</calculate>');
        await applyCalculateActions(ctx);
        expect(ctx.report.some((r: string) => r.includes('Calculated'))).toBe(true);
        expect(ctx.chatHistory.length).toBe(1);
        expect(ctx.chatHistory[0].role).toBe('system');
        expect(ctx.chatHistory[0].internal).toBe(true);
        expect(ctx.chatHistory[0].content).toContain('[Result of calculate]');
        expect(ctx.chatHistory[0].content).toContain('7006652'); // 1234*5678
    });

    itPy('에러 코드: stderr 가 ERROR 블록으로 재주입되어 자가수정 루프를 유도한다', async () => {
        const ctx = makeCtx('<calculate>print(undefined_variable_xyz)</calculate>');
        await applyCalculateActions(ctx);
        expect(ctx.report.some((r: string) => r.includes('failed'))).toBe(true);
        expect(ctx.chatHistory[0].content).toContain('[Result of calculate — ERROR]');
        expect(ctx.chatHistory[0].content).toContain('다시 emit');
    });

    itPy('print 누락: 빈 출력이면 print 힌트를 재주입한다', async () => {
        const ctx = makeCtx('<calculate>x = 40 + 2</calculate>');
        await applyCalculateActions(ctx);
        expect(ctx.chatHistory[0].content).toContain('EMPTY OUTPUT');
        expect(ctx.chatHistory[0].content).toContain('print');
    });

    itPy('여러 태그는 각각 실행되고, 한도(4개) 초과분은 건너뛴다', async () => {
        const tags = Array.from({ length: 6 }, (_, i) => `<calculate>print(${i} + 1)</calculate>`).join('\n');
        const ctx = makeCtx(tags);
        await applyCalculateActions(ctx);
        const results = ctx.chatHistory.filter((m: any) => m.content.includes('[Result of calculate]'));
        expect(results.length).toBe(4);
        expect(ctx.report.some((r: string) => r.includes('한도'))).toBe(true);
    });

    it('과도하게 긴 코드는 실행 전 차단한다', async () => {
        const ctx = makeCtx(`<calculate>${'x=1\n'.repeat(3000)}print(x)</calculate>`);
        await applyCalculateActions(ctx);
        expect(ctx.report.some((r: string) => r.includes('너무 깁니다'))).toBe(true);
        expect(ctx.chatHistory).toEqual([]);
    });
});
