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 controller = new AbortController();
  const timeout = setTimeout(() => controller.abort(), options.timeout || 10000);
  config.signal = controller.signal;
  let res;
  try {
    res = await fetch(url, config);
  } finally {
    clearTimeout(timeout);
  }
  const text = await res.text();
  let data;
  try {
    data = JSON.parse(text);
  } catch (e) {
    throw new ApiError('Server returned invalid response', res.status || 502);
  }

  if (!res.ok) {
    if (res.status === 401 && !options._retried) {
      const refreshed = await refreshToken();
      if (refreshed) {
        const retryRes = await api(endpoint, { ...options, _retried: true });
        return retryRes;
      }
      bus.emit('auth:expired');
    } else if (res.status === 401 && options._retried) {
      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 });
}

let refreshPromise = null;
async function refreshToken() {
  if (refreshPromise) return refreshPromise;
  refreshPromise = doRefresh();
  try { return await refreshPromise; } finally { refreshPromise = null; }
}

async function doRefresh() {
  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;
  }
}
