/**
 * Pixel Office — Agent Work Pipeline 상태를 시각화하는 *UI Layer 전용* 모듈.
 *
 * ─────────────────── 설계 원칙 ───────────────────
 * 1. **Agent 핵심 판단 로직을 절대 바꾸지 않는다.** Pipeline 진행, contract
 *    합의, 검수 cycle, 승인 게이트 — 모두 기존 dispatcher / chatHandlers /
 *    SidebarChatProvider 안에서 결정된다. 이 모듈은 그 결정을 *읽고* webview용
 *    상태 객체로 변환할 뿐이다.
 * 2. 입력은 기존에 emit되던 이벤트 (CompanyTurnEvent + alignment phase +
 *    intent classifier 결과)뿐. 새로운 인터럽트 포인트를 만들지 않는다.
 * 3. 출력은 두 종류 — `AgentWorkState` (현재 작업 패널)와 `AgentBubble` 큐
 *    (말풍선 연출). 둘 다 webview가 그대로 받아 그리기만 하면 된다.
 *
 * 즉 dispatcher 안의 어떤 한 줄도 "if pixelOffice ..."로 분기하지 않는다.
 */

/** Agent의 현재 단계. 사용자가 명세한 11개 상태값 전부 포함. */
export type AgentStatus =
    | 'idle'
    | 'intake'
    | 'analyzing'
    | 'need_clarification'
    | 'contract_ready'
    | 'planning'
    | 'executing'
    | 'reviewing'
    | 'waiting_approval'
    | 'error'
    | 'done';

/** 말풍선이 어떤 카테고리에서 나왔는지 — 스타일링 / 우선순위에 활용. */
export type BubbleType = 'status' | 'event' | 'warning' | 'error' | 'success';

/** 말풍선 발생 트리거가 되는 이벤트 — 사용자가 명세한 10개 + 약간 확장. */
export type AgentEvent =
    | 'missing_required_info'
    | 'clarification_needed'
    | 'requirement_contract_created'
    | 'plan_completed'
    | 'execution_started'
    | 'review_failed'
    | 'review_passed'
    | 'risky_change_detected'
    | 'approval_required'
    | 'error_occurred'
    | 'task_completed'
    | 'stage_loop_retry';

export interface AgentWorkState {
    agentId: string;
    agentName: string;
    status: AgentStatus;
    /** 사용자 원본 요청 한 줄 — 패널 상단 "Current Task"에 표시. */
    currentTask?: string;
    /** 현재 stage / phase 라벨 — "기획 논의", "QA 진행" 등. */
    currentStep?: string;
    /** 다음 stage 라벨 (있으면) — 예측 표시용. */
    nextStep?: string;
    /** 짧은 보조 메시지 (예: "라운드 2/3", "검수자: 민지"). */
    message?: string;
    /** 진행률 0~1 — 파이프라인 모드일 때 stage index / total로 계산. */
    progress?: number;
    /** Requirement Contract 요약 (alignment 완료 후 채워짐). */
    requirementContract?: {
        goal?: string;
        context?: string;
        criteria?: string[];
        format?: string;
        openQuestions?: string[];
        confidence?: 'low' | 'medium' | 'high';
    };
    /** 사용자에게 던지는 미해결 질문 목록 — need_clarification 상태에서 채움. */
    needUserInput?: string[];
    /** 승인 대기 중 항목 — waiting_approval 상태에서 채움. */
    awaitingApproval?: string;
    /** 짧은 최근 로그 — 사용자가 한눈에 흐름 파악. 최대 6개 ring buffer. */
    recentLogs?: string[];
    /**
     * 파이프라인 미니 맵용 stage 리스트. `plan-ready` 시점에 채워지고 agent-start/
     * agent-done 으로 상태가 갱신된다. webview는 이 리스트를 dot strip 으로 렌더.
     *   - status: 'done' | 'active' | 'pending'
     */
    pipelineStages?: Array<{ label: string; agent?: string; status: 'done' | 'active' | 'pending' }>;
    /** epoch ms — webview의 "n초 전" 표시용. */
    updatedAt: number;
}

export interface AgentBubble {
    id: string;
    /** 어떤 캐릭터 위에 띄울지 — 단일 캐릭터 모드면 'main' 고정도 가능. */
    agentId: string;
    text: string;
    type: BubbleType;
    /** 생성 시각 epoch ms. */
    createdAt: number;
    /** 자동 사라짐 ms (webview가 사용). 기본값은 webview에서 결정. */
    durationMs?: number;
}

/**
 * 사용자가 설정으로 켜고 끌 수 있는 행동 옵션.
 * webview는 broadcast마다 같이 받아서 즉시 반영.
 */
export interface PixelOfficeConfig {
    enabled: boolean;
    bubblesEnabled: boolean;
    maxVisibleBubbles: number;
    bubbleDurationMs: number;
}

// ─────────────────── 상태→말풍선 텍스트 풀 ───────────────────
// 사용자가 명세한 톤(가벼운 사무실 코미디) 유지. 무작위 선택을 위해 같은 상태에
// 여러 안을 두되 너무 길어지지 않게 4~5개로 제한.

const STATUS_BUBBLE_POOL: Record<AgentStatus, string[]> = {
    idle: [
        '오늘은 무슨 일을 할까?',
        '주문 대기 중…',
        '커피 한 잔 더 하고 시작할까.',
    ],
    intake: [
        '요청서 들어왔다.',
        '한번 읽어보자.',
        '오케이, 뭘 원하시는지 보자.',
    ],
    analyzing: [
        '음… 의도가 조금 모호한데?',
        '맥락부터 정리해보자.',
        '핵심이 뭐였더라.',
        '이거 작업 범위가 어디까지지?',
    ],
    need_clarification: [
        '이건 사용자 확인이 먼저야.',
        '질문 하나만 하고 가자.',
        '추측으로 가면 위험해.',
        '핵심 정보가 빠졌네.',
    ],
    contract_ready: [
        '좋아, 작업 조건 정리 완료.',
        '이제 방향은 잡혔어.',
        '계약서 도장 찍었다.',
        '이제 진짜 시작.',
    ],
    planning: [
        '순서부터 잡아보자.',
        '기존 기능은 건드리지 말자.',
        '화이트보드 좀 빌릴게.',
        '단계 나눠서 가자.',
    ],
    executing: [
        '코드 들어간다.',
        '이번엔 단순하게 가자.',
        '집중 모드 진입.',
        '키보드 워밍업 완료.',
    ],
    reviewing: [
        '잠깐, 이건 다시 보자.',
        '기존 기능 깨지는지 확인해야 해.',
        '검수자 시점으로 한 번 더.',
        '엣지 케이스 빠진 거 없나.',
    ],
    waiting_approval: [
        '이건 승인 없이 못 바꿔.',
        '위험 작업 감지. 확인 필요!',
        '사장님 결재 부탁드립니다.',
        '도장 받기 전엔 멈춤.',
    ],
    error: [
        '앗, 이건 예상 못 했는데…',
        '조건 하나 놓쳤네.',
        '잠깐, 다시 정리.',
        '엇, 이게 깨졌네.',
    ],
    done: [
        '좋아, 끝났다!',
        '이번 작업 깔끔하게 완료.',
        '커피 한 잔.',
        '오늘치 끝!',
    ],
};

const EVENT_BUBBLE_POOL: Record<AgentEvent, string[]> = {
    missing_required_info: [
        '핵심 정보가 빠졌어.',
        '이거 빠지면 추측해야 해.',
    ],
    clarification_needed: [
        '질문 하나만.',
        '확실하지 않으면 먼저 물어보자.',
    ],
    requirement_contract_created: [
        '계약서 도장 찍었다.',
        '이제 방향은 잡혔어.',
    ],
    plan_completed: [
        '계획 정리 끝!',
        '순서대로 가자.',
    ],
    execution_started: [
        '코드 들어간다.',
        '시작!',
    ],
    review_failed: [
        '조건 하나 놓쳤네. 다시 보자.',
        '너무 복잡하게 가는 거 아냐?',
    ],
    review_passed: [
        '검수 통과!',
        '셋 다 만족이래.',
    ],
    risky_change_detected: [
        '잠깐, 이건 승인 필요!',
        '파일 삭제는 함부로 하면 안 돼.',
    ],
    approval_required: [
        '결재 부탁드립니다.',
        '도장 받고 이어 갈게.',
    ],
    error_occurred: [
        '앗, 이건 예상 못 했는데…',
        '엇, 이게 깨졌네.',
    ],
    task_completed: [
        '좋아, 끝났다!',
        '오늘치 끝.',
    ],
    stage_loop_retry: [
        '한 번 더 가자.',
        '버그 잡고 다시 시도.',
    ],
};

/**
 * 텍스트 풀에서 하나 뽑기. 같은 결과가 연달아 나오지 않게 lastPicked를
 * 받아 회피. 풀이 1개뿐이면 어쩔 수 없이 그걸 반환.
 */
export function pickBubbleText(pool: string[], lastPicked?: string): string {
    if (!pool || pool.length === 0) return '';
    if (pool.length === 1) return pool[0];
    let candidates = pool;
    if (lastPicked) candidates = pool.filter((s) => s !== lastPicked);
    if (candidates.length === 0) candidates = pool;
    return candidates[Math.floor(Math.random() * candidates.length)];
}

export function getStatusBubbleText(status: AgentStatus, lastPicked?: string): string {
    return pickBubbleText(STATUS_BUBBLE_POOL[status] ?? [], lastPicked);
}

export function getEventBubbleText(event: AgentEvent, lastPicked?: string): string {
    return pickBubbleText(EVENT_BUBBLE_POOL[event] ?? [], lastPicked);
}

/** 이벤트 → 말풍선 type 매핑. 색상/스타일을 webview가 결정할 때 사용. */
export function eventBubbleType(event: AgentEvent): BubbleType {
    switch (event) {
        case 'error_occurred': return 'error';
        case 'review_failed':
        case 'risky_change_detected':
        case 'missing_required_info':
            return 'warning';
        case 'task_completed':
        case 'review_passed':
        case 'plan_completed':
        case 'requirement_contract_created':
            return 'success';
        default: return 'event';
    }
}

/** AgentBubble factory — id 자동 생성. */
export function makeBubble(opts: {
    agentId: string;
    text: string;
    type?: BubbleType;
    durationMs?: number;
}): AgentBubble {
    return {
        id: `b-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 6)}`,
        agentId: opts.agentId,
        text: opts.text,
        type: opts.type ?? 'status',
        createdAt: Date.now(),
        durationMs: opts.durationMs,
    };
}
