const BASE = "/api";

async function request<T = any>(
  method: string,
  path: string,
  body?: any,
): Promise<{ ok: boolean; data?: T; message?: string; status: number }> {
  const res = await fetch(`${BASE}${path}`, {
    method,
    headers: body ? { "Content-Type": "application/json" } : undefined,
    body: body ? JSON.stringify(body) : undefined,
    credentials: "include",
  });

  let json: any = {};
  try {
    json = await res.json();
  } catch {}

  return { ok: res.ok, data: json.data, message: json.message, status: res.status };
}

export const api = {
  auth: {
    login: (username: string, password: string) => request("POST", "/auth/login", { username, password }),
    logout: () => request("POST", "/auth/logout"),
    me: () => request("GET", "/auth/me"),
    setupStatus: () => request("GET", "/auth/setup-status"),
    firstUser: (username: string, password: string) => request("POST", "/auth/first-user", { username, password }),
  },
  user: {
    settings: () => request("GET", "/user/settings"),
    updateUsername: (username: string) => request("PATCH", "/user/username", { username }),
    updatePassword: (currentPassword: string, newPassword: string) =>
      request("PATCH", "/user/password", { currentPassword, newPassword }),
    updateGitea: (data: { giteaInstanceUrl: string; giteaUsername: string; giteaPAT?: string }) =>
      request("PUT", "/user/gitea", data),
    updateAws: (data: { awsAccessKeyId: string; awsSecretAccessKey: string; awsRegion: string }) =>
      request("PUT", "/user/aws", data),
    getWebhookSecret: () => request("GET", "/user/webhook-secret"),
    regenerateWebhookSecret: () => request("POST", "/user/webhook-secret/regenerate"),
  },
  repos: {
    list: () => request("GET", "/repos"),
    getConfig: (owner: string, repo: string) => request("GET", `/repos/${owner}/${repo}/config`),
    saveConfig: (data: any) => request("POST", "/repos/config", data),
    toggle: (owner: string, repo: string, enabled: boolean) => request("POST", "/repos/toggle", { owner, repo, enabled }),
  },
  stats: {
    get: () => request("GET", "/stats"),
  },
  previews: {
    list: () => request("GET", "/previews"),
    get: (id: number) => request("GET", `/previews/${id}`),
    stop: (id: number) => request("POST", `/previews/${id}/stop`),
    rebuild: (id: number) => request("POST", `/previews/${id}/rebuild`),
  },
  admin: {
    listUsers: () => request("GET", "/admin/users"),
    createUser: (username: string, password: string) => request("POST", "/admin/users", { username, password }),
    updateUser: (id: number, data: any) => request("PATCH", `/admin/users/${id}`, data),
    deleteUser: (id: number) => request("DELETE", `/admin/users/${id}`),
    getSettings: () => request("GET", "/admin/settings"),
    updateSettings: (data: any) => request("PUT", "/admin/settings", data),
    listPreviews: () => request("GET", "/admin/previews"),
    stopPreview: (id: number) => request("POST", `/admin/previews/${id}/stop`),
  },
};

// Format an estimated USD cost. Sub-cent values keep more precision so a
// freshly-started preview doesn't just read "$0.00". See backend lib/cost.ts.
export function formatUsd(n: number | null | undefined): string {
  const v = n ?? 0;
  if (v > 0 && v < 0.01) return `$${v.toFixed(4)}`;
  return `$${v.toFixed(2)}`;
}

export function openLogsWs(previewId: number, onMessage: (msg: any) => void, onClose?: () => void): WebSocket {
  const protocol = location.protocol === "https:" ? "wss:" : "ws:";
  const ws = new WebSocket(`${protocol}//${location.host}/api/previews/${previewId}/logs`);
  ws.onmessage = (e) => {
    try { onMessage(JSON.parse(e.data)); } catch {}
  };
  ws.onclose = onClose || (() => {});
  return ws;
}

// Live stream of the running app's own stdout/stderr (the app process, not the
// PP deploy engine). Backed by an on-demand SSH tail — only produces output
// while the preview is live.
export function openAppLogsWs(previewId: number, onMessage: (msg: any) => void, onClose?: () => void): WebSocket {
  const protocol = location.protocol === "https:" ? "wss:" : "ws:";
  const ws = new WebSocket(`${protocol}//${location.host}/api/previews/${previewId}/applogs`);
  ws.onmessage = (e) => {
    try { onMessage(JSON.parse(e.data)); } catch {}
  };
  ws.onclose = onClose || (() => {});
  return ws;
}
