// Always use relative URLs — Vite proxy handles routing to the actual server.
// Set VITE_API_URL in vite.config.ts (not here) to change the target.
const BASE = '';
const API_KEY_STORAGE_KEY = 'qc_trace_api_key';
const ENV_API_KEY = import.meta.env.VITE_API_KEY ?? null;

export interface Stats {
  total_sessions: number;
  total_messages: number;
  by_source: { source: string; count: number }[];
  by_type: { msg_type: string; count: number }[];
  by_org: { org: string; session_count: number; message_count: number }[];
  tokens: { input: number; output: number; cached: number; thinking: number };
}

export interface Session {
  id: string;
  source: string;
  model: string | null;
  first_seen: string;
  last_updated: string;
  message_count: number;
  latest_message: string | null;
  user_email: string | null;
  user_name: string | null;
  device_name: string | null;
  device_id: string | null;
  cwd: string | null;
  repo_url: string | null;
  repo_name: string | null;
  git_branch: string | null;
  git_commit: string | null;
  project_hash: string | null;
  org: string | null;
}

export interface Message {
  id: string;
  session_id: string;
  source: string;
  msg_type: string;
  timestamp: string;
  content: string | null;
  content_preview?: string | null;
  thinking: string | null;
  model: string | null;
  raw_line_number: number | null;
  input_tokens: number | null;
  output_tokens: number | null;
  cached_tokens: number | null;
  thinking_tokens: number | null;
  tool_name: string | null;
  tool_input: unknown | null;
  tool_output: string | null;
  tool_status: string | null;
}

export type FeedMessage = Pick<
  Message,
  'id' | 'session_id' | 'source' | 'msg_type' | 'timestamp' | 'model' | 'input_tokens' | 'output_tokens'
> & { content_preview: string | null };

// ── API key management ──────────────────────────────────────────────

export function getApiKey(): string | null {
  return ENV_API_KEY ?? localStorage.getItem(API_KEY_STORAGE_KEY);
}

export function setApiKey(key: string): void {
  localStorage.setItem(API_KEY_STORAGE_KEY, key);
}

export function clearApiKey(): void {
  localStorage.removeItem(API_KEY_STORAGE_KEY);
}

/** Prompt the user for an API key. Only one prompt at a time. */
let _keyPromise: Promise<string | null> | null = null;

export function promptForApiKey(): Promise<string | null> {
  if (_keyPromise) return _keyPromise;
  _keyPromise = new Promise((resolve) => {
    // Defer so the prompt doesn't block concurrent callers from joining
    setTimeout(() => {
      const key = window.prompt('Enter your qc-trace API key:');
      _keyPromise = null;
      if (key) {
        setApiKey(key.trim());
        resolve(key.trim());
      } else {
        resolve(null);
      }
    }, 0);
  });
  return _keyPromise;
}

// ── HTTP helper ─────────────────────────────────────────────────────

async function get<T>(path: string): Promise<T> {
  const headers: Record<string, string> = {};
  const apiKey = getApiKey();
  if (apiKey) {
    headers['X-API-Key'] = apiKey;
  }

  const res = await fetch(`${BASE}${path}`, { headers });

  if (res.status === 401) {
    const newKey = await promptForApiKey();
    if (newKey) {
      // Retry with the new key
      const retryRes = await fetch(`${BASE}${path}`, {
        headers: { 'X-API-Key': newKey },
      });
      if (!retryRes.ok) throw new Error(`${retryRes.status} ${retryRes.statusText}`);
      return retryRes.json();
    }
    throw new Error('Unauthorized — no API key provided');
  }

  if (!res.ok) throw new Error(`${res.status} ${res.statusText}`);
  return res.json();
}

export interface Device {
  device_id: string;
  device_name: string;
  org: string;
  status: string;
  daemon_version: string;
  queue_size: number;
  current_backoff: number;
  messages_this_session: number;
  last_push_at: string | null;
  uptime_seconds: number;
  source_stats: Record<string, unknown> | null;
  recent_errors: string[];
  last_seen_at: string;
}

export const api = {
  health: () => get<{ status: string; db: string }>('/health'),
  stats: (params?: { org?: string }) => {
    const q = new URLSearchParams();
    if (params?.org) q.set('org', params.org);
    const qs = q.toString();
    return get<Stats>(`/api/stats${qs ? '?' + qs : ''}`);
  },
  sessions: (params?: { source?: string; org?: string; limit?: number; offset?: number }) => {
    const q = new URLSearchParams();
    if (params?.source) q.set('source', params.source);
    if (params?.org) q.set('org', params.org);
    if (params?.limit) q.set('limit', String(params.limit));
    if (params?.offset) q.set('offset', String(params.offset));
    const qs = q.toString();
    return get<Session[]>(`/api/sessions${qs ? '?' + qs : ''}`);
  },
  session: (id: string) =>
    get<Session[]>(`/api/sessions?id=${encodeURIComponent(id)}&limit=1`).then(
      (rows) => rows[0] ?? null,
    ),
  messages: (sessionId: string, params?: { limit?: number; offset?: number }) => {
    const q = new URLSearchParams({ session_id: sessionId });
    if (params?.limit) q.set('limit', String(params.limit));
    if (params?.offset) q.set('offset', String(params.offset));
    return get<Message[]>(`/api/messages?${q}`);
  },
  feed: (params?: { since?: string; org?: string; limit?: number }) => {
    const q = new URLSearchParams();
    if (params?.since) q.set('since', params.since);
    if (params?.org) q.set('org', params.org);
    if (params?.limit) q.set('limit', String(params.limit));
    return get<FeedMessage[]>(`/api/feed?${q}`);
  },
  devices: (params?: { org?: string }) => {
    const q = new URLSearchParams();
    if (params?.org) q.set('org', params.org);
    const qs = q.toString();
    return get<Device[]>(`/api/devices${qs ? '?' + qs : ''}`);
  },
  orgs: () => get<string[]>('/api/orgs'),
};
