// Thin API client. All endpoints go through this so we can:
// - attach the JWT to every request
// - handle 401 by clearing auth and reloading
// - throw typed errors for the UI to surface

import type {
  RouterEvent, RouterInfo, CommandRecord, Alert,
  MetricsResponse, HealthResponse, LoginResponse, MeResponse,
} from './types'

const BASE = ''  // same origin via Vite proxy / Caddy

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

function getToken(): string | null {
  return localStorage.getItem('c2s_token')
}

export function setToken(token: string | null) {
  if (token) localStorage.setItem('c2s_token', token)
  else localStorage.removeItem('c2s_token')
}

async function request<T>(path: string, opts: RequestInit = {}): Promise<T> {
  const headers = new Headers(opts.headers)
  headers.set('Content-Type', 'application/json')
  const tok = getToken()
  if (tok) headers.set('Authorization', `Bearer ${tok}`)

  const res = await fetch(BASE + path, { ...opts, headers })
  if (res.status === 401) {
    setToken(null)
    // Let the UI handle the redirect
    window.dispatchEvent(new CustomEvent('c2s:unauthorized'))
  }
  if (!res.ok) {
    const text = await res.text()
    let msg = text
    try { msg = JSON.parse(text).error || text } catch {}
    throw new ApiError(res.status, msg)
  }
  return res.json() as Promise<T>
}

export const api = {
  login: (username: string, password: string) =>
    request<LoginResponse>('/api/auth/login', {
      method: 'POST',
      body: JSON.stringify({ username, password }),
    }),

  me: () => request<MeResponse>('/api/auth/me'),

  health: () => request<HealthResponse>('/health'),

  routers: () => request<{ routers: RouterInfo[] }>('/api/routers'),

  events: (params: { limit?: number; router_id?: string; event_type?: string } = {}) => {
    const q = new URLSearchParams()
    if (params.limit) q.set('limit', String(params.limit))
    if (params.router_id) q.set('router_id', params.router_id)
    if (params.event_type) q.set('event_type', params.event_type)
    return request<{ events: RouterEvent[] }>('/api/events/list?' + q.toString())
  },

  commands: (params: { limit?: number; router_id?: string } = {}) => {
    const q = new URLSearchParams()
    if (params.limit) q.set('limit', String(params.limit))
    if (params.router_id) q.set('router_id', params.router_id)
    return request<{ commands: CommandRecord[] }>('/api/commands?' + q.toString())
  },

  sendCommand: (router_id: string, command: string, args: Record<string, string> = {}, id?: string) =>
    request<{ command_id: string; status: string; queue_depth?: number }>('/api/command', {
      method: 'POST',
      body: JSON.stringify({ router_id, command, args, ...(id ? { id } : {}) }),
    }),

  metrics: (since = '1h') => request<MetricsResponse>('/api/metrics?since=' + since),

  alerts: (params: { unack?: boolean; limit?: number } = {}) => {
    const q = new URLSearchParams()
    if (params.unack) q.set('unack', '1')
    if (params.limit) q.set('limit', String(params.limit))
    return request<{ alerts: Alert[] }>('/api/alerts?' + q.toString())
  },

  acknowledgeAlert: (id: number) =>
    request<{ status: string }>(`/api/alerts/${id}/ack`, { method: 'POST' }),
}

export { ApiError }
