import * as fs from 'fs';
import * as path from 'path';
import { logError, summarizeText } from '../../utils';
import type { ChatMessage } from '../../agent';
import { extractEvidenceFilesFromProjectKnowledge, extractPriorityPreviewFiles } from './projectEvidence';

/**
 * "이전 라운드에서 만든 project knowledge overview 문서" 를 *이번 답변의 근거* 로
 * 끌어오는 follow-up 흐름 + 답변 사후 근거 섹션 주입.
 *
 * 흐름:
 *   1) isProjectKnowledgeFollowupRequest — prompt 가 architecture/structure 류
 *      후속 질문인지 detect.
 *   2) findRecentProjectKnowledgeRecord — chat history 에서 옛 record path 추출
 *      → fallback 으로 `docs/records/**` 의 가장 최근 *_project_knowledge_overview.md.
 *   3) buildRecentProjectKnowledgeContext — record 본문을 5000자로 잘라 system prompt 에
 *      prepend.
 *   4) ensureRecentProjectKnowledgeEvidence / ensureLocalProjectPathEvidence — 모델
 *      답변에 "## 근거" 섹션이 없으면 끝에 자동 추가 (사용자가 근거 출처를 즉시
 *      확인할 수 있게).
 *   5) isBlockingProjectKnowledgeAnswer — 모델이 "방향 알려주세요" 류 blocking 답변을
 *      낸 경우 detect (호출자가 fallback path 로 우회).
 *
 * 모두 stateless — agent.ts 의 private 메서드를 그대로 추출. findRecord 만 옛
 * 버전이 `this.chatHistory` 를 직접 읽었는데 history 를 명시 arg 로 받게 변경.
 */

/**
 * Follow-up 질문 detection — architecture / structure / design 류 키워드가 한 개라도
 * 있으면 true. 옛 record 가 있을 때만 의미 있는 detection 이므로 호출자는 보통
 * `rootPath` 도 함께 체크.
 */
export function isProjectKnowledgeFollowupRequest(prompt: string): boolean {
    return /(아키텍처|구조|조사|분석|설계|흐름|모듈|역할|개선|architecture|structure|design|flow|module|investigate|analy[sz]e)/i.test(prompt);
}

/** "project evidence:" 라인에서 옛 record path 만 뽑아냄. 없으면 null. */
export function extractRecentProjectKnowledgeRecordPath(recentProjectKnowledgeContext: string): string | null {
    return recentProjectKnowledgeContext.match(/project evidence:\s*(\/Volumes\/Data\/project\/Antigravity\/[^\s`"'<>]+\.md)/i)?.[1] || null;
}

/**
 * Chat history → 옛 record path 추출 (가장 최근부터). history 에 없으면 fallback 으로
 * `docs/records/**` 를 직접 scan 해 mtime 기준 가장 최근 `*_project_knowledge_overview.md`
 * 를 반환. 둘 다 실패면 null.
 */
export function findRecentProjectKnowledgeRecord(history: ChatMessage[], rootPath: string): string | null {
    const fromHistory = [...history]
        .reverse()
        .map((message) => typeof message.content === 'string'
            ? message.content.match(/\/Volumes\/Data\/project\/Antigravity\/[^\s`"'<>]+_project_knowledge_overview\.md/i)?.[0]
            : undefined)
        .find(Boolean);
    if (fromHistory && fs.existsSync(fromHistory)) {
        return fromHistory;
    }

    const recordsRoot = path.join(rootPath, 'docs', 'records');
    if (!fs.existsSync(recordsRoot)) {
        return null;
    }

    const candidates: string[] = [];
    const visit = (dir: string, depth: number) => {
        if (depth > 5) return;
        let entries: fs.Dirent[] = [];
        try {
            entries = fs.readdirSync(dir, { withFileTypes: true });
        } catch {
            return;
        }
        for (const entry of entries) {
            const fullPath = path.join(dir, entry.name);
            if (entry.isDirectory()) {
                if (!entry.name.startsWith('.')) visit(fullPath, depth + 1);
                continue;
            }
            if (/_project_knowledge_overview\.md$/i.test(entry.name)) {
                candidates.push(fullPath);
            }
        }
    };
    visit(recordsRoot, 0);

    return candidates
        .filter((file) => fs.existsSync(file))
        .sort((a, b) => fs.statSync(b).mtimeMs - fs.statSync(a).mtimeMs)[0] || null;
}

/**
 * Follow-up 감지 시 옛 record 본문을 system prompt 에 prepend. 감지 안 되거나
 * record 가 없으면 빈 문자열. Content 는 5000자 cap (token 폭증 방지).
 */
export function buildRecentProjectKnowledgeContext(
    prompt: string,
    rootPath: string,
    history: ChatMessage[],
): string {
    if (!rootPath || !isProjectKnowledgeFollowupRequest(prompt)) {
        return '';
    }

    const recordPath = findRecentProjectKnowledgeRecord(history, rootPath);
    if (!recordPath) {
        return '';
    }

    try {
        const content = fs.readFileSync(recordPath, 'utf8');
        return [
            '[RECENT LOCAL PROJECT KNOWLEDGE]',
            'The current user request appears to continue a previous local project knowledge discussion.',
            `Use this recently generated project knowledge record as project evidence: ${recordPath}`,
            'When answering, explicitly say that the analysis is based on the recently generated project knowledge record and local project structure. Do not imply that Second Brain Trace was the only evidence.',
            'If deeper architecture detail is needed, recommend reading the concrete source files next instead of asking for the project path again.',
            '',
            summarizeText(content, 5000),
        ].join('\n');
    } catch (error: any) {
        logError('Failed to load recent project knowledge record.', { recordPath, error: error?.message || String(error) });
        return '';
    }
}

/**
 * 모델 답변에 record path 가 안 보이면 끝에 "## 근거" 섹션을 자동 추가. 이미
 * record path 가 포함돼 있으면 noop (중복 방지).
 */
export function ensureRecentProjectKnowledgeEvidence(content: string, recentProjectKnowledgeContext: string): string {
    const recordPath = extractRecentProjectKnowledgeRecordPath(recentProjectKnowledgeContext);
    if (!recordPath || content.includes(recordPath)) {
        return content;
    }

    const evidenceFiles = extractEvidenceFilesFromProjectKnowledge(recentProjectKnowledgeContext).slice(0, 8);
    const evidenceSection = [
        '## 근거',
        `이번 답변은 최근 생성된 프로젝트 지식 기록과 로컬 프로젝트 구조를 기준으로 작성했습니다: \`${recordPath}\``,
        evidenceFiles.length
            ? `확인된 근거 파일:\n${evidenceFiles.map((file) => `- \`${file}\``).join('\n')}`
            : '',
    ].filter(Boolean).join('\n\n');

    return [
        content.trim(),
        '',
        evidenceSection,
    ].join('\n');
}

/**
 * 모델 답변에 "## 근거" 가 없고 local path access 가 성공한 경우, 끝에 path
 * evidence 섹션을 자동 추가. recent record 경로가 아니라 *방금 inspect 한 로컬
 * 프로젝트 경로* 가 근거.
 */
export function ensureLocalProjectPathEvidence(content: string, localPathContext: string): string {
    if (!localPathContext.includes('Access: succeeded') || content.includes('## 근거')) {
        return content;
    }

    const pathMatch = localPathContext.match(/Path:\s*(.+)/);
    const projectPath = pathMatch?.[1]?.trim();
    const evidenceFiles = extractPriorityPreviewFiles(localPathContext).slice(0, 10);
    if (!projectPath && evidenceFiles.length === 0) {
        return content;
    }

    const evidenceSection = [
        '## 근거',
        projectPath
            ? `이번 답변은 로컬 프로젝트 경로 \`${projectPath}\`에서 확인한 파일 구조와 코드 프리뷰를 기준으로 작성했습니다.`
            : '이번 답변은 확인된 로컬 프로젝트 파일 구조와 코드 프리뷰를 기준으로 작성했습니다.',
        evidenceFiles.length
            ? `확인된 근거 파일:\n${evidenceFiles.map((file) => `- \`${file}\``).join('\n')}`
            : '',
    ].filter(Boolean).join('\n\n');

    return [
        content.trim(),
        '',
        evidenceSection,
    ].join('\n');
}

/**
 * 모델이 "방향 알려주세요 / 어떤 부분 먼저 / 구체적인 방향 필요" 같은 blocking 답변을
 * 만들었는지 detect. 호출자는 true 일 때 fallback path 로 우회해 자동 진행.
 */
export function isBlockingProjectKnowledgeAnswer(content: string): boolean {
    return /(블로킹 질문|어떤 기능 영역|어떤 부분.*먼저|어떤 기능이나 아키텍처|구체적인 방향|방향 설정이 필요|명확히 알려주시면|우선적으로 정리|최종 사용 목적|Question reason|별도의 파일 기록.*생성되지|파일 기록이 생성되지|더 깊이 있는 분석.*지정|해당 기능.*지정하여 요청)/i.test(content);
}
