/**
 * Thin fetch wrapper over mcpd's HTTP API.
 *
 * Reads the bearer token from localStorage on every request — the user can
 * paste either a session token (from `mcpctl auth login`) or a PAT
 * (`mcpctl_pat_*`). Both flow through the same `Authorization: Bearer …`
 * header that mcpd already accepts (see `src/mcpd/src/middleware/auth.ts`).
 *
 * The wrapper deliberately stays minimal — no caching, no retry policy, no
 * cancellation tokens. Add those when a real call site needs them.
 */

const TOKEN_KEY = 'mcpctl.token';

export function getToken(): string | null {
  return localStorage.getItem(TOKEN_KEY);
}

export function setToken(token: string): void {
  localStorage.setItem(TOKEN_KEY, token);
}

export function clearToken(): void {
  localStorage.removeItem(TOKEN_KEY);
}

export interface ApiError extends Error {
  status: number;
  body: unknown;
}

async function request<T>(method: string, path: string, body?: unknown): Promise<T> {
  const token = getToken();
  const headers: Record<string, string> = { 'Content-Type': 'application/json' };
  if (token !== null) headers['Authorization'] = `Bearer ${token}`;

  const init: RequestInit = { method, headers };
  if (body !== undefined) init.body = JSON.stringify(body);
  const res = await fetch(path, init);

  if (!res.ok) {
    let parsed: unknown = null;
    try { parsed = await res.json(); } catch { /* ignore */ }
    const err = new Error(`HTTP ${String(res.status)} ${res.statusText}`) as ApiError;
    err.status = res.status;
    err.body = parsed;
    throw err;
  }
  if (res.status === 204) return undefined as T;
  return res.json() as Promise<T>;
}

export const api = {
  get: <T>(path: string): Promise<T> => request<T>('GET', path),
  post: <T>(path: string, body: unknown): Promise<T> => request<T>('POST', path, body),
  put: <T>(path: string, body: unknown): Promise<T> => request<T>('PUT', path, body),
  delete: <T = void>(path: string): Promise<T> => request<T>('DELETE', path),
};

// ── Domain types (subset of what the UI needs from mcpd) ──

export interface Project {
  id: string;
  name: string;
  description?: string;
}

export interface Agent {
  id: string;
  name: string;
  description: string;
  systemPrompt: string;
  llm: { id: string; name: string };
  project: { id: string; name: string } | null;
  defaultPersonality: { id: string; name: string } | null;
}

export interface Prompt {
  id: string;
  name: string;
  content: string;
  projectId: string | null;
  agentId: string | null;
  priority: number;
  linkTarget: string | null;
}

export interface Personality {
  id: string;
  name: string;
  description: string;
  agentId: string;
  agentName: string;
  priority: number;
  promptCount: number;
}

// PR-3: Skill resource. Mirrors Prompt with the addition of multi-file
// bundles (`files`) and typed metadata (`hooks`, `mcpServers`,
// `postInstall`, …).
export interface Skill {
  id: string;
  name: string;
  description: string;
  content: string;
  files: Record<string, string>;
  metadata: Record<string, unknown>;
  projectId: string | null;
  agentId: string | null;
  priority: number;
  semver: string;
  currentRevisionId: string | null;
  createdAt: string;
  updatedAt: string;
  project?: { name: string } | null;
  agent?: { name: string } | null;
}

export interface VisibleSkill {
  id: string;
  name: string;
  description: string;
  semver: string;
  contentHash: string;
  metadata: unknown;
  scope: 'global' | 'project' | 'agent';
}

// PR-2: ResourceProposal — generic propose/approve/reject queue.
// Replaces PromptRequest in the new path.
export interface Proposal {
  id: string;
  resourceType: 'prompt' | 'skill';
  name: string;
  body: Record<string, unknown>;
  projectId: string | null;
  agentId: string | null;
  createdBySession: string | null;
  createdByUserId: string | null;
  status: 'pending' | 'approved' | 'rejected';
  reviewerNote: string;
  approvedRevisionId: string | null;
  createdAt: string;
  updatedAt: string;
  project?: { name: string } | null;
  agent?: { name: string } | null;
}

// PR-2: ResourceRevision — append-only audit log keyed by
// (resourceType, resourceId).
export interface Revision {
  id: string;
  resourceType: 'prompt' | 'skill';
  resourceId: string;
  semver: string;
  contentHash: string;
  body: Record<string, unknown>;
  authorUserId: string | null;
  authorSessionId: string | null;
  note: string;
  createdAt: string;
}

export interface PersonalityPrompt {
  promptId: string;
  promptName: string;
  promptContent: string;
  priority: number;
}
