/**
 * 本地开发用 mock 账号服务（畅联 PC 端联调用）
 *
 * ⚠️ 仅供本地开发联调！
 *  - 内置测试环境默认密钥（OpenIM secret / LiveKit key），都是内网测试环境的公开默认值
 *  - 禁止打包进客户端、禁止用于正式环境
 *  - 真实员工账号由管理员在服务器上的账号服务（:10010）开通
 *
 * 用法：
 *  1. node scripts/mock-account-server.js（或 npm run mock:account）
 *  2. 把 .env 里的 VITE_ACCOUNT_URL 临时指向 http://127.0.0.1:11010
 *  3. 用 test001 / test123（或 test002 / test123）登录
 *
 * 接口形状与真实账号服务完全一致：POST /api/login、POST /api/rtc_token。
 * 零依赖，Node >= 18（用到全局 fetch）。
 */

'use strict';

const http = require('http');
const crypto = require('crypto');

const PORT = 11010;
const OPENIM_API_URL = 'http://192.168.200.11:10002';
const OPENIM_SECRET = 'openIM123';
const LIVEKIT_API_KEY = 'openimLKkey';
const LIVEKIT_API_SECRET = 'lk-secret-9f2c7a41d5e8b063f1a4c795e2d8b3a6';

// 本地测试账号（密码均为 test123）
const USERS = {
  test001: { password: 'test123', nickname: '测试一号' },
  test002: { password: 'test123', nickname: '测试二号' },
};

// ---------------- OpenIM 管理接口 ----------------

async function imApi(route, body, token) {
  const res = await fetch(OPENIM_API_URL + route, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      operationID: crypto.randomUUID(),
      ...(token ? { token } : {}),
    },
    body: JSON.stringify(body),
  });
  return res.json();
}

async function getAdminToken() {
  const r = await imApi('/auth/get_admin_token', {
    secret: OPENIM_SECRET,
    userID: 'imAdmin',
  });
  if (r.errCode !== 0) throw new Error('OpenIM 管理员令牌获取失败: ' + (r.errMsg || r.errCode));
  return r.data.token;
}

/** 确保 OpenIM 里存在该用户（不存在则注册，尽力而为） */
async function ensureImUser(userID, nickname, admin) {
  try {
    await imApi('/user/user_register', {
      users: [{ userID, nickname, faceURL: '' }],
    }, admin);
  } catch { /* 忽略，后面取令牌时再报错 */ }
}

async function getImUserToken(userID, platformID) {
  const admin = await getAdminToken();
  await ensureImUser(userID, USERS[userID].nickname, admin);
  const r = await imApi('/auth/get_user_token', { secret: OPENIM_SECRET, platformID, userID }, admin);
  if (r.errCode !== 0) throw new Error('OpenIM 用户令牌获取失败: ' + (r.errMsg || r.errCode));
  return r.data;
}

// ---------------- LiveKit RTC 令牌签发 ----------------

const b64url = (s) => Buffer.from(s).toString('base64url');

function signLivekitToken(userID, room) {
  const now = Math.floor(Date.now() / 1000);
  const header = b64url(JSON.stringify({ alg: 'HS256', typ: 'JWT' }));
  const payload = b64url(JSON.stringify({
    iss: LIVEKIT_API_KEY,
    sub: userID,
    exp: now + 3600,
    nbf: now - 10,
    video: { roomJoin: true, room },
    metadata: '',
  }));
  const sig = crypto.createHmac('sha256', LIVEKIT_API_SECRET).update(`${header}.${payload}`).digest('base64url');
  return `${header}.${payload}.${sig}`;
}

// ---------------- HTTP 服务 ----------------

function send(res, status, obj) {
  res.writeHead(status, {
    'Content-Type': 'application/json; charset=utf-8',
    'Access-Control-Allow-Origin': '*',
    'Access-Control-Allow-Headers': 'Content-Type, authorization',
    'Access-Control-Allow-Methods': 'GET,POST,OPTIONS',
  });
  res.end(JSON.stringify(obj));
}

const ok = (res, data) => send(res, 200, { code: 0, msg: '', data });
const fail = (res, msg, httpStatus = 200) => send(res, httpStatus, { code: 1, msg });

function readBody(req) {
  return new Promise((resolve, reject) => {
    let buf = '';
    req.on('data', (c) => { buf += c; });
    req.on('end', () => {
      if (!buf) return resolve({});
      try { resolve(JSON.parse(buf)); } catch { reject(new Error('请求体不是合法 JSON')); }
    });
    req.on('error', reject);
  });
}

const server = http.createServer(async (req, res) => {
  try {
    const url = new URL(req.url, 'http://localhost');
    if (req.method === 'OPTIONS') return send(res, 204, {});

    if (req.method === 'POST' && url.pathname === '/api/login') {
      const body = await readBody(req);
      const { staffNo, password, platformID } = body;
      if (!staffNo || !password) return fail(res, '工号和密码不能为空');
      const user = USERS[staffNo];
      if (!user || user.password !== String(password)) return fail(res, '工号或密码错误');
      const t = await getImUserToken(staffNo, Number.isInteger(platformID) ? platformID : 3);
      return ok(res, {
        userID: staffNo,
        nickname: user.nickname,
        imToken: t.token,
        expireTimeSeconds: t.expireTimeSeconds,
      });
    }

    if (req.method === 'POST' && url.pathname === '/api/rtc_token') {
      // 与真实账号服务一致：Authorization: Bearer <imToken> + {room, identity}，返回 {token}
      const m = /^Bearer\s+(.+)$/.exec(String(req.headers.authorization || ''));
      if (!m) return fail(res, '未登录或登录已过期', 401);
      const body = await readBody(req);
      const { room, identity } = body;
      if (!room || !identity) return fail(res, '房间号或用户标识不能为空');
      return ok(res, { token: signLivekitToken(String(identity), String(room)) });
    }

    return fail(res, '接口不存在', 404);
  } catch (e) {
    return fail(res, '服务内部错误: ' + e.message, 500);
  }
});

server.listen(PORT, '127.0.0.1', () => {
  console.log(`mock-account-server listening on http://127.0.0.1:${PORT}`);
  console.log('测试账号：test001 / test123，test002 / test123');
});
