const BASE = '';

interface ApiOptions {
  method?: string;
  body?: unknown;
}

function isArray(v: unknown): v is unknown[] {
  return Array.isArray(v);
}

export async function api<T>(path: string, opts: ApiOptions = {}): Promise<T> {
  const { method = 'GET', body } = opts;
  const res = await fetch(`${BASE}${path}`, {
    method,
    headers: body ? { 'Content-Type': 'application/json' } : {},
    body: body ? JSON.stringify(body) : undefined,
    credentials: 'include',
  });
  if (!res.ok) {
    const err = await res.json().catch(() => ({ error: res.statusText }));
    throw new Error((err as { error?: string }).error || 'Request failed');
  }
  if (res.status === 204) return undefined as T;
  const data = await res.json().catch(() => null);
  if (data === null) return undefined as T;
  if (isArray(data) && !data.length && data[0] === undefined) return [] as unknown as T;
  return data as T;
}

export async function apiRaw(path: string): Promise<Response> {
  return fetch(`${BASE}${path}`, { credentials: 'include' });
}

export interface User {
  id: number;
  username: string;
  role: string;
}

export interface Machine {
  id: number;
  name: string;
  host: string;
  port: number;
  ssh_user: string;
  ssh_key_id: number | null;
  mac_address: string | null;
  wol_enabled: boolean;
  broadcast_addr: string | null;
  wake_timeout_seconds: number;
  wake_check_interval_seconds: number;
  fingerprint_confirmed: boolean;
  status: string;
}

export interface SyncPair {
  id: number;
  name: string;
  source_machine_id: number | null;
  source_path: string;
  dest_machine_id: number | null;
  dest_path: string;
  direction: string;
  rsync_flags: string;
  exclude_patterns: string;
  enabled: boolean;
}

export interface Job {
  id: number;
  sync_pair_id: number;
  trigger_type: string;
  status: string;
  started_at: string | null;
  finished_at: string | null;
  log_file: string | null;
  error_message?: string | null;
  error_code?: string | null;
  duration_seconds?: number | null;
  log_line_count?: number | null;
}

export interface LogLine {
  id: number;
  job_id: number;
  stream: string;
  content: string;
  timestamp: string;
}

export interface CancelJobRequest {
  reason?: string;
}

export interface SSHKey {
  id: number;
  label: string;
  public_key: string;
  fingerprint: string;
  in_use: boolean;
  has_private_key: boolean;
  created_at: string;
}
