import * as store from './store.js';
import * as bus from './bus.js';

const API_BASE = '/api';

export async function api(endpoint, options = {}) {
  const { method = 'GET', body, auth = true } = options;
  const headers = { 'Content-Type': 'application/json' };

  if (auth) {
    const token = store.get('auth.token');
    if (token) headers['Authorization'] = `Bearer ${token}`;
  }

  const config = { method, headers };
  if (body && method !== 'GET') {
    config.body = JSON.stringify(body);
  }

  const url = endpoint.startsWith('http') ? endpoint : `${API_BASE}/${endpoint}`;
  const res = await fetch(url, config);
  const data = await res.json();

  if (!res.ok) {
    if (res.status === 401) {
      const refreshed = await refreshToken();
      if (refreshed) return api(endpoint, options);
      bus.emit('auth:expired');
    }
    throw new ApiError(data.error || 'Request failed', res.status);
  }

  return data;
}

export async function get(endpoint, params = {}) {
  const qs = Object.entries(params)
    .filter(([, v]) => v != null)
    .map(([k, v]) => `${k}=${encodeURIComponent(v)}`)
    .join('&');
  const url = qs ? `${endpoint}?${qs}` : endpoint;
  return api(url);
}

export async function post(endpoint, body) {
  return api(endpoint, { method: 'POST', body });
}

export async function patch(endpoint, body) {
  return api(endpoint, { method: 'PATCH', body });
}

export async function del(endpoint, body) {
  return api(endpoint, { method: 'DELETE', body });
}

async function refreshToken() {
  const refreshToken = store.get('auth.refreshToken');
  if (!refreshToken) return false;
  try {
    const res = await fetch(`${API_BASE}/auth.php`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ action: 'refresh', refresh_token: refreshToken })
    });
    const data = await res.json();
    if (data.access_token) {
      store.set('auth.token', data.access_token);
      store.set('auth.refreshToken', data.refresh_token);
      return true;
    }
  } catch (e) {}
  return false;
}

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

// Realtime via Supabase
const REALTIME_URL = 'wss://safe-supabase-kong.caprover.al-arcade.com/realtime/v1/websocket';
const ANON_KEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbiIsImlzcyI6InN1cGFiYXNlIiwiaWF0IjoxNzM1Njg5NjAwLCJleHAiOjE4OTM0NTYwMDB9.31PF6PvP-pSrvRuQwLFptQoejR0W1A7o53lZhEbnz84';

let ws = null;
let wsCallbacks = {};
let wsRef = 0;
let heartbeat = null;

export function subscribe(channel, table, filter, callback) {
  const topic = `realtime:public:${table}:${filter}`;
  if (!wsCallbacks[topic]) wsCallbacks[topic] = [];
  wsCallbacks[topic].push(callback);

  ensureWs();
  sendJoin(topic);

  return () => {
    wsCallbacks[topic] = wsCallbacks[topic].filter(f => f !== callback);
    if (wsCallbacks[topic].length === 0) {
      sendLeave(topic);
      delete wsCallbacks[topic];
    }
  };
}

function ensureWs() {
  if (ws && ws.readyState === WebSocket.OPEN) return;

  const token = store.get('auth.token') || ANON_KEY;
  ws = new WebSocket(`${REALTIME_URL}?apikey=${ANON_KEY}&vsn=1.0.0`);

  ws.onopen = () => {
    heartbeat = setInterval(() => {
      ws.send(JSON.stringify({ topic: 'phoenix', event: 'heartbeat', payload: {}, ref: String(++wsRef) }));
    }, 30000);
    Object.keys(wsCallbacks).forEach(sendJoin);
  };

  ws.onmessage = (e) => {
    const msg = JSON.parse(e.data);
    if (msg.event === 'INSERT' || msg.event === 'UPDATE' || msg.event === 'DELETE') {
      const cbs = wsCallbacks[msg.topic] || [];
      cbs.forEach(cb => cb({ event: msg.event, new: msg.payload?.record, old: msg.payload?.old_record }));
    }
  };

  ws.onclose = () => {
    clearInterval(heartbeat);
    setTimeout(ensureWs, 3000);
  };
}

function sendJoin(topic) {
  if (!ws || ws.readyState !== WebSocket.OPEN) return;
  const token = store.get('auth.token') || ANON_KEY;
  ws.send(JSON.stringify({
    topic,
    event: 'phx_join',
    payload: { user_token: token },
    ref: String(++wsRef)
  }));
}

function sendLeave(topic) {
  if (!ws || ws.readyState !== WebSocket.OPEN) return;
  ws.send(JSON.stringify({
    topic,
    event: 'phx_leave',
    payload: {},
    ref: String(++wsRef)
  }));
}
