import * as fs from 'fs';
import * as os from 'os';
import * as path from 'path';
import { AgentExecutor } from '../src/agent';
import { buildRequestHistory } from '../src/lib/contextBuilders/historyTransform';
import { isThinkingPartnerRequest, isCasualConversationPrompt } from '../src/lib/contextBuilders/promptDetection';
import { extractPriorityPreviewFiles } from '../src/lib/contextBuilders/projectEvidence';
import { buildJarvisProjectBriefContext } from '../src/lib/contextBuilders/jarvisProjectBrief';
import {
    shouldPreflightLocalProjectPath,
    classifyLocalProjectIntent,
    isProjectKnowledgeCreationRequest,
    isProjectReviewEvaluationRequest,
    buildLocalProjectIntentGuidance,
    buildAstraStanceContext,
} from '../src/lib/contextBuilders/localProjectIntent';
import {
    buildProjectKnowledgeFallbackAnswer,
    writeProjectKnowledgeRecord,
} from '../src/lib/contextBuilders/projectKnowledge';
import {
    inspectLocalProjectPath,
    enforceLocalPathReviewAnswer,
} from '../src/lib/contextBuilders/localProjectPath';
import {
    isBlockingProjectKnowledgeAnswer,
    buildRecentProjectKnowledgeContext,
    ensureRecentProjectKnowledgeEvidence,
    ensureLocalProjectPathEvidence,
} from '../src/lib/contextBuilders/recentProjectKnowledge';
import { isAstraModeArchitectureQuestion, buildAstraModeArchitectureContext } from '../src/lib/contextBuilders/astraModeArchitecture';
import { shouldUseMultiAgentWorkflow } from '../src/lib/contextBuilders/multiAgentRouting';

function stateStore() {
    const store = new Map<string, any>();
    return {
        get: (key: string) => store.get(key),
        update: async (key: string, value: any) => {
            store.set(key, value);
        }
    };
}

describe('local project path preflight', () => {
    let root: string;

    beforeEach(() => {
        root = fs.mkdtempSync(path.join(os.tmpdir(), 'g1-local-preflight-'));
        fs.mkdirSync(path.join(root, 'src', 'features', 'game', 'systems'), { recursive: true });
        fs.writeFileSync(path.join(root, 'package.json'), '{"scripts":{"dev":"vite"}}', 'utf8');
        fs.writeFileSync(path.join(root, 'src', 'features', 'game', 'systems', 'CombatSystem.ts'), 'export class CombatSystem {}', 'utf8');
    });

    afterEach(() => {
        fs.rmSync(root, { recursive: true, force: true });
    });

    it('previews deep source files instead of treating a project folder as empty', () => {
        const context: any = {
            globalStorageUri: { fsPath: path.join(root, '.storage') },
            workspaceState: stateStore(),
            globalState: stateStore()
        };
        const agent = new AgentExecutor(context) as any;

        const inspected = inspectLocalProjectPath(root, root);

        expect(inspected).toContain('Access: succeeded');
        expect(inspected).toContain('Priority file previews');
        expect(inspected).toContain('package.json');
        expect(inspected).toContain(path.join('src', 'features', 'game', 'systems', 'CombatSystem.ts'));
        expect(inspected).toContain('export class CombatSystem');
    });

    it('removes upload requests when local project access already succeeded', () => {
        const context: any = {
            globalStorageUri: { fsPath: path.join(root, '.storage') },
            workspaceState: stateStore(),
            globalState: stateStore()
        };
        const agent = new AgentExecutor(context) as any;
        const answer = '코드를 업로드해 주시면 검토하겠습니다.';
        const fixed = enforceLocalPathReviewAnswer(answer, 'Access: succeeded\nPriority file previews:\n### package.json');

        expect(fixed).toContain('제공된 로컬 프로젝트 경로에는 접근할 수 있고');
        expect(fixed).not.toContain('코드를 업로드해 주시면');
    });

    it('treats project knowledge creation requests with local paths as inspectable work', () => {
        const context: any = {
            globalStorageUri: { fsPath: path.join(root, '.storage') },
            workspaceState: stateStore(),
            globalState: stateStore()
        };
        const agent = new AgentExecutor(context) as any;
        const prompt = '그러면 지금 /Volumes/Data/project/Antigravity/ConnectAI 이 프로젝트에 대한 지식을 만들면 되는거 아니야?';

        expect(shouldPreflightLocalProjectPath(prompt)).toBe(true);
    });

    it('does not mistake a knowledge collection tool review for project knowledge creation', () => {
        const context: any = {
            globalStorageUri: { fsPath: path.join(root, '.storage') },
            workspaceState: stateStore(),
            globalState: stateStore()
        };
        const agent = new AgentExecutor(context) as any;
        const prompt = '/Volumes/Data/project/Antigravity/Datacollector_MAC 이 프로젝트는 재가 지식을 수집하는데 사용하는 프로그램이야. 이 프로그램을 너가 코드리뷰를 하고 이 프로그램에 대한 너의 평가를 듣고 싶어. 장점과 단점, 앞으로의 확장성은 어떻게 잡아야할지.';

        expect(shouldPreflightLocalProjectPath(prompt)).toBe(true);
        expect(isProjectReviewEvaluationRequest(prompt)).toBe(true);
        expect(isProjectKnowledgeCreationRequest(prompt)).toBe(false);
    });

    it('classifies local project intent by requested task instead of subject words', () => {
        const context: any = {
            globalStorageUri: { fsPath: path.join(root, '.storage') },
            workspaceState: stateStore(),
            globalState: stateStore()
        };
        const agent = new AgentExecutor(context) as any;
        const projectPath = '/Volumes/Data/project/Antigravity/Datacollector_MAC';

        expect(classifyLocalProjectIntent(`${projectPath} 지식 수집용 앱인데 한번 봐줘. 앞으로 확장성은?`)).toBe('review-evaluation');
        expect(classifyLocalProjectIntent(`${projectPath} 데이터 수집 프로그램이야. 장단점과 리스크 평가해줘.`)).toBe('review-evaluation');
        expect(classifyLocalProjectIntent(`${projectPath} 이 프로젝트에 대한 지식을 만들어줘.`)).toBe('knowledge-creation');
        expect(classifyLocalProjectIntent(`${projectPath} 이 프로젝트 README와 사용 가이드를 문서로 정리해줘.`)).toBe('documentation');
        expect(classifyLocalProjectIntent(`${projectPath} 이 프로젝트의 아키텍처 방향은 어떻게 생각해?`)).toBe('thinking');
    });

    it('adds deep review lenses for local project review intent', () => {
        const context: any = {
            globalStorageUri: { fsPath: path.join(root, '.storage') },
            workspaceState: stateStore(),
            globalState: stateStore()
        };
        const agent = new AgentExecutor(context) as any;
        const guidance = buildLocalProjectIntentGuidance('review-evaluation');

        expect(guidance).toContain('Intent operating contract — Code Review');
        // v2.2.64: review labels switched from markdown headers ("## 한 줄 판단") to plain-text
        // numbered labels ("1) 한 줄 판단") so the model doesn't learn to emit `##` in the answer.
        expect(guidance).toContain('1) 한 줄 판단');
        expect(guidance).toContain('2) 잘된 점');
        expect(guidance).toContain('3) 부족한 점');
        expect(guidance).toContain('4) 사용자 관점 개선');
        expect(guidance).toContain('5) 다음 한 수');
    });

    it('adds an Astra stance layer for opinionated project collaboration', () => {
        const context: any = {
            globalStorageUri: { fsPath: path.join(root, '.storage') },
            workspaceState: stateStore(),
            globalState: stateStore()
        };
        const agent = new AgentExecutor(context) as any;
        const prompt = '/Volumes/Data/project/Antigravity/Datacollector_MAC 이 지식 수집 앱을 평가해줘. 장점 단점 확장성도 보고 싶어.';
        const localPathContext = [
            'Path: /Volumes/Data/project/Antigravity/Datacollector_MAC',
            'Access: succeeded'
        ].join('\n');

        const stance = buildAstraStanceContext(prompt, localPathContext);

        expect(stance).toContain('[ASTRA STANCE LAYER]');
        expect(stance).toContain('not a template');
        expect(stance).toContain('State the real bet');
        expect(stance).toContain('Review stance');
        expect(stance).toContain('would rely on this project today');
        expect(stance).toContain('Local project intent for tone: review-evaluation');
    });

    // applyAstraQualityGate was removed in v2.80.31 to prefer model-generated answers over hardcoded templates.

    it('treats architecture opinion requests with local paths as inspectable work', () => {
        const context: any = {
            globalStorageUri: { fsPath: path.join(root, '.storage') },
            workspaceState: stateStore(),
            globalState: stateStore()
        };
        const agent = new AgentExecutor(context) as any;
        const prompt = '프로젝트 경로는 /Volumes/Data/project/Antigravity/ConnectAI 이야. 그럼 이 프로젝트에 대한 설계, 아키텍처는 어떤거 같아?';

        expect(shouldPreflightLocalProjectPath(prompt)).toBe(true);
        expect(isThinkingPartnerRequest(prompt)).toBe(true);
    });

    it('classifies short greetings as casual conversation so RAG can be skipped', () => {
        const context: any = {
            globalStorageUri: { fsPath: path.join(root, '.storage') },
            workspaceState: stateStore(),
            globalState: stateStore()
        };
        const agent = new AgentExecutor(context) as any;

        expect(isCasualConversationPrompt('안녕')).toBe(true);
        expect(isCasualConversationPrompt('hello!')).toBe(true);
        expect(isCasualConversationPrompt('안녕, 이 프로젝트 구조 분석해줘')).toBe(false);
        // expanded coverage: affirmations / negations / thanks / laughs (still small talk)
        expect(isCasualConversationPrompt('ㅇㅇ')).toBe(true);
        expect(isCasualConversationPrompt('알겠어')).toBe(true);
        expect(isCasualConversationPrompt('아니')).toBe(true);
        expect(isCasualConversationPrompt('고마워!!')).toBe(true);
        expect(isCasualConversationPrompt('ㅋㅋㅋ')).toBe(true);
        expect(isCasualConversationPrompt('hahaha')).toBe(true);
        expect(isCasualConversationPrompt('Thanks.')).toBe(true);
        // must NOT be treated as casual — these need memory / work, not a greeting reply
        expect(isCasualConversationPrompt('기억해?')).toBe(false);
        expect(isCasualConversationPrompt('방금 말한 거 이어서 해줘')).toBe(false);
        expect(isCasualConversationPrompt('이 함수 고쳐줘')).toBe(false);
        expect(isCasualConversationPrompt('')).toBe(false);
    });

    it('adds concrete Astra mode architecture context for Guard and MA design questions', () => {
        const context: any = {
            globalStorageUri: { fsPath: path.join(root, '.storage') },
            workspaceState: stateStore(),
            globalState: stateStore()
        };
        const agent = new AgentExecutor(context) as any;
        const prompt = '지금 우리는 guard 모드가 있고 MA 모드가 있는데 굳이 이렇게 모드를 분리해서 사용하는게 좋을까?';

        expect(isAstraModeArchitectureQuestion(prompt)).toBe(true);
        const modeContext = buildAstraModeArchitectureContext(prompt);
        expect(modeContext).toContain('Confirmed implementation facts');
        expect(modeContext).toContain('Guard should be an always-on policy/context layer');
        expect(modeContext).toContain('MA should be an optional execution strategy');
        expect(modeContext).toContain('richer context assembly');
    });

    it('keeps Guard and MA out of the visible sidebar controls', () => {
        const sidebarSource = fs.readFileSync(path.join(__dirname, '..', 'src', 'sidebarProvider.ts'), 'utf8');

        expect(sidebarSource).not.toContain('id="designerGuardBtn"');
        expect(sidebarSource).not.toContain('id="multiAgentBtn"');
    });

    it('routes multi-agent automatically for report-style tasks but not local project preflight', () => {
        const context: any = {
            globalStorageUri: { fsPath: path.join(root, '.storage') },
            workspaceState: stateStore(),
            globalState: stateStore()
        };
        const agent = new AgentExecutor(context) as any;

        expect(shouldUseMultiAgentWorkflow('시장 조사 기반으로 긴 보고서를 작성해줘', false)).toBe(true);
        expect(shouldUseMultiAgentWorkflow('프로젝트 경로는 /Volumes/Data/project/Antigravity/ConnectAI 이야. 아키텍처 봐줘', false)).toBe(false);
        expect(shouldUseMultiAgentWorkflow('guard 모드와 MA 모드를 분리하는게 좋을까?', true)).toBe(false);
    });

    it('removes file-structure requests when knowledge creation path access already succeeded', () => {
        const context: any = {
            globalStorageUri: { fsPath: path.join(root, '.storage') },
            workspaceState: stateStore(),
            globalState: stateStore()
        };
        const agent = new AgentExecutor(context) as any;
        const answer = '프로젝트에 대한 지식을 만들고 싶다면, 먼저 해당 프로젝트의 핵심 파일이나 구조를 저에게 제공해 주셔야 합니다. 실제 구현 근거 없이는 유용한 지식을 만들 수 없습니다.';
        const fixed = enforceLocalPathReviewAnswer(answer, 'Access: succeeded\nPriority file previews:\n### package.json');

        expect(fixed).toContain('액션 태그를 통해 스스로 필요한 코드를 열어보겠습니다');
        expect(fixed).not.toContain('핵심 파일이나 구조를 저에게 제공');
        expect(fixed).not.toContain('실제 구현 근거 없이는');
    });

    it('replaces blocking scope questions for local project knowledge creation', () => {
        const context: any = {
            globalStorageUri: { fsPath: path.join(root, '.storage') },
            workspaceState: stateStore(),
            globalState: stateStore()
        };
        const agent = new AgentExecutor(context) as any;
        const answer = '## 블로킹 질문\n1. 어떤 기능 영역을 가장 먼저 분석하고 싶으신가요? (Question reason: 범위 조정)';
        const localPathContext = [
            'Path: /Volumes/Data/project/Antigravity/ConnectAI',
            'Access: succeeded',
            'Type: directory',
            'Scanned tree:',
            'src/',
            'src/agent.ts',
            'Priority file previews:',
            'File: package.json',
            '{"name":"g1nation"}',
            'File: src/agent.ts',
            'export class AgentExecutor {}'
        ].join('\n');

        expect(isBlockingProjectKnowledgeAnswer(answer)).toBe(true);
        const fallback = buildProjectKnowledgeFallbackAnswer(localPathContext);
        expect(fallback).toContain('추가 질문으로 멈출 필요 없이');
        expect(fallback).toContain('Astra Project Knowledge Overview');
        expect(fallback).not.toContain('어떤 기능 영역을 가장 먼저');
    });

    // misrouted project-knowledge answer replacement for reviews was removed to favor flexible model responses.

    // isShallowProjectReviewAnswer was removed in favor of system-prompt-driven quality.

    it('treats no-record-created answers as incomplete project knowledge creation', () => {
        const context: any = {
            globalStorageUri: { fsPath: path.join(root, '.storage') },
            workspaceState: stateStore(),
            globalState: stateStore()
        };
        const agent = new AgentExecutor(context) as any;
        const answer = 'Record Path Check: 요청하신 지식 생성 작업은 파일 목록 검토를 통해 완료되었으며, 별도의 파일 기록이 생성되지 않았습니다.';

        expect(isBlockingProjectKnowledgeAnswer(answer)).toBe(true);
    });

    it('extracts only preview file markers, not markdown headings inside previews', () => {
        const context: any = {
            globalStorageUri: { fsPath: path.join(root, '.storage') },
            workspaceState: stateStore(),
            globalState: stateStore()
        };
        const agent = new AgentExecutor(context) as any;
        const localPathContext = [
            'Priority file previews:',
            'File: README.md',
            '### 1. 벡터화된 고성능 추론 엔진',
            'File: src/agent.ts',
            'export class AgentExecutor {}'
        ].join('\n');

        expect(extractPriorityPreviewFiles(localPathContext)).toEqual(['README.md', 'src/agent.ts']);
    });

    it('writes a project knowledge record for accessible local project context', () => {
        const context: any = {
            globalStorageUri: { fsPath: path.join(root, '.storage') },
            workspaceState: stateStore(),
            globalState: stateStore()
        };
        const agent = new AgentExecutor(context) as any;
        const localPathContext = [
            `Path: ${root}`,
            'Access: succeeded',
            'Type: directory',
            'Scanned tree:',
            'package.json',
            'src/',
            'Priority file previews:',
            'File: package.json',
            '{"name":"g1nation"}',
            'File: src/features/game/systems/CombatSystem.ts',
            'export class CombatSystem {}'
        ].join('\n');

        const record = writeProjectKnowledgeRecord(localPathContext)!;

        expect(record?.filePath).toBeTruthy();
        expect(fs.existsSync(record.filePath)).toBe(true);
        const content = fs.readFileSync(record.filePath, 'utf8');
        expect(content).toContain('Project Knowledge Overview');
        expect(content).toContain('package.json');
        expect(content).toContain('src/features/game/systems/CombatSystem.ts');
    });

    it('uses the latest project knowledge record for architecture follow-up questions without a path', () => {
        const context: any = {
            globalStorageUri: { fsPath: path.join(root, '.storage') },
            workspaceState: stateStore(),
            globalState: stateStore()
        };
        const agent = new AgentExecutor(context) as any;
        const recordDir = path.join(root, 'docs', 'records', path.basename(root), 'development');
        fs.mkdirSync(recordDir, { recursive: true });
        const recordPath = path.join(recordDir, '2026-05-02_project_knowledge_overview.md');
        fs.writeFileSync(
            recordPath,
            [
                '# Project Knowledge Overview',
                '',
                '## Confirmed Structure',
                '- `src/agent.ts`: 에이전트 실행 흐름의 중심.',
                '- `src/sidebarProvider.ts`: Webview UI를 담당.'
            ].join('\n'),
            'utf8'
        );

        const followup = buildRecentProjectKnowledgeContext('이젠 아키텍처에 대한 조사도 해주면 좋을 것 같아.', root, []);

        expect(followup).toContain('[RECENT LOCAL PROJECT KNOWLEDGE]');
        expect(followup).toContain(recordPath);
        expect(followup).toContain('src/agent.ts');
        expect(followup).toContain('recently generated project knowledge record');
    });

    it('removes old Second Brain trace details from assistant history before model requests', () => {
        const context: any = {
            globalStorageUri: { fsPath: path.join(root, '.storage') },
            workspaceState: stateStore(),
            globalState: stateStore()
        };
        const agent = new AgentExecutor(context) as any;
        const history = [
            { role: 'user', content: 'ConnectAI 지식 만들어줘' },
            {
                role: 'assistant',
                content: [
                    '## 간단 요약',
                    'ConnectAI 프로젝트 지식을 만들었습니다.',
                    '<details>',
                    '<summary>2nd Brain Trace: 사용함</summary>',
                    'Project_Logs/2026-04-25-Datacollector_Fix.md',
                    '## Second Brain Debug JSON',
                    '{"path":"Datacollector"}',
                    '</details>'
                ].join('\n')
            }
        ];

        const requestHistory = buildRequestHistory(history as any);

        expect(requestHistory[1].content).toContain('ConnectAI 프로젝트 지식을 만들었습니다');
        expect(requestHistory[1].content).not.toContain('Datacollector');
        expect(requestHistory[1].content).not.toContain('2nd Brain Trace');
    });

    it('adds visible evidence when answering from recent project knowledge context', () => {
        const context: any = {
            globalStorageUri: { fsPath: path.join(root, '.storage') },
            workspaceState: stateStore(),
            globalState: stateStore()
        };
        const agent = new AgentExecutor(context) as any;
        const recordPath = '/Volumes/Data/project/Antigravity/ConnectAI/docs/records/ConnectAI/development/2026-05-02_connectai_project_knowledge_overview.md';
        const recentContext = [
            '[RECENT LOCAL PROJECT KNOWLEDGE]',
            `Use this recently generated project knowledge record as project evidence: ${recordPath}`,
            '',
            '# Astra Project Knowledge Overview',
            '',
            '## Evidence Files',
            '- `package.json`',
            '- `src/agent.ts`',
            '- `src/sidebarProvider.ts`'
        ].join('\n');
        const answer = '## 간단 요약\nConnectAI 아키텍처는 실행 흐름 분리를 중심으로 구성됩니다.';

        const fixed = ensureRecentProjectKnowledgeEvidence(answer, recentContext);

        expect(fixed).toContain('## 근거');
        expect(fixed).toContain(recordPath);
        expect(fixed).toContain('`src/agent.ts`');
        expect(fixed).toContain('최근 생성된 프로젝트 지식 기록');
    });

    it('adds visible evidence when answering from an explicit local project path', () => {
        const context: any = {
            globalStorageUri: { fsPath: path.join(root, '.storage') },
            workspaceState: stateStore(),
            globalState: stateStore()
        };
        const agent = new AgentExecutor(context) as any;
        const localPathContext = [
            'Path: /Volumes/Data/project/Antigravity/ConnectAI',
            'Access: succeeded',
            'Type: directory',
            'Scanned tree:',
            'package.json',
            'src/agent.ts',
            'Priority file previews:',
            'File: package.json',
            '```json',
            '{"name":"connectai"}',
            '```',
            'File: src/agent.ts',
            '```ts',
            'export class AgentExecutor {}',
            '```'
        ].join('\n');
        const answer = '## 간단 요약\nConnectAI 아키텍처는 실행 흐름 분리를 중심으로 구성됩니다.';

        const fixed = ensureLocalProjectPathEvidence(answer, localPathContext);

        expect(fixed).toContain('## 근거');
        expect(fixed).toContain('/Volumes/Data/project/Antigravity/ConnectAI');
        expect(fixed).toContain('`package.json`');
        expect(fixed).toContain('`src/agent.ts`');
        expect(fixed).toContain('로컬 프로젝트 경로');
    });

    it('builds a Jarvis project brief for architecture thinking-partner questions', () => {
        const context: any = {
            globalStorageUri: { fsPath: path.join(root, '.storage') },
            workspaceState: stateStore(),
            globalState: stateStore()
        };
        const agent = new AgentExecutor(context) as any;
        const localPathContext = [
            'Path: /Volumes/Data/project/Antigravity/ConnectAI',
            'Access: succeeded',
            'Type: directory',
            'Scanned tree:',
            'package.json',
            'src/agent.ts',
            'src/features/secondBrainTrace.ts',
            'Priority file previews:',
            'File: package.json',
            '{"name":"connectai"}',
            'File: src/agent.ts',
            'export class AgentExecutor {}'
        ].join('\n');

        const brief = buildJarvisProjectBriefContext(
            '그럼 이 프로젝트에 대한 설계, 아키텍처는 어떤거 같아?',
            localPathContext,
            ''
        );

        expect(brief).toContain('[JARVIS PROJECT BRIEF]');
        expect(brief).toContain('/Volumes/Data/project/Antigravity/ConnectAI');
        expect(brief).toContain('src/agent.ts');
        expect(brief).toContain('Thinking partner response contract');
        expect(brief).toContain('direct verdict');
        expect(brief).toContain('decision fork');
    });
});
