/**
 * Research Agent — 학습 큐 approved 항목의 조사 실행 (설계서 9장).
 *
 * Self-Evolving OS 마스터 플랜 Phase 6 / Track 7-1. 학습 루프의 마지막 구간:
 *   Need Engine → Learning Queue(approved) → **Research Agent** → Validation 게이트 → 저장 제안
 *
 * v1 은 "조사 패키지 준비자" — 로컬 환경의 정직한 한계 안에서 동작한다:
 *   1. 조사 브리프 생성 (LLM 1회): 핵심 질문·검색 키워드·권장 출처 유형
 *   2. 내부 지식 현황: 두뇌 검색 상위 문서 수집 (이미 아는 것 파악)
 *   3. 모델 지식 초안: *모든 내용에 추정 라벨* — 출처 없는 지식이므로
 *   4. Knowledge Validation 게이트: 출처 없음 → 대부분 review (자동 저장 안 됨)
 *   5. 다음 단계 안내: /research·/benchmark (Datacollect Bridge) 로 외부 근거 수집 후 승인
 *
 * 산출물은 <brain>/.astra/growth/proposals/<id>.md — 사람이 검토·보강·승인하는
 * 제안 문서다. 두뇌 본문에 자동 저장하지 않는다 (Permission Based Learning).
 */

import type { QueueItem } from './learningQueue';
import { validateKnowledgeCandidate, ExistingKnowledgeRef, ValidationResult } from './knowledgeValidation';

export interface ResearchBrief {
    questions: string[];
    keywords: string[];
    sourceTypes: string[];
}

export interface ResearchPackage {
    queueItemId: string;
    topic: string;
    brief: ResearchBrief;
    /** 내부(두뇌) 관련 문서 — 이미 아는 것. */
    internalRefs: ExistingKnowledgeRef[];
    /** 모델 지식 초안 (추정 라벨 포함). */
    draft: string;
    validation: ValidationResult;
}

export type ResearchLlmCall = (system: string, user: string, maxTokens: number) => Promise<string>;

/** 브리프 JSON 파싱 — criticAgent 와 같은 균형 괄호 추출 전략의 단순판. */
export function parseBrief(raw: string): ResearchBrief | null {
    const start = raw.indexOf('{');
    const end = raw.lastIndexOf('}');
    if (start === -1 || end <= start) return null;
    try {
        const obj = JSON.parse(raw.slice(start, end + 1));
        const arr = (v: any) => Array.isArray(v) ? v.filter((x) => typeof x === 'string').slice(0, 8) : [];
        const brief: ResearchBrief = { questions: arr(obj.questions), keywords: arr(obj.keywords), sourceTypes: arr(obj.sourceTypes) };
        return brief.questions.length > 0 ? brief : null;
    } catch {
        return null;
    }
}

/** LLM 실패 시에도 루프가 멈추지 않도록 — 주제 기반 최소 브리프. */
export function fallbackBrief(topic: string): ResearchBrief {
    return {
        questions: [`${topic} 의 핵심 개념과 현재 표준은 무엇인가?`, `${topic} 에서 자주 발생하는 실수와 베스트 프랙티스는?`],
        keywords: [topic],
        sourceTypes: ['공식 문서', '최근 1년 내 자료'],
    };
}

export async function runResearch(params: {
    item: QueueItem;
    /** 두뇌에서 주제 관련 기존 문서를 가져오는 함수 (orchestrator 주입). */
    fetchInternalRefs: (topic: string) => Promise<ExistingKnowledgeRef[]>;
    callLlm: ResearchLlmCall;
    nowIso: string;
}): Promise<ResearchPackage> {
    const { item } = params;

    // ─── 1. 조사 브리프 (LLM — 계획 수립은 환각 위험이 낮은 용도) ───
    const briefSystem = [
        '너는 조사 계획 수립자다. 주어진 학습 주제에 대한 조사 브리프를 만든다.',
        '반드시 아래 JSON 만 출력:',
        '{"questions": ["핵심 질문 3~5개"], "keywords": ["검색 키워드 3~6개"], "sourceTypes": ["권장 출처 유형 2~4개"]}',
    ].join('\n');
    let brief: ResearchBrief;
    try {
        const raw = await params.callLlm(briefSystem, `학습 주제: ${item.topic}\n선정 사유: ${item.reason}`, 400);
        brief = parseBrief(raw) ?? fallbackBrief(item.topic);
    } catch {
        brief = fallbackBrief(item.topic);
    }

    // ─── 2. 내부 지식 현황 ───
    let internalRefs: ExistingKnowledgeRef[] = [];
    try {
        internalRefs = await params.fetchInternalRefs(item.topic);
    } catch { /* 검색 실패 → 빈 현황으로 진행 */ }

    // ─── 3. 모델 지식 초안 — 전부 추정 라벨 강제 ───
    const draftSystem = [
        '너는 학습 노트 초안 작성자다. 주어진 질문들에 대해 아는 것을 정리한다.',
        '중요: 너의 일반 지식은 출처가 없다. 모든 단락 끝에 "(모델 지식 — 추정, 출처 확인 필요)" 를 붙일 것.',
        '모르는 것은 "모름 — 외부 조사 필요" 로 솔직히 표시. 지어내기 금지.',
        '마크다운 ## 섹션으로 질문별 정리.',
    ].join('\n');
    let draft = '';
    try {
        draft = await params.callLlm(draftSystem, brief.questions.map((q, i) => `${i + 1}. ${q}`).join('\n'), 1200);
    } catch {
        draft = '(초안 생성 실패 — 외부 조사로 직접 작성 필요)';
    }

    // ─── 4. Validation 게이트 — 출처 없는 초안은 자동 수용되지 않는다 ───
    const validation = validateKnowledgeCandidate(
        { title: item.topic, content: draft, collectedAt: params.nowIso /* source 의도적 누락 */ },
        internalRefs,
    );

    return { queueItemId: item.id, topic: item.topic, brief, internalRefs, draft, validation };
}

export function formatProposalMarkdown(pkg: ResearchPackage, meta: { dateStr: string; modelName: string }): string {
    const lines: string[] = [];
    lines.push(`# 학습 제안 — ${pkg.topic}`);
    lines.push('');
    lines.push(`- 생성: ${meta.dateStr} · 모델: ${meta.modelName} · 큐 항목: ${pkg.queueItemId}`);
    lines.push(`- **검증 판정: ${pkg.validation.verdict}** — ${pkg.validation.reasons.join(' / ')}`);
    lines.push('');
    lines.push('## 1. 조사 브리프');
    lines.push('');
    lines.push('**핵심 질문**');
    for (const q of pkg.brief.questions) lines.push(`- ${q}`);
    lines.push('');
    lines.push(`**검색 키워드**: ${pkg.brief.keywords.join(', ')}`);
    lines.push(`**권장 출처**: ${pkg.brief.sourceTypes.join(', ')}`);
    lines.push('');
    lines.push('## 2. 내부 지식 현황 (두뇌에 이미 있는 것)');
    lines.push('');
    if (pkg.internalRefs.length === 0) {
        lines.push('- 관련 문서 없음 — 완전한 신규 영역');
    } else {
        for (const ref of pkg.internalRefs) {
            lines.push(`- \`${ref.filePath || ref.title}\``);
        }
    }
    lines.push('');
    lines.push('## 3. 모델 지식 초안 (출처 없음 — 검증 전 사용 금지)');
    lines.push('');
    lines.push(pkg.draft);
    lines.push('');
    lines.push('## 4. 다음 단계');
    lines.push('');
    lines.push('1. 위 키워드로 외부 근거 수집 — ASTRA 채팅에서 `/research` 또는 `/benchmark` (Datacollect Bridge 필요)');
    lines.push('2. 수집 근거로 초안을 보강·교정 (추정 라벨 제거는 출처 확보 후에만)');
    lines.push('3. 완성본을 두뇌 적절한 폴더에 저장하면 다음 turn 부터 검색에 반영됨');
    lines.push('4. learning-queue.json 에서 이 항목 status 를 done 으로 변경');
    lines.push('');
    return lines.join('\n');
}
