import { listActiveAgentsByCategory, resolveAgent } from './companyConfig';
import type {
    AgentRoleCategory,
    AgentTurnOutput,
    CompanyState,
    PipelineStage,
} from './types';

/**
 * `dispatcher.ts` 의 6개 stateless helper 모음. dispatcher 본 흐름에서 떼어내
 * (a) 단위 테스트 가능, (b) parsing 정책 변경 시 한 곳만 수정.
 *
 *   - resolveInspector(reviewWith, state)     — `inspector` / `role:<cat>` / `agent:<id>` 라우팅
 *   - parseInspectorVerdict(text)             — pass / revise / unclear
 *   - parseCeoVerdict(text)                   — pass / revise / abort / unclear
 *   - renderStageInstruction(stage, ...)      — instruction 템플릿 토큰 치환
 *   - hasActionTag(text)                      — action-tag 존재 cheap pre-check
 *   - claimsFileCreation(text)                — past-tense 파일 생성 narration 검출
 */

/**
 * 검수자 (또는 직군) 를 stage.reviewWith 값에 따라 한 명 결정:
 *   - 'inspector'       → inspector 직군 활성 후보 중 첫 번째
 *   - 'role:<cat>'      → 해당 직군 활성 후보 중 첫 번째
 *   - 'agent:<id>'      → 그 에이전트 (활성/비활성 무관)
 * 후보 없으면 null — 호출자가 검수 사이클 skip.
 */
export function resolveInspector(reviewWith: string, state: CompanyState): { agentId: string } | null {
    if (reviewWith === 'inspector') {
        const list = listActiveAgentsByCategory(state)['inspector'] ?? [];
        return list[0] ? { agentId: list[0].id } : null;
    }
    if (reviewWith.startsWith('role:')) {
        const cat = reviewWith.slice(5) as AgentRoleCategory;
        const list = listActiveAgentsByCategory(state)[cat] ?? [];
        return list[0] ? { agentId: list[0].id } : null;
    }
    if (reviewWith.startsWith('agent:')) {
        const id = reviewWith.slice(6);
        return resolveAgent(state, id) ? { agentId: id } : null;
    }
    return null;
}

/**
 * 검수자 응답의 verdict 추출. 작은 모델이 라벨 흐트러뜨릴 수 있어 키워드 매칭으로
 * 관대하게. 못 잡으면 'unclear' — 호출자가 안전한 쪽 (보통 'revise') 으로 폴백.
 */
export function parseInspectorVerdict(text: string): 'pass' | 'revise' | 'unclear' {
    const head = (text || '').split(/\n/, 1)[0] ?? '';
    if (/^\s*(?:✅|통과|승인|pass|approve|ok)/i.test(head)) return 'pass';
    if (/^\s*(?:❌|보완|재작업|revise|reject|fail|보완 필요)/i.test(head)) return 'revise';
    // 본문에 명확한 신호가 있으면 잡아냄 — 작은 모델이 머리말을 빠뜨리는 경우.
    if (/✅\s*통과|모든 케이스 통과/.test(text)) return 'pass';
    if (/❌|보완 필요|재작업/.test(text)) return 'revise';
    return 'unclear';
}

/**
 * CEO 메타-판단 verdict. pass / revise / abort / unclear. 검수자 verdict 와 같은
 * 키워드-우선 휴리스틱이지만 abort 옵션이 추가됨 (의도적으로 중단).
 */
export function parseCeoVerdict(text: string): 'pass' | 'revise' | 'abort' | 'unclear' {
    const head = (text || '').split(/\n/, 1)[0] ?? '';
    if (/^\s*(?:✅|통과|approve|pass|최종\s*ok|진행)/i.test(head)) return 'pass';
    if (/^\s*(?:🔁|보완|한 번 더|revise|다시)/i.test(head)) return 'revise';
    if (/^\s*(?:🛑|중단|stop|abort|그만)/i.test(head)) return 'abort';
    if (/✅\s*통과/.test(text)) return 'pass';
    if (/🛑|중단/.test(text)) return 'abort';
    if (/🔁|보완|한 번 더/.test(text)) return 'revise';
    return 'unclear';
}

/**
 * Stage instruction 의 템플릿 토큰 치환. 템플릿 비어 있으면 raw user prompt 그대로
 * 폴백 — 사용자가 매 stage 마다 긴 템플릿을 채울 필요 없게.
 *
 * 지원 토큰:
 *   - {{userPrompt}}        — 원본 사용자 prompt
 *   - {{brief}}             — 플래너가 생성한 brief
 *   - {{stage.<sid>}}       — 다른 stage 의 가장 최근 response (미실행 시 placeholder)
 */
export function renderStageInstruction(
    stage: PipelineStage,
    userPrompt: string,
    brief: string,
    latestByStage: Record<string, AgentTurnOutput>,
): string {
    const tpl = (stage.instructionTemplate || '').trim();
    if (!tpl) return userPrompt;
    return tpl
        .replace(/\{\{\s*userPrompt\s*\}\}/g, userPrompt)
        .replace(/\{\{\s*brief\s*\}\}/g, brief)
        .replace(/\{\{\s*stage\.([a-zA-Z0-9_-]+)\s*\}\}/g, (_m, sid) => {
            const o = latestByStage[sid];
            return o?.response ?? `[stage:${sid} 아직 실행되지 않음]`;
        });
}

/**
 * Cheap pre-check — text 에 어떤 action-tag 라도 있으면 true. action-tag executor
 * 를 매 specialist 응답마다 띄우지 않게 가드.
 */
export function hasActionTag(text: string): boolean {
    return /<\s*(?:create_file|edit_file|delete_file|read_file|list_files|list_brain|run_command|read_brain|reveal_in_explorer|open_file|glob|grep)\b/i.test(text);
}

/**
 * Heuristic: response 가 *narrate* "파일 생성했음" 했는지 (action-tag 없이).
 *
 * 과거형 / 완료 표현 + 파일/폴더 mention 둘 다 있어야 true. plan ("다음에 X 를 만들어야")
 * 같은 미래형은 의도적으로 안 잡음. agent 가 `<create_file>` 태그 안 쓰고 "foo.py
 * 파일을 생성했습니다" 환각하는 패턴 검출 → dispatcher 가 CEO 와 사용자에게 flag.
 */
export function claimsFileCreation(text: string): boolean {
    const claimRe = /(?:생성했|만들었|작성했|저장했|구현했|created|wrote|saved|built|generated)/i;
    if (!claimRe.test(text)) return false;
    const fileLike = /\b[\w\-./]+\.(?:py|js|ts|tsx|jsx|md|json|html|css|sh|yaml|yml|sql|java|go|rs|c|cpp|rb|php)\b/i.test(text);
    const folderLike = /(?:폴더|디렉토리|directory|folder)/i.test(text);
    return fileLike || folderLike;
}
