/** 与 /database/api/* 的约定一致;401 时清空会话(回到登录视图)。 */

import { me } from "./stores.js";

export class ApiError extends Error {
  constructor(
    readonly status: number,
    readonly code: string,
    message: string,
    readonly details?: Record<string, unknown>,
  ) {
    super(message);
    this.name = "ApiError";
  }
}

export class UnauthenticatedError extends Error {
  constructor() {
    super("unauthenticated");
    this.name = "UnauthenticatedError";
  }
}

interface RequestOpts {
  readonly method?: string;
  readonly body?: unknown;
}

export async function api<T = unknown>(path: string, opts: RequestOpts = {}): Promise<T> {
  const res = await fetch(path, {
    credentials: "same-origin",
    method: opts.method ?? "GET",
    ...(opts.body !== undefined
      ? { headers: { "Content-Type": "application/json" }, body: JSON.stringify(opts.body) }
      : {}),
  });
  if (res.status === 401) {
    me.set(null);
    throw new UnauthenticatedError();
  }
  if (res.status === 204) return null as T;
  const text = await res.text();
  const data = text === "" ? null : (JSON.parse(text) as unknown);
  if (!res.ok) {
    const err = (data as { error?: { code?: string; message?: string } } | null)?.error ?? {};
    throw new ApiError(res.status, err.code ?? "unknown", err.message ?? res.statusText, err as Record<string, unknown>);
  }
  return data as T;
}
