// API client для pulse-lets-go backend.
const API_BASE = '/api';

function getToken(): string | null {
  if (typeof localStorage === 'undefined') return null;
  return localStorage.getItem('token');
}

function getRefreshToken(): string | null {
  if (typeof localStorage === 'undefined') return null;
  return localStorage.getItem('refreshToken');
}

async function refreshAccessToken(): Promise<string | null> {
  const refresh = getRefreshToken();
  if (!refresh) return null;

  try {
    const res = await fetch(`${API_BASE}/auth/refresh`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${refresh}` },
    });
    if (!res.ok) return null;

    const data = await res.json();
    localStorage.setItem('token', data.access_token);
    localStorage.setItem('refreshToken', data.refresh_token);
    return data.access_token;
  } catch {
    return null;
  }
}

async function request<T>(url: string, options: RequestInit = {}): Promise<T> {
  let token = getToken();
  const headers: Record<string, string> = {
    'Content-Type': 'application/json',
    ...(options.headers as Record<string, string>),
  };

  if (token) {
    headers['Authorization'] = `Bearer ${token}`;
  }

  let res = await fetch(`${API_BASE}${url}`, { ...options, headers });

  // Пробуем обновить токен при 401
  if (res.status === 401 && token) {
    const newToken = await refreshAccessToken();
    if (newToken) {
      headers['Authorization'] = `Bearer ${newToken}`;
      res = await fetch(`${API_BASE}${url}`, { ...options, headers });
    }
  }

  if (res.status === 204) return undefined as T;
  if (!res.ok) {
    const err = await res.json().catch(() => ({ error: res.statusText }));
    throw new Error(err.error || 'API error');
  }

  return res.json();
}

// --- Auth ---
export async function login(username: string, password: string) {
  const data = await request<{ access_token: string; refresh_token: string; expires_in: number }>(
    '/auth/login',
    { method: 'POST', body: JSON.stringify({ username, password }) }
  );
  localStorage.setItem('token', data.access_token);
  localStorage.setItem('refreshToken', data.refresh_token);
  return data;
}

export function isAuthenticated(): boolean {
  return !!getToken();
}

export function logout() {
  localStorage.removeItem('token');
  localStorage.removeItem('refreshToken');
  window.location.href = '/login';
}

// --- Nodes ---
export interface NodeInfo {
  node_id: string;
  ts: number;
  status: string;
  active_calls: number;
  max_calls: number;
  idle_cpu: number;
  load_avg: number;
  call_failure_rate: number;
  disabled: boolean;
  disabled_reason: string;
  score: number;
  lethal_reason: string;
  is_stale: boolean;
  seconds_ago: number;
}

export async function getNodes(): Promise<NodeInfo[]> {
  return request<NodeInfo[]>('/nodes');
}

export async function toggleNode(nodeId: string, disabled: boolean, reason: string = '') {
  return request<NodeInfo>(`/nodes/${encodeURIComponent(nodeId)}/toggle`, {
    method: 'PUT',
    body: JSON.stringify({ disabled, reason }),
  });
}

export interface NodeSnapshot {
  active_calls: number;
  max_calls: number;
  idle_cpu: number;
  load_avg: number;
  call_failure_rate: number;
  score: number;
  ts: number;
}

export async function getNodeMetrics(nodeId: string): Promise<{ node_id: string; snapshots: NodeSnapshot[]; count: number }> {
  return request(`/nodes/${encodeURIComponent(nodeId)}/metrics`);
}

// --- Trunks ---
export interface Trunk {
  id: string;
  name: string;
  type: 'ingress' | 'balance' | 'fallback';
  node_id: string;
  gateway: string;
  codecs: string[];
  context: string;
  enabled: boolean;
  description: string;
  created_at: string;
  updated_at: string;
}

export async function getTrunks(typeFilter?: string): Promise<Trunk[]> {
  const q = typeFilter ? `?type=${typeFilter}` : '';
  return request<Trunk[]>(`/trunks${q}`);
}

export async function createTrunk(data: Partial<Trunk>) {
  return request<Trunk>('/trunks', { method: 'POST', body: JSON.stringify(data) });
}

export async function updateTrunk(id: string, data: Partial<Trunk>) {
  return request<Trunk>(`/trunks/${encodeURIComponent(id)}`, { method: 'PUT', body: JSON.stringify(data) });
}

export async function deleteTrunk(id: string) {
  return request<void>(`/trunks/${encodeURIComponent(id)}`, { method: 'DELETE' });
}

// --- Users ---
export interface UserInfo {
  id: string;
  username: string;
  role: string;
  created_at: string;
  updated_at: string;
}

export async function getUsers(): Promise<UserInfo[]> {
  return request<UserInfo[]>('/users');
}

export async function createUser(data: { username: string; password: string; role: string }) {
  return request('/users', { method: 'POST', body: JSON.stringify(data) });
}

export async function updateUser(id: string, data: { username?: string; password?: string; role?: string }) {
  return request(`/users/${encodeURIComponent(id)}`, { method: 'PUT', body: JSON.stringify(data) });
}

export async function deleteUser(id: string) {
  return request<void>(`/users/${encodeURIComponent(id)}`, { method: 'DELETE' });
}

// --- WebSocket ---
export interface BalancerInfo {
  esl_connected: boolean;
  esl_uptime_sec: number;
  esl_reconnects: number;
  nats_connected: boolean;
  gateways_total: number;
  gateways_up: number;
  gateways_down: number;
  fs_active_calls: number;
  fs_max_sessions: number;
  fs_uptime: string;
  route_total: number;
  route_fallbacks: number;
  uptime_sec: number;
  balance_mode: string;
}

export function connectWebSocket(onMessage: (data: any) => void): WebSocket {
  const token = getToken();
  const proto = window.location.protocol === 'https:' ? 'wss' : 'ws';
  const ws = new WebSocket(`${proto}://${window.location.host}/ws/metrics?token=${token}`);

  ws.onmessage = (event) => {
    try {
      const data = JSON.parse(event.data);
      onMessage(data);
    } catch (e) {
      console.error('WS parse error:', e);
    }
  };

  ws.onclose = () => {
    // Переподключение через 5 секунд
    setTimeout(() => {
      if (getToken()) connectWebSocket(onMessage);
    }, 5000);
  };

  return ws;
}

// --- Route mode ---

export async function setBalanceMode(mode: 'best' | 'weighted_random') {
  return request<{ mode: string }>('/route/mode', {
    method: 'PUT',
    body: JSON.stringify({ mode }),
  });
}

// --- Routing Rules ---

export interface RouteRule {
  id: string;
  name: string;
  enabled: boolean;
  priority: number;
  match_caller_id: string;
  match_destination: string;
  match_ingress_trunk: string;
  match_days: string;
  match_time_start: string;
  match_time_end: string;
  action_type: 'node' | 'pool' | 'auto';
  action_node_id: string;
  action_pool_ids: string[];
  description: string;
  hits: number;
  created_at: string;
  updated_at: string;
}

export async function getRoutingRules(): Promise<RouteRule[]> {
  return request<RouteRule[]>('/routing/rules');
}

export async function createRoutingRule(data: Partial<RouteRule>) {
  return request<RouteRule>('/routing/rules', { method: 'POST', body: JSON.stringify(data) });
}

export async function updateRoutingRule(id: string, data: Partial<RouteRule>) {
  return request<RouteRule>(`/routing/rules/${encodeURIComponent(id)}`, { method: 'PUT', body: JSON.stringify(data) });
}

export async function deleteRoutingRule(id: string) {
  return request<void>(`/routing/rules/${encodeURIComponent(id)}`, { method: 'DELETE' });
}

export async function toggleRoutingRule(id: string, enabled: boolean) {
  return request<RouteRule>(`/routing/rules/${encodeURIComponent(id)}/toggle`, {
    method: 'PUT',
    body: JSON.stringify({ enabled }),
  });
}

export async function reorderRoutingRules(order: string[]) {
  return request<{ status: string }>('/routing/rules/reorder', {
    method: 'PUT',
    body: JSON.stringify(order),
  });
}
