// ═══════════════════════════════════════════════════════
//  CVC Dashboard — Typed REST API Client
// ═══════════════════════════════════════════════════════
import type {
  ServicesResponse, AnalyticsResponse, StatsResponse,
  CommitEntry, TimelineEntry,
  CommitRequest, BranchRequest, MergeRequest, RestoreRequest,
  OperationResult, RecallResult, DiffResult,
  MemoryContextResponse, MemoryBlobsResponse, MemoryStatsResponse,
  ModelCatalog, CurrentModel,
  MCPTool, MCPStatus,
  ChatRequest,
  HiveMindAgent, RegisterAgentRequest,
  GatewayConfig, VCSStatus, AuditEntry,
  SettingsResponse, SettingsSchema,
  AgentTemplate, AgentsListResponse, AgentFromPromptResponse,
  HiveMemoryEntry, HiveMemoryResponse, HiveMemoryStats, SquadInfo,
} from './types';

const BASE = '';  // same-origin

async function request<T>(path: string, init?: RequestInit): Promise<T> {
  const res = await fetch(`${BASE}${path}`, {
    headers: { 'Content-Type': 'application/json', ...(init?.headers as Record<string, string> ?? {}) },
    ...init,
  });
  if (!res.ok) {
    const body = await res.text();
    throw new Error(`API ${res.status}: ${body}`);
  }
  return res.json() as Promise<T>;
}

function get<T>(path: string): Promise<T> {
  return request<T>(path);
}

function post<T>(path: string, body?: unknown): Promise<T> {
  return request<T>(path, { method: 'POST', body: body != null ? JSON.stringify(body) : undefined });
}

function del<T>(path: string): Promise<T> {
  return request<T>(path, { method: 'DELETE' });
}

function put<T>(path: string, body?: unknown): Promise<T> {
  return request<T>(path, { method: 'PUT', body: body != null ? JSON.stringify(body) : undefined });
}

// ── Gateway / Services ─────────────────────────
export function getServices(): Promise<ServicesResponse> {
  return get('/api/gateway/services');
}

export function serviceAction(service: string, action: string): Promise<OperationResult> {
  return post(`/api/gateway/services/${encodeURIComponent(service)}/${encodeURIComponent(action)}`);
}

export function getAnalytics(): Promise<AnalyticsResponse> {
  return get('/api/gateway/analytics');
}

export function getCommits(limit: number = 50): Promise<CommitEntry[]> {
  return get(`/api/gateway/commits?limit=${limit}`);
}

export function getConfig(): Promise<GatewayConfig> {
  return get('/api/gateway/config');
}

// ── Operations ─────────────────────────────────
export function opsCommit(req: CommitRequest): Promise<OperationResult> {
  return post('/api/ops/commit', req);
}

export function opsBranch(req: BranchRequest): Promise<OperationResult> {
  return post('/api/ops/branch', req);
}

export function opsMerge(req: MergeRequest): Promise<OperationResult> {
  return post('/api/ops/merge', req);
}

export function opsRestore(req: RestoreRequest): Promise<OperationResult> {
  return post('/api/ops/restore', req);
}

export function opsRecall(query: string, limit: number = 10): Promise<RecallResult> {
  return get(`/api/ops/recall?query=${encodeURIComponent(query)}&limit=${limit}`);
}

export function opsDiff(hash1: string, hash2: string): Promise<DiffResult> {
  return get(`/api/ops/diff?hash1=${encodeURIComponent(hash1)}&hash2=${encodeURIComponent(hash2)}`);
}

export function opsTimeline(limit: number = 50): Promise<TimelineEntry[]> {
  return get(`/api/ops/timeline?limit=${limit}`);
}

export function opsBranches(): Promise<string[]> {
  return get('/api/ops/branches');
}

export function opsStatus(): Promise<StatsResponse> {
  return get('/api/ops/status');
}

// ── Memory ─────────────────────────────────────
export function getMemoryContext(): Promise<MemoryContextResponse> {
  return get('/api/memory/context');
}

export function getMemoryBlobs(): Promise<MemoryBlobsResponse> {
  return get('/api/memory/blobs');
}

export function getMemoryStats(): Promise<MemoryStatsResponse> {
  return get('/api/memory/stats');
}

// ── Models ─────────────────────────────────────
export function getModelCatalog(): Promise<ModelCatalog> {
  return get('/api/models/catalog');
}

export function getCurrentModel(): Promise<CurrentModel> {
  return get('/api/models/current');
}

export function switchModel(provider: string, model: string): Promise<OperationResult> {
  return post('/api/models/switch', { provider, model });
}

// ── Chat — yields structured event objects ─────
export interface ChatEvent {
  type: 'text' | 'tool_start' | 'tool_result' | 'status';
  content?: string;
  name?: string;
  args?: Record<string, unknown>;
  output?: string;
  message?: string;
}

export async function* chatStream(req: ChatRequest): AsyncGenerator<ChatEvent, void, unknown> {
  const res = await fetch(`${BASE}/api/chat`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ ...req, stream: true }),
  });
  if (!res.ok) throw new Error(`Chat ${res.status}`);
  const reader = res.body?.getReader();
  if (!reader) return;
  const decoder = new TextDecoder();
  let buffer = '';
  while (true) {
    const { done, value } = await reader.read();
    if (done) break;
    buffer += decoder.decode(value, { stream: true });
    const lines = buffer.split('\n');
    buffer = lines.pop()!;
    for (const line of lines) {
      if (line.startsWith('data: ')) {
        const data = line.slice(6);
        if (data === '[DONE]') return;
        try {
          const parsed = JSON.parse(data);
          // New structured events from agentic loop
          if (parsed.type) {
            yield parsed as ChatEvent;
          }
          // Legacy fallback: OpenAI-style delta
          else if (parsed.choices?.[0]?.delta?.content) {
            yield { type: 'text', content: parsed.choices[0].delta.content };
          }
        } catch { /* skip malformed SSE */ }
      }
    }
  }
}

export function getChatModels(): Promise<{ models: string[] }> {
  return get('/api/chat/models');
}

// ── MCP ────────────────────────────────────────
export function getMCPTools(): Promise<MCPTool[]> {
  return get('/api/mcp/tools');
}

export function getMCPStatus(): Promise<MCPStatus> {
  return get('/api/mcp/status');
}

// ── VCS ────────────────────────────────────────
export function getVCSStatus(): Promise<VCSStatus> {
  return get('/api/vcs/status');
}

// ── Audit ──────────────────────────────────────
export function getAudit(): Promise<AuditEntry[]> {
  return get('/api/audit');
}

// ── Sessions ───────────────────────────────────
export function getSessions(): Promise<unknown[]> {
  return get('/api/sessions');
}

// ── Connections ────────────────────────────────
export function getConnections(): Promise<unknown> {
  return get('/api/connections');
}

// ── Hive Mind ──────────────────────────────────
export function getHiveMindAgents(): Promise<HiveMindAgent[]> {
  return get('/api/hivemind/agents');
}

export function registerHiveMindAgent(req: RegisterAgentRequest): Promise<OperationResult> {
  return post('/api/hivemind/register', req);
}

export function removeHiveMindAgent(agentId: string): Promise<OperationResult> {
  return del(`/api/hivemind/agents/${encodeURIComponent(agentId)}`);
}

// ── Stats ──────────────────────────────────────
export function getStats(): Promise<StatsResponse> {
  return get('/api/stats');
}

// ── Settings ───────────────────────────────────
export function getSettings(): Promise<SettingsResponse> {
  return get('/api/settings');
}

export function updateGlobalSettings(data: Record<string, unknown>): Promise<OperationResult> {
  return put('/api/settings/global', data);
}

export function updateProjectSettings(data: Record<string, unknown>): Promise<OperationResult> {
  return put('/api/settings/project', data);
}

export function updateLocalSettings(data: Record<string, unknown>): Promise<OperationResult> {
  return put('/api/settings/local', data);
}

export function getSettingsSchema(): Promise<SettingsSchema> {
  return get('/api/settings/schema');
}

export function resetSettings(level: string): Promise<OperationResult> {
  return post('/api/settings/reset', { level });
}

export function getApiKeys(): Promise<Record<string, string>> {
  return get('/api/settings/keys');
}

export function setApiKey(provider: string, key: string): Promise<OperationResult> {
  return put(`/api/settings/keys/${encodeURIComponent(provider)}`, { api_key: key });
}

export function removeApiKey(provider: string): Promise<OperationResult> {
  return del(`/api/settings/keys/${encodeURIComponent(provider)}`);
}

export function testApiKey(provider: string): Promise<OperationResult> {
  return post(`/api/settings/keys/${encodeURIComponent(provider)}/test`);
}

export function getHooks(): Promise<Record<string, unknown[]>> {
  return get('/api/settings/hooks');
}

export function addHook(event: string, command: string): Promise<OperationResult> {
  return post('/api/settings/hooks', { event, command });
}

export function removeHook(event: string, index: number): Promise<OperationResult> {
  return del(`/api/settings/hooks/${encodeURIComponent(event)}/${index}`);
}

export function getEnvVars(): Promise<Record<string, string>> {
  return get('/api/settings/env');
}

// ── Agent Templates ────────────────────────────
export function listAgents(): Promise<AgentsListResponse> {
  return get('/api/agents');
}

export function getBuiltinAgents(): Promise<AgentTemplate[]> {
  return get('/api/agents/builtin');
}

export function createAgent(template: Partial<AgentTemplate>): Promise<{ status: string; agent: AgentTemplate }> {
  return post('/api/agents', template);
}

export function createAgentFromPrompt(prompt: string): Promise<AgentFromPromptResponse> {
  return post('/api/agents/from-prompt', { prompt });
}

export function getAgentDetail(id: string): Promise<AgentTemplate> {
  return get(`/api/agents/${encodeURIComponent(id)}`);
}

export function updateAgent(id: string, data: Partial<AgentTemplate>): Promise<{ status: string; agent: AgentTemplate }> {
  return put(`/api/agents/${encodeURIComponent(id)}`, data);
}

export function deleteAgent(id: string): Promise<OperationResult> {
  return del(`/api/agents/${encodeURIComponent(id)}`);
}

export function getAgentHistory(id: string): Promise<CommitEntry[]> {
  return get(`/api/agents/${encodeURIComponent(id)}/history`);
}

export function createSquad(name: string, agents: string[]): Promise<OperationResult> {
  return post('/api/agents/squad', { name, agents });
}

export function listSquads(): Promise<SquadInfo[]> {
  return get<{squads: SquadInfo[]}>('/api/agents/squads').then(r => r.squads || []);
}

// ── Hive Memory ────────────────────────────────
export function getHiveMemory(
  query?: string, category?: string, agent_id?: string, limit: number = 50,
): Promise<HiveMemoryResponse> {
  const params = new URLSearchParams();
  if (query) params.set('query', query);
  if (category) params.set('category', category);
  if (agent_id) params.set('agent_id', agent_id);
  params.set('limit', String(limit));
  return get(`/api/hivemind/memory?${params}`);
}

export function writeHiveMemory(
  agent_id: string, content: string, category: string = 'general', tags: string[] = [],
): Promise<{ status: string; entry: HiveMemoryEntry }> {
  return post('/api/hivemind/memory', { agent_id, content, category, tags });
}

export function getHiveMemoryStats(): Promise<HiveMemoryStats> {
  return get('/api/hivemind/memory/stats');
}

export function getHiveMemorySummary(limit: number = 10): Promise<{ context: string }> {
  return get(`/api/hivemind/memory/summary?limit=${limit}`);
}

export function compactHiveMemory(): Promise<OperationResult> {
  return post('/api/hivemind/memory/compact');
}
