import * as vscode from 'vscode';
import type {
    AgentStatus,
    AgentWorkState,
    AgentBubble,
    CompanyState,
    RequirementContract,
} from '../../features/company';
import { listActiveAgentsByCategory } from '../../features/company';
import type { OfficeAgentSnapshot } from '../../features/astraOffice';
import { renderAstraOfficePanelHtml } from '../../features/astraOffice';

/**
 * Pixel Office UI broadcast 에 쓰이는 pure helpers. 모두 stateless transform —
 * sidebarProvider 의 private 메서드를 그대로 추출.
 *
 *   - mergeAgentWorkState(prev, patch) — broadcast 직전 state merge + updatedAt 갱신
 *   - summariseContract(contract) — RequirementContract → webview 가 표시할 요약 모양
 *   - buildOfficeRoster(state) — CompanyState → presenter 의 roster 입력
 *
 * webview send / 말풍선 sequencing / bubble dedupe 같은 *상태성* 흐름은 여전히
 * sidebarProvider 와 PixelOfficeState 에 남는다. 이 모듈은 *데이터 변환만* 책임.
 */

const ROSTER_ORDER: Array<'ceo' | 'planner' | 'researcher' | 'designer' | 'developer' | 'qa' | 'inspector' | 'support'> = [
    'ceo', 'planner', 'researcher', 'designer', 'developer', 'qa', 'inspector', 'support',
];

/**
 * 직전 상태에 patch 를 머지해 다음 state 생성. recentLogs 는 patch 가 명시
 * 안 했으면 prev 그대로 유지 (broadcast 중 일부 호출이 log 만 push 하지 않는
 * 케이스 — 그래도 옛 logs 가 화면에 살아 있어야 함). updatedAt 은 항상 갱신해
 * webview 의 "마지막 갱신" 뱃지가 작동.
 */
export function mergeAgentWorkState(
    prev: AgentWorkState | undefined,
    patch: Partial<AgentWorkState>,
): AgentWorkState {
    const base = prev ?? {
        agentId: 'main',
        agentName: 'Agent',
        status: 'idle' as AgentWorkState['status'],
        recentLogs: [],
        updatedAt: Date.now(),
    };
    return {
        ...base,
        ...patch,
        recentLogs: patch.recentLogs ?? base.recentLogs ?? [],
        updatedAt: Date.now(),
    };
}

/**
 * RequirementContract 를 webview 카드 표시용 요약 객체로 변환. 빈 문자열 필드는
 * undefined 로 정규화해 카드 UI 에서 "값 없음" 분기를 단순화.
 */
export function summariseContract(c: RequirementContract): {
    goal: string | undefined;
    context: string | undefined;
    criteria: RequirementContract['criteria'];
    format: string | undefined;
    openQuestions: RequirementContract['openQuestions'];
    confidence: RequirementContract['confidence'];
} {
    return {
        goal: c.goal || undefined,
        context: c.context || undefined,
        criteria: c.criteria,
        format: c.format || undefined,
        openQuestions: c.openQuestions,
        confidence: c.confidence,
    };
}

/**
 * 현재 CompanyState 에서 active agents 를 평탄화해 presenter 의 roster 입력으로.
 * `state.enabled === false` 면 빈 배열 (presenter 가 옛 single-agent fallback 사용).
 * ROSTER_ORDER 순서 보존 — 화면에서 일관된 좌→우/위→아래 정렬.
 */
/**
 * 사이드바/패널 webview 가 받는 `pixelOfficeUpdate` 메시지 payload 빌드. 기능
 * 비활성화면 state=null + 빈 bubbles 로 webview 가 "꺼짐" 표시. 활성화면 cached
 * state (없으면 default idle agent) + 빈 bubbles + config snapshot.
 *
 * bubbles 는 *resend* (재전송) 용도라 항상 빈 배열 — 같은 말풍선을 reload 마다
 * 다시 띄우면 시각 노이즈. 새 broadcast 가 bubbles 를 채워준다.
 */
export function buildPixelOfficeUpdatePayload(
    cfg: { companyPixelOfficeEnabled: boolean; companyPixelOfficeBubbles: boolean },
    state: AgentWorkState | undefined,
): { type: 'pixelOfficeUpdate'; value: { state: AgentWorkState | null; bubbles: AgentBubble[]; config: { enabled: boolean; bubblesEnabled: boolean; maxVisibleBubbles: number; bubbleDurationMs: number } } } {
    if (!cfg.companyPixelOfficeEnabled) {
        return {
            type: 'pixelOfficeUpdate',
            value: { state: null, bubbles: [], config: { enabled: false, bubblesEnabled: false, maxVisibleBubbles: 0, bubbleDurationMs: 0 } },
        };
    }
    const resolved: AgentWorkState = state ?? {
        agentId: 'main',
        agentName: 'Agent',
        status: 'idle' as AgentStatus,
        recentLogs: [],
        updatedAt: Date.now(),
    };
    return {
        type: 'pixelOfficeUpdate',
        value: {
            state: resolved,
            bubbles: [],
            config: {
                enabled: cfg.companyPixelOfficeEnabled,
                bubblesEnabled: cfg.companyPixelOfficeBubbles,
                maxVisibleBubbles: 3,
                bubbleDurationMs: 4500,
            },
        },
    };
}

/**
 * Pixel Office 전체보기 panel 의 HTML 본문. 사이드바 mini 와 같은 메시지 스키마를
 * 받지만 그리는 방식이 전혀 달라 (사무실 그리드 + 직군별 캐릭터) 별도 HTML 사용.
 * CSP source 와 derived asset base URI 만 webview 에서 가져오면 나머지는 정적.
 */
export function buildPixelOfficeHtml(extensionUri: vscode.Uri, webview: vscode.Webview): string {
    const cspSource = webview.cspSource;
    const derivedBase = webview.asWebviewUri(
        vscode.Uri.joinPath(extensionUri, 'assets', 'pixelOffice', 'derived'),
    ).toString();
    return renderAstraOfficePanelHtml({ cspSource, derivedBase });
}

export function buildOfficeRoster(state: CompanyState): Array<{
    agentId: string;
    agentName: string;
    roleCategory: OfficeAgentSnapshot['roleCategory'];
}> {
    try {
        if (!state.enabled) return [];
        const buckets = listActiveAgentsByCategory(state);
        const out: Array<{ agentId: string; agentName: string; roleCategory: OfficeAgentSnapshot['roleCategory'] }> = [];
        for (const cat of ROSTER_ORDER) {
            for (const def of buckets[cat] ?? []) {
                out.push({
                    agentId: def.id,
                    agentName: def.name ?? def.id,
                    roleCategory: cat,
                });
            }
        }
        return out;
    } catch {
        return [];
    }
}
