import type { ApprovalDecision } from '../../features/company/dispatcher';

/**
 * 회사 모드 dispatcher 의 stage approval gate 들을 관리.
 *
 * 의도: dispatcher 가 stage 산출물 (예: 기획서 초안) 을 만든 후 사용자 승인을
 * 기다릴 때, sidebarProvider 가 *resolver* 를 등록해두고 사용자가 채팅 카드의
 * 버튼을 누르면 `resolve(stageId, decision)` 호출로 dispatcher 를 깨운다.
 *
 * 옛 코드는 이 Map 을 sidebarProvider 의 13개 state slot 중 하나로 박아두고
 * 직접 set/get/delete 했는데, 그 결과:
 *   - turn abort 시 정리 책임이 어디에 있는지 모호 (clear() 호출이 누락된
 *     code path 존재 가능성)
 *   - 새 manager (예: 다른 종류의 gate) 추가 시 또 sidebarProvider 본문 부풀음
 *
 * Manager 클래스로 격리해 (a) 정리 책임 한 곳, (b) 단위 테스트 용이성,
 * (c) 새 매니저 추가 시 본문 변경 최소화 달성.
 */
export class ApprovalGateManager {
    private readonly pending = new Map<string, (d: ApprovalDecision) => void>();

    /**
     * Dispatcher 가 stage approval 대기 진입 시 resolver 등록. 사용자가 카드 버튼을
     * 누르면 `resolve()` 가 호출돼 await 가 깨어남.
     */
    register(stageId: string, resolver: (d: ApprovalDecision) => void): void {
        // 같은 stageId 가 이미 등록돼 있으면 그건 dispatcher 의 중복 호출 — 기존
        // resolver 를 abort 로 처리해 dangling promise 방지.
        const existing = this.pending.get(stageId);
        if (existing) {
            try { existing({ kind: 'abort' }); } catch { /* noop */ }
        }
        this.pending.set(stageId, resolver);
    }

    /**
     * 사용자 카드 클릭 → 등록된 resolver 호출. 등록 없으면 false (이미 timeout / abort
     * 됐을 가능성). true 면 dispatcher 의 await 가 깨어났음.
     */
    resolve(stageId: string, decision: ApprovalDecision): boolean {
        const resolver = this.pending.get(stageId);
        if (!resolver) return false;
        this.pending.delete(stageId);
        try { resolver(decision); } catch { /* dispatcher 가 try 안에서 await 함, 무시 */ }
        return true;
    }

    /**
     * Turn abort 시 모든 대기 중인 gate 를 abort 로 정리. dispatcher 의 모든 stage
     * await 가 깨어나면서 turn 이 깨끗하게 종료된다.
     */
    abortAll(): void {
        for (const resolver of this.pending.values()) {
            try { resolver({ kind: 'abort' }); } catch { /* noop */ }
        }
        this.pending.clear();
    }

    /** 디버그 — 현재 대기 중인 gate 수. */
    get count(): number {
        return this.pending.size;
    }
}
