/**
 * Typed client for the @void-nav/api kanban backend.
 *
 * In development, requests are proxied to `http://localhost:3001` by the Vite
 * config (`server.proxy['/api']`), so the docs site and API share one origin.
 * Keep these types in sync with `apps/api/src/types.ts`.
 */

export type Column = 'done' | 'in-progress' | 'todo' | 'backlog';

export type ReferenceType = 'doc' | 'code' | 'demo' | 'external' | 'custom';

export interface Reference {
  label: string;
  type: ReferenceType;
  href: string;
  /** Canonical references come from the seed and cannot be removed by users. */
  removable: boolean;
}

export interface Comment {
  id: string;
  cardId: string;
  text: string;
  author: string;
  /** Epoch milliseconds. */
  createdAt: number;
}

export interface Card {
  id: string;
  title: string;
  description: string;
  details: string;
  category: string;
  files: string | null;
  notes: string | null;
  status: Column;
  sortOrder: number;
  comments: Comment[];
  tags: string[];
  references: Reference[];
}

export interface Board {
  cards: Card[];
  lastUpdated: string;
}

export interface DocPage {
  path: string;
  title: string;
  icon: string;
  blurb: string;
}

const BASE = '/api/kanban';

class ApiError extends Error {
  constructor(
    message: string,
    readonly status: number,
  ) {
    super(message);
    this.name = 'ApiError';
  }
}

async function req<T>(path: string, init?: RequestInit): Promise<T> {
  const res = await fetch(`${BASE}${path}`, {
    ...init,
    headers: { 'Content-Type': 'application/json', ...(init?.headers ?? {}) },
  });
  if (!res.ok) {
    let detail = `${res.status} ${res.statusText}`;
    try {
      const body = await res.json();
      if (body?.error) detail = body.error;
    } catch {
      /* non-JSON error body; keep status text */
    }
    throw new ApiError(detail, res.status);
  }
  if (res.status === 204) return undefined as T;
  return (await res.json()) as T;
}

export const kanbanApi = {
  getBoard: () => req<Board>('/board'),
  getPages: () => req<DocPage[]>('/pages'),

  moveCard: (id: string, status: Column) =>
    req<Card>(`/cards/${id}`, { method: 'PATCH', body: JSON.stringify({ status }) }),

  addComment: (cardId: string, text: string, author: string) =>
    req<Comment>(`/cards/${cardId}/comments`, {
      method: 'POST',
      body: JSON.stringify({ text, author }),
    }),

  deleteComment: (commentId: string) =>
    req<void>(`/comments/${commentId}`, { method: 'DELETE' }),

  addTag: (cardId: string, tag: string) =>
    req<{ cardId: string; tag: string }>(`/cards/${cardId}/tags`, {
      method: 'POST',
      body: JSON.stringify({ tag }),
    }),

  removeTag: (cardId: string, tag: string) =>
    req<void>(`/cards/${cardId}/tags/${encodeURIComponent(tag)}`, { method: 'DELETE' }),

  addReference: (cardId: string, ref: { label: string; type: ReferenceType; href: string }) =>
    req<Reference>(`/cards/${cardId}/references`, {
      method: 'POST',
      body: JSON.stringify(ref),
    }),

  removeReference: (cardId: string, href: string) =>
    req<void>(`/cards/${cardId}/references?href=${encodeURIComponent(href)}`, {
      method: 'DELETE',
    }),
};
