// HTTP API 客户端：对接 WebRTCSignalServer 的账号体系与主控端自助接口。
//
// 服务端约定（WebRTCSignalServer）：
//   - 无 context-path，接口路径即 /api/**，端口 8080；
//   - 鉴权统一使用 Authorization: Bearer <accessToken>；
//   - accessToken TTL 900s，refreshToken TTL 7 天，refreshToken 一次性轮换；
//   - CORS 对 /api/** 全开（allowCredentials=true）。
//
// 令牌存储策略：
//   - accessToken / refreshToken 均放 sessionStorage，页面关闭即清除，降低泄露面。
// API 基地址：生产态由 VITE_API_BASE 提供（浏览器直连后端）；
// 开发态由 vite.config.js 的代理转发，前端请求相对路径 /api（VITE_API_BASE 留空）。
const API_BASE = (import.meta.env.VITE_API_BASE || '').replace(/\/$/, '');

const ACCESS_KEY = 'ttstd.accessToken';
const REFRESH_KEY = 'ttstd.refreshToken';

let accessToken = sessionStorage.getItem(ACCESS_KEY) || '';
let refreshToken = sessionStorage.getItem(REFRESH_KEY) || '';
// 刷新单飞：避免并发请求同时触发多次刷新（refreshToken 是一次性的，并发刷新会互相作废）。
let refreshing = null;
// 令牌被判定为彻底失效时的回调（由 store 注册，用于跳回登录页）。
let onAuthFailed = null;

export function setAuthFailedHandler(fn) {
  onAuthFailed = fn;
}

export function getAccessToken() {
  return accessToken;
}

export function isLoggedIn() {
  return !!accessToken;
}

export function setTokens({ accessToken: at, refreshToken: rt }) {
  accessToken = at || '';
  if (rt) refreshToken = rt;
  if (accessToken) sessionStorage.setItem(ACCESS_KEY, accessToken);
  else sessionStorage.removeItem(ACCESS_KEY);
  if (refreshToken) sessionStorage.setItem(REFRESH_KEY, refreshToken);
  else sessionStorage.removeItem(REFRESH_KEY);
}

export function clearTokens() {
  accessToken = '';
  refreshToken = '';
  sessionStorage.removeItem(ACCESS_KEY);
  sessionStorage.removeItem(REFRESH_KEY);
}

function buildError(data, status) {
  // 服务端 AuthExceptionHandler 返回 { code, error/message }。
  const err = new Error(data.error || data.message || 'HTTP ' + status);
  err.code = data.code;
  err.status = status;
  return err;
}

// 单次裸请求，不做刷新重试。
async function rawRequest(path, { method = 'POST', body, auth = false } = {}) {
  const headers = {};
  if (body !== undefined) headers['Content-Type'] = 'application/json';
  if (auth && accessToken) headers['Authorization'] = 'Bearer ' + accessToken;

  const res = await fetch(API_BASE + path, {
    method,
    headers,
    body: body !== undefined ? JSON.stringify(body) : undefined,
  });

  if (!res.ok) {
    const data = await res.json().catch(() => ({}));
    throw buildError(data, res.status);
  }
  // 部分接口可能返回空体。
  const text = await res.text();
  if (!text) return {};
  try {
    return JSON.parse(text);
  } catch {
    return {};
  }
}

/**
 * 带鉴权的请求：遇到 401 自动刷新一次令牌后重试；
 * 刷新失败则清空令牌并通知上层跳回登录页。
 */
async function request(path, options = {}) {
  try {
    return await rawRequest(path, options);
  } catch (e) {
    if (e.status !== 401 || !options.auth) throw e;
    try {
      await refresh();
    } catch {
      clearTokens();
      onAuthFailed && onAuthFailed('登录已过期，请重新登录');
      throw e;
    }
    return rawRequest(path, options);
  }
}

/* ---------------- 认证 /api/auth ---------------- */

/** 登录。响应：{ accessToken, refreshToken, expiresInSeconds, sessionId, principalId, displayName } */
export async function login(username, password, totpCode) {
  const body = { username, password };
  if (totpCode) body.totpCode = totpCode;
  const data = await rawRequest('/api/auth/login', { body });
  setTokens({ accessToken: data.accessToken, refreshToken: data.refreshToken });
  return data;
}

/** 注册。响应：{ userId, username } */
export async function register(body) {
  return rawRequest('/api/auth/register', { body });
}

/** 退出登录。服务端从 Bearer 令牌解析 sessionId，无需请求体。 */
export async function logout() {
  if (accessToken) {
    try {
      await rawRequest('/api/auth/logout', { method: 'POST', auth: true });
    } catch { /* 忽略：本地令牌无论如何都要清掉 */ }
  }
  clearTokens();
}

/** 刷新令牌：单飞锁，并发调用共享同一次刷新结果。 */
export async function refresh() {
  if (!refreshToken) {
    clearTokens();
    throw new Error('NO_REFRESH_TOKEN');
  }
  if (refreshing) return refreshing;
  refreshing = (async () => {
    try {
      // 刷新自身不能再走 request()，否则 401 会递归。
      const data = await rawRequest('/api/auth/refresh', { body: { refreshToken } });
      // 服务端轮换 refreshToken（一次性），必须覆盖保存。
      setTokens({ accessToken: data.accessToken, refreshToken: data.refreshToken });
      return data;
    } catch (e) {
      clearTokens();
      throw e;
    } finally {
      refreshing = null;
    }
  })();
  return refreshing;
}

/**
 * 查询当前登录身份，用于页面刷新后恢复会话。
 * 响应：{ principalId, principalType, displayName, sessionId, signalDeviceId, totpEnabled }
 */
export async function me() {
  return request('/api/auth/me', { method: 'GET', auth: true });
}

/* ---------------- 主控端自助 /api/client ---------------- */

/** 令牌校验（可选）。 */
export async function verify() {
  return request('/api/client/verify', { method: 'GET', auth: true });
}

/** WebSocket 接入信息：{ wsPath, subprotocol, tokenMethods }。 */
export async function wsInfo() {
  return rawRequest('/api/client/ws-info', { method: 'GET' });
}

/**
 * 主控端已绑定设备列表。
 * 响应：{ bindings: [{ bindingId, deviceUid, userId, role, alias, status, online }] }
 * 服务端已过滤仅返回 status=ACTIVE 的绑定。
 */
export async function listBindings() {
  return request('/api/client/bindings', { method: 'GET', auth: true });
}

/**
 * 已绑定且当前在线的设备。
 * 响应：{ devices: [{ deviceUid, alias, online }] }
 */
export async function listOnlineDevices() {
  return request('/api/client/devices/online', { method: 'GET', auth: true });
}

/**
 * 用配对码绑定一台被控端设备（配对码由被控端生成，默认 10 分钟有效）。
 */
export async function redeemPairingCode(code, alias) {
  const body = { code };
  if (alias) body.alias = alias;
  return request('/api/client/pairing/redeem', { method: 'POST', body, auth: true });
}

/** 拉取 TURN 短期凭证（服务端开启时返回 iceServers）。 */
export async function fetchTurnCredentials() {
  try {
    return await request('/api/client/turn-credentials', { method: 'GET', auth: true });
  } catch {
    return null;
  }
}
