import type { RequirementContract } from '../../features/company';

/**
 * 1인 기업 모드 turn 의 runtime 상태 — *진행 중* turn 의 abort handle 과
 * *방금 끝난* turn 의 요약 스냅샷을 함께 보관.
 *
 * 옛 코드는 sidebarProvider 의 두 slot(`_companyAbort`, `_lastCompanyTurnSummary`)
 * 으로 흩어져 있어, "turn 끝" 시 abort 정리와 summary 갱신이 서로 다른 분기에서
 * 일어났음. Manager 로 묶어 turn lifecycle 의 진입/종료 책임을 한 곳에 모았다.
 *
 * Summary 슬롯은 *완료된* turn 만 채운다 (abort/error 는 비움 유지) — intent
 * classifier 가 "이전 turn 후속" vs "신규 task" 를 판단할 때 abort 된 turn 을
 * 후속의 기준으로 삼으면 안 되기 때문.
 */
export class CompanyTurnRuntime {
    private abortController?: AbortController;
    private lastSummary?: {
        brief: string;
        reportTail: string;
        finishedAt: number;
    };

    /** Turn 시작 — fresh AbortController 등록. dispatcher signal 로 전달됨. */
    startTurn(): AbortController {
        const ctrl = new AbortController();
        this.abortController = ctrl;
        return ctrl;
    }

    /**
     * Turn 종료(완료/실패/abort 무관) — finally 절에서 호출. 우리가 발급한 그
     * controller 일 때만 비워 race 방지 (느린 cleanup 이 새 turn 의 controller
     * 를 잘못 지우는 경우 차단).
     */
    endTurn(ctrl: AbortController): void {
        if (this.abortController === ctrl) this.abortController = undefined;
    }

    /**
     * Stop 버튼 — abort 신호 emit. 호출 시점에 진행 중 turn 없으면 false.
     * 호출자(provider) 는 추가로 ApprovalGateManager.abortAll() 도 호출해야
     * dispatcher 의 stage gate await 가 함께 깨어남.
     */
    abort(): boolean {
        if (!this.abortController) return false;
        this.abortController.abort();
        return true;
    }

    /** report-done 시점에 호출. abort / error 케이스는 호출 안 됨 (intent 의도). */
    recordSummary(brief: string, reportTail: string): void {
        this.lastSummary = { brief, reportTail, finishedAt: Date.now() };
    }

    /** Intent classifier 가 follow-up 판단할 때 읽음. cold start 면 undefined. */
    getLastSummary() {
        return this.lastSummary;
    }

    /** 새 chat / 다른 세션 load 시 — 옛 report 가 의도 분류 오염하지 않게. */
    clearLastSummary(): void {
        this.lastSummary = undefined;
    }
}

/**
 * Intent Alignment 의 *현재 미해결* 상태. 분석기가 round 를 끝낸 후 사용자
 * 확인이 필요한 경우 이 슬롯에 contract 를 보관 → 다음 사용자 메시지를 답변으로
 * 해석. 한 번에 한 alignment 만 진행 (회사 모드는 sequential).
 *
 * 옛 코드는 sidebarProvider 의 단일 slot 으로 4개 메서드에 흩어져 있었음.
 * Manager 로 모아 set/get/clear 책임 단일화 + 외부에서는 isPending() / consume()
 * 으로 안전하게 사용.
 */
export interface PendingAlignment {
    userOriginalPrompt: string;
    contract: RequirementContract;
    /** 이번 alignment 동안 사용자가 답한 누적 라운드 수 — 무한 라운드 방지. */
    roundsAsked: number;
    /** 이번 turn 한정 pipeline override (Phase 4 분류기에서 전달된 추천). */
    pipelineIdOverride?: string;
}

export class AlignmentSession {
    private pending?: PendingAlignment;

    isPending(): boolean {
        return !!this.pending;
    }

    /** 카드 push 시 호출 — 분석기 결과 보관. */
    set(state: PendingAlignment): void {
        this.pending = state;
    }

    /** 현재 보류 상태 조회 (consume 안 함). */
    get(): PendingAlignment | undefined {
        return this.pending;
    }

    /**
     * 한 번에 *읽고 비움* — 사용자가 진행 / 답변 시 호출. consume 패턴으로 race
     * (사용자가 진행 누르고 곧바로 답변 메시지 보내는 경우) 의 두 번째 호출이
     * 자동으로 noop 이 되어 안전.
     */
    consume(): PendingAlignment | undefined {
        const cur = this.pending;
        this.pending = undefined;
        return cur;
    }

    /** 취소 — 카드 / streamEnd push 는 호출자(provider) 책임. */
    clear(): void {
        this.pending = undefined;
    }
}
