/**
 * Typed fetch client for the panel backend. Same-origin; the session cookie rides automatically
 * (HttpOnly — JS never reads it). Every call narrows the response and throws `ApiError` on failure
 * so the UI can react (e.g. bounce to the login screen on 401).
 */
export interface HostView {
  readonly hostId: string
  readonly subdomain: string
  readonly status: string
  readonly lastSeen?: string
  readonly createdAt?: string
  readonly revokedAt?: string | null
  readonly notAfter?: string
}

export interface PairingArtifacts {
  readonly code: string
  readonly expiresAt: string
  readonly pairCommand: string
  readonly qrDataUrl: string
}

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

async function request(method: string, url: string, body?: unknown): Promise<Response> {
  const init: RequestInit = { method, credentials: 'same-origin', headers: {} }
  if (body !== undefined) {
    init.headers = { 'content-type': 'application/json' }
    init.body = JSON.stringify(body)
  }
  return fetch(url, init)
}

async function json<T>(res: Response): Promise<T> {
  if (!res.ok) throw new ApiError(res.status, `request failed (${res.status})`)
  return (await res.json()) as T
}

export async function getSession(): Promise<boolean> {
  const res = await request('GET', '/api/session')
  const data = await json<{ authenticated: boolean }>(res)
  return data.authenticated === true
}

/** Attempt login. Returns true on success; throws ApiError (status) otherwise so callers can message. */
export async function login(password: string): Promise<boolean> {
  const res = await request('POST', '/login', { password })
  if (res.ok) return true
  throw new ApiError(res.status, `login failed (${res.status})`)
}

export async function logout(): Promise<void> {
  await request('POST', '/logout')
}

export async function getHosts(): Promise<readonly HostView[]> {
  const res = await request('GET', '/api/hosts')
  const data = await json<{ hosts: HostView[] }>(res)
  return data.hosts ?? []
}

export async function createPairingCode(): Promise<PairingArtifacts> {
  const res = await request('POST', '/api/pairing-codes')
  return json<PairingArtifacts>(res)
}

export async function revokeHost(hostId: string): Promise<void> {
  const res = await request('DELETE', `/api/hosts/${encodeURIComponent(hostId)}`)
  if (!res.ok && res.status !== 204) throw new ApiError(res.status, `revoke failed (${res.status})`)
}
