import * as vscode from 'vscode';
import type {
    ApprovalDecision,
    CompanyTurnEvent,
    DispatcherDeps,
    RequirementContract,
} from '../../features/company';
import type { ApprovalGateManager } from '../managers/approvalGates';
import type { AIService } from '../../core/services';
import { getConfig } from '../../config';

/**
 * 1인 기업 turn 의 `DispatcherDeps` 객체를 조립하는 빌더. 옛 코드는 sidebarProvider
 * 의 `_runCompanyTurn` 안에서 inline 으로 37줄짜리 객체를 만들고 있었음 — 인자 6개
 * + closure 2개가 한 자리에 섞여 가독성이 낮았다.
 *
 * 빌더는 *순수 조립* 만 책임 — config 읽기 / approval 등록 등의 closure 는 호출자
 * 가 전달하는 deps 로부터 생성. 실제 turn 실행 (`runCompanyTurn` / `resumeCompanyTurn`)
 * 은 여전히 provider 가 호출.
 */

/** Provider 가 미리 준비해서 넘기는 closure deps — 각 항목이 instance state 1개에 1대1 매칭. */
export interface DispatcherDepsInputs {
    context: vscode.ExtensionContext;
    ai: AIService;
    signal: AbortSignal;
    onEvent: (event: CompanyTurnEvent) => void;
    /** Action tag (`<create_file>` 등) 를 실제 파일시스템에 적용. AgentExecutor 의 thunk. */
    executeActionTags: (text: string) => Promise<string[]>;
    /** 승인 게이트 — dispatcher 가 await 할 Promise 의 resolver 를 등록 받는다. */
    approvalGates: ApprovalGateManager;
    /** 이번 turn 한정 pipeline override. chatHandlers 가 의도 분류기 결과로 채움. */
    pipelineIdOverride?: string;
    /** Intent Alignment 가 도출한 사용자 합의 contract. 없으면 legacy 동작. */
    requirementContract?: RequirementContract;
    /** 현재 워크스페이스 아키텍처 컨텍스트 (호출자가 절단해 전달). */
    architectureContextBlock?: string;
    /** 사용자 프롬프트 URL pre-fetch 결과 ([URL CONTENT] 블록). */
    webContextBlock?: string;
}

export function buildDispatcherDeps(inputs: DispatcherDepsInputs): DispatcherDeps {
    const cfg = getConfig();
    return {
        context: inputs.context,
        ai: inputs.ai,
        defaultModel: cfg.defaultModel || 'gemma4:e2b',
        // Knowledge Mix wiring — 회사 specialists 도 사용자의 Second Brain 을 같은
        // global 기본값 + per-agent override semantics 로 사용. 없으면 Knowledge Mix
        // 슬라이더가 회사 turn 에 영향 없음.
        globalKnowledgeMixWeight: cfg.knowledgeMixSecondBrainWeight ?? 50,
        brainFileBaseline: cfg.memoryLongTermFiles ?? 6,
        // Specialist 출력 (예: `<create_file>`) 을 실제 디스크에 적용. 없으면 agents 가
        // "파일 만들었다" 고만 주장하고 실제 디스크엔 아무 일도 안 일어남.
        executeActionTags: inputs.executeActionTags,
        signal: inputs.signal,
        onEvent: inputs.onEvent,
        // 승인 게이트 bridge — dispatcher 가 호출하면 Promise 생성 + resolver 를
        // approvalGates 에 등록. chatHandlers 가 카드 버튼 클릭으로 resolve 호출.
        // signal 이 이미 aborted 면 즉시 abort 결과로 resolve (await 무한 대기 방지).
        awaitApproval: ({ stageId }: { stageId: string; stageLabel: string }) =>
            new Promise<ApprovalDecision>((resolve) => {
                if (inputs.signal.aborted) {
                    resolve({ kind: 'abort' });
                    return;
                }
                inputs.approvalGates.register(stageId, resolve);
            }),
        pipelineIdOverride: inputs.pipelineIdOverride,
        requirementContract: inputs.requirementContract,
        architectureContextBlock: inputs.architectureContextBlock,
        webContextBlock: inputs.webContextBlock,
    };
}
