import * as vscode from 'vscode';
import * as path from 'path';
import { SidebarChatProvider } from '../sidebarProvider';
import { getActiveBrainProfile, logInfo } from '../utils';
import { pickConfigTarget } from '../lib/paths';

/**
 * Handles chat-domain messages: prompts, model selection, sessions, streaming control,
 * generic webview transport (export, settings, addMessage), action approvals, and the
 * cross-cutting `ready` bootstrap.
 *
 * Returns true when the message was handled by this domain, false otherwise — the
 * caller chains domain handlers until one accepts the message.
 */
export async function handleChatMessage(provider: SidebarChatProvider, data: any): Promise<boolean> {
    switch (data.type) {
        case 'prompt':
        case 'promptWithFile':
            provider._lmStudio?.activity.bump();
            await provider._context.globalState.update(SidebarChatProvider.blankChatStateKey, false);
            // ── 1인 기업 모드 우선 분기 ──
            // When company mode is active, route the prompt through the
            // CEO planner / sequential dispatcher / synthesis pipeline
            // instead of the normal single-agent path. The user-facing
            // chat surface is the same — only the runtime differs.
            if (provider.isCompanyModeEnabled() && typeof data.value === 'string' && data.value.trim()) {
                await provider._runCompanyTurn(data.value.trim());
                return true;
            }
            await provider._handlePrompt(data);
            await provider._autoWriteChronicleAfterPrompt();
            await provider._saveCurrentSession();
            return true;
        case 'activity':
            provider._lmStudio?.activity.bump();
            return true;
        case 'ready':
            await provider._sendBrainStatus();
            await provider._sendBrainProfiles();
            await provider._sendSessionList();
            await provider._sendModels();
            await provider._sendChronicleProjects();
            await provider._restoreActiveSessionIntoView();
            await provider._sendReadyStatus();
            // Restore the Project Architecture chip + watcher if the active project
            // was already running in architecture mode in a previous VS Code session.
            await provider._sendArchitectureStatus();
            // Restore the Company chip from globalState so the user sees the same
            // mode they had on at last shutdown.
            await provider._sendCompanyStatus();
            return true;
        case 'getReadyStatus':
            await provider._sendReadyStatus();
            return true;
        case 'createLessonFromConversation':
            await vscode.commands.executeCommand('g1nation.lesson.fromConversation');
            return true;
        case 'manageLessons':
            await vscode.commands.executeCommand('g1nation.lesson.manage');
            return true;
        case 'getModels':
            await provider._sendModels();
            return true;
        case 'getSessions':
            await provider._sendSessionList();
            return true;
        case 'newChat':
            provider._currentSessionId = null;
            provider._currentSessionBrainId = getActiveBrainProfile().id;
            provider._agent.resetConversation();
            await provider._context.globalState.update(SidebarChatProvider.activeSessionStateKey, null);
            await provider._context.globalState.update(SidebarChatProvider.lastVisibleChatStateKey, null);
            await provider._context.globalState.update(SidebarChatProvider.blankChatStateKey, true);
            provider.clearChat();
            await provider._sendBrainStatus();
            return true;
        case 'stopGeneration':
            // 1인 기업 모드는 AgentExecutor를 거치지 않으므로 별도 abort 경로.
            // 두 경로 모두 신호를 보내 두면 중간에 모드 전환되어도 안전.
            provider.abortCompanyTurn();
            provider._agent.stop();
            return true;
        case 'loadSession':
            await provider._loadSession(data.id);
            return true;
        case 'deleteSession':
            await provider._deleteSession(data.id);
            return true;
        case 'openSettings':
            // Route the sidebar gear button to Astra's own settings webview.
            // Falls back to VS Code Settings if the view hasn't registered yet
            // (e.g. during the very first activation pass) and surfaces any
            // unexpected error so the user isn't stuck with a silent button.
            try {
                await vscode.commands.executeCommand('g1nation.settings.focus');
            } catch (e: any) {
                logInfo('openSettings: settings.focus failed, falling back to VS Code Settings.', { error: e?.message ?? String(e) });
                try {
                    await vscode.commands.executeCommand('workbench.action.openSettings', 'g1nation');
                } catch (e2: any) {
                    vscode.window.showErrorMessage(`Astra Settings 열기 실패: ${e2?.message ?? e2}`);
                }
            }
            return true;
        case 'addMessage':
            provider._view?.webview.postMessage({ type: 'addMessage', role: data.role, value: data.value, rationale: data.rationale });
            return true;
        case 'refreshModels':
            await provider._sendModels(true);
            return true;
        case 'model': {
            // Write to whichever scope already holds the value so a stale
            // Workspace override doesn't shadow our Global update — that was
            // the "sidebar shows e2b but Settings shows e4b" desync.
            const { target } = pickConfigTarget('g1nation', 'defaultModel');
            await vscode.workspace.getConfiguration('g1nation').update('defaultModel', data.value, target);
            logInfo(`Default model updated to: ${data.value}`, { target });
            provider._lmStudio?.lifecycle.onModelSelected(data.value);
            return true;
        }
        case 'getKnowledgeMix': {
            // Ship the current global Knowledge Mix to the webview so the slider can
            // initialize. Per-agent overrides ride along with the agent map data.
            const cfg = vscode.workspace.getConfiguration('g1nation');
            const w = cfg.get<number>('knowledgeMix.secondBrainWeight', 50);
            const clamped = Math.max(0, Math.min(100, Math.round(typeof w === 'number' ? w : 50)));
            provider._view?.webview.postMessage({
                type: 'knowledgeMix',
                value: { weight: clamped, source: 'global' },
            });
            return true;
        }
        case 'setKnowledgeMix': {
            const raw = typeof data.value === 'number' ? data.value : NaN;
            if (!Number.isFinite(raw)) return true;
            const clamped = Math.max(0, Math.min(100, Math.round(raw)));
            // Use whichever scope already holds the value to avoid the same "Workspace
            // override shadows Global update" desync that the `model` case guards against.
            const { target } = pickConfigTarget('g1nation', 'knowledgeMix.secondBrainWeight');
            await vscode.workspace.getConfiguration('g1nation').update('knowledgeMix.secondBrainWeight', clamped, target);
            logInfo(`Knowledge Mix (global) updated to: ${clamped}`, { target });
            return true;
        }
        // ── Project Architecture (Feature 2) ──────────────────────────────────
        case 'getArchitectureStatus':
            await provider._sendArchitectureStatus();
            return true;
        case 'openArchitectureDoc':
            await provider._openArchitectureDoc();
            return true;
        case 'refreshArchitecture':
            await provider._refreshArchitecture();
            return true;
        case 'detachArchitecture':
            await provider._detachArchitecture();
            return true;
        case 'attachArchitecture':
            // Re-enable architecture context for the current workspace —
            // user clicked the inactive chip's [Attach] button.
            await provider._attachArchitecture();
            return true;
        case 'activateArchitectureFromText': {
            // Optional explicit-toggle path: webview can pass arbitrary text
            // (e.g. the current input draft) for one-shot intent detection.
            if (typeof data.text === 'string') {
                await provider._tryActivateArchitectureFromText(data.text);
            }
            return true;
        }
        // ── 1인 기업 모드 메시지 라우팅 ────────────────────────────────────
        case 'getCompanyStatus':
            await provider._sendCompanyStatus();
            return true;
        case 'getCompanyAgents':
            await provider._sendCompanyAgents();
            return true;
        case 'setCompanyEnabled': {
            const { setCompanyEnabled } = await import('../features/company');
            await setCompanyEnabled(provider._context, !!data.value);
            await provider._sendCompanyStatus();
            return true;
        }
        case 'setCompanyName': {
            const { setCompanyName } = await import('../features/company');
            await setCompanyName(provider._context, typeof data.value === 'string' ? data.value : '');
            await provider._sendCompanyStatus();
            return true;
        }
        case 'setCompanyActiveAgents': {
            const { setActiveAgents } = await import('../features/company');
            const ids = Array.isArray(data.value)
                ? data.value.filter((v: unknown): v is string => typeof v === 'string')
                : [];
            await setActiveAgents(provider._context, ids);
            await provider._sendCompanyStatus();
            await provider._sendCompanyAgents();
            return true;
        }
        case 'setCompanyAgentModel': {
            const { setAgentModelOverride } = await import('../features/company');
            const agentId = typeof data.agentId === 'string' ? data.agentId : '';
            const model = typeof data.model === 'string' ? data.model : '';
            if (agentId) {
                await setAgentModelOverride(provider._context, agentId, model);
                await provider._sendCompanyAgents();
            }
            return true;
        }
        case 'setCompanyAgentDisplay': {
            // 이름/역할/이모지/색상 override. 페이로드는 setCompanyAgentPrompt와
            // 동일한 패턴 — null이면 전체 reset, 각 필드 빈 문자열이면 그 필드만 reset.
            const { setAgentDisplayOverride } = await import('../features/company');
            const agentId = typeof data.agentId === 'string' ? data.agentId : '';
            if (!agentId) return true;
            const v = data.override;
            const override = v === null
                ? null
                : {
                    name: typeof v?.name === 'string' ? v.name : undefined,
                    role: typeof v?.role === 'string' ? v.role : undefined,
                    emoji: typeof v?.emoji === 'string' ? v.emoji : undefined,
                    color: typeof v?.color === 'string' ? v.color : undefined,
                };
            const result = await setAgentDisplayOverride(provider._context, agentId, override);
            provider._view?.webview.postMessage({
                type: 'setCompanyAgentDisplayResult',
                value: result.ok ? { ok: true, agentId } : { ok: false, reason: result.reason },
            });
            if (result.ok) await provider._sendCompanyAgents();
            return true;
        }
        case 'setCompanyAgentRoleCategory': {
            // Override an agent's 직군. Empty / null payload value reverts to
            // the def's own roleCategory. CEO is rejected by the backend.
            const { setAgentRoleCategory } = await import('../features/company');
            const agentId = typeof data.agentId === 'string' ? data.agentId : '';
            if (!agentId) return true;
            const cat = (typeof data.value === 'string' && data.value.trim()) ? data.value.trim() : null;
            const result = await setAgentRoleCategory(provider._context, agentId, cat as any);
            provider._view?.webview.postMessage({
                type: 'setCompanyAgentRoleCategoryResult',
                value: result.ok ? { ok: true, agentId } : { ok: false, reason: result.reason },
            });
            if (result.ok) await provider._sendCompanyAgents();
            return true;
        }
        case 'setCompanyAgentKnowledgeMix': {
            // Per-agent Knowledge Mix override. `null`/missing value falls
            // back to the global slider. The dispatcher reads this on the
            // *next* turn — no restart required.
            const { setAgentKnowledgeMix } = await import('../features/company');
            const agentId = typeof data.agentId === 'string' ? data.agentId : '';
            if (!agentId) return true;
            const raw = data.value;
            const weight = (raw === null || raw === undefined || !Number.isFinite(Number(raw)))
                ? null
                : Math.max(0, Math.min(100, Math.round(Number(raw))));
            await setAgentKnowledgeMix(provider._context, agentId, weight);
            await provider._sendCompanyAgents();
            return true;
        }
        case 'setCompanyAgentPrompt': {
            // Patch one agent's persona / specialty / tagline. Each field is
            // optional in the payload; passing an *empty string* explicitly
            // clears that field (back to the default from `agents.ts`).
            // Sending `null` for the whole override resets every field at once.
            const { setAgentPromptOverride } = await import('../features/company');
            const agentId = typeof data.agentId === 'string' ? data.agentId : '';
            if (!agentId) return true;
            const v = data.override;
            const override = v === null
                ? null
                : {
                    persona: typeof v?.persona === 'string' ? v.persona : undefined,
                    specialty: typeof v?.specialty === 'string' ? v.specialty : undefined,
                    tagline: typeof v?.tagline === 'string' ? v.tagline : undefined,
                };
            await setAgentPromptOverride(provider._context, agentId, override);
            await provider._sendCompanyAgents();
            return true;
        }
        case 'addCompanyAgent': {
            // User-defined agent. Payload: { def: CompanyAgentDef }. Returns
            // an `addCompanyAgentResult` so the UI overlay can keep its form
            // open + show an error when validation fails (id collision etc.).
            const { addCustomAgent } = await import('../features/company');
            const def = data.def;
            const result = await addCustomAgent(provider._context, def ?? {});
            provider._view?.webview.postMessage({
                type: 'addCompanyAgentResult',
                value: result.ok
                    ? { ok: true, agentId: def?.id }
                    : { ok: false, reason: result.reason },
            });
            if (result.ok) {
                await provider._sendCompanyStatus();
                await provider._sendCompanyAgents();
            }
            return true;
        }
        case 'deleteCompanyAgent': {
            // Drop a user-defined agent. Built-ins refuse — backend enforces.
            const { removeCustomAgent } = await import('../features/company');
            const agentId = typeof data.agentId === 'string' ? data.agentId : '';
            if (!agentId) return true;
            const result = await removeCustomAgent(provider._context, agentId);
            provider._view?.webview.postMessage({
                type: 'deleteCompanyAgentResult',
                value: result.ok ? { ok: true, agentId } : { ok: false, reason: result.reason },
            });
            if (result.ok) {
                await provider._sendCompanyStatus();
                await provider._sendCompanyAgents();
            }
            return true;
        }
        case 'getCompanyPipelines':
            await provider._sendCompanyPipelines();
            return true;
        case 'upsertCompanyPipeline': {
            const { upsertPipeline } = await import('../features/company');
            const result = await upsertPipeline(provider._context, data.def ?? {});
            provider._view?.webview.postMessage({
                type: 'upsertCompanyPipelineResult',
                value: result.ok ? { ok: true } : { ok: false, reason: result.reason },
            });
            if (result.ok) await provider._sendCompanyPipelines();
            return true;
        }
        case 'deleteCompanyPipeline': {
            const { deletePipeline } = await import('../features/company');
            const pid = typeof data.pipelineId === 'string' ? data.pipelineId : '';
            if (!pid) return true;
            const result = await deletePipeline(provider._context, pid);
            provider._view?.webview.postMessage({
                type: 'deleteCompanyPipelineResult',
                value: result.ok ? { ok: true, pipelineId: pid } : { ok: false, reason: result.reason },
            });
            if (result.ok) await provider._sendCompanyPipelines();
            return true;
        }
        case 'getCompanyPipelineTemplate': {
            // Returns a template's stages so the editor can pre-fill the form.
            const { getPipelineTemplate } = await import('../features/company');
            const tplId = typeof data.templateId === 'string' ? data.templateId : '';
            const tpl = getPipelineTemplate(tplId);
            provider._view?.webview.postMessage({
                type: 'companyPipelineTemplateContent',
                value: tpl ? {
                    templateId: tpl.templateId,
                    suggestedPipelineId: tpl.suggestedPipelineId,
                    suggestedPipelineName: tpl.suggestedPipelineName,
                    stages: tpl.stages,
                } : null,
            });
            return true;
        }
        case 'respondCompanyApproval': {
            // Webview의 승인 카드 버튼 클릭 → dispatcher의 await 해제.
            // payload: { stageId, decision: 'approve' | 'revise' | 'abort', comment? }
            const stageId = typeof data.stageId === 'string' ? data.stageId : '';
            const decision = typeof data.decision === 'string' ? data.decision : '';
            if (!stageId || !['approve', 'revise', 'abort'].includes(decision)) return true;
            let payload: any;
            if (decision === 'approve') payload = { kind: 'approve' };
            else if (decision === 'abort') payload = { kind: 'abort' };
            else payload = { kind: 'revise', comment: typeof data.comment === 'string' ? data.comment : '' };
            provider.resolveApprovalGate(stageId, payload);
            return true;
        }
        case 'setActiveCompanyPipeline': {
            const { setActivePipeline } = await import('../features/company');
            const pid = typeof data.pipelineId === 'string' && data.pipelineId.trim()
                ? data.pipelineId.trim()
                : null;
            const result = await setActivePipeline(provider._context, pid);
            provider._view?.webview.postMessage({
                type: 'setActiveCompanyPipelineResult',
                value: result.ok ? { ok: true, pipelineId: pid } : { ok: false, reason: result.reason },
            });
            if (result.ok) await provider._sendCompanyPipelines();
            return true;
        }
        case 'proactiveTrigger':
            await provider._handleProactiveSuggestion(data.context);
            return true;
        case 'exportResponse': {
            const workspacePath = vscode.workspace.workspaceFolders?.[0].uri.fsPath || '';
            const defaultPath = path.join(workspacePath, 'g1_response.md');
            const uri = await vscode.window.showSaveDialog({
                defaultUri: vscode.Uri.file(defaultPath),
                filters: { 'Markdown': ['md'] }
            });
            if (uri) {
                await vscode.workspace.fs.writeFile(uri, Buffer.from(data.text, 'utf8'));
                vscode.window.showInformationMessage(`✅ Exported to ${path.basename(uri.fsPath)}`);
            }
            return true;
        }
        case 'approveAction':
            await provider._agent.approveTransaction();
            return true;
        case 'rejectAction':
            await provider._agent.rejectTransaction();
            return true;
        default:
            return false;
    }
}
