/**
 * HTTP处理器
 * 负责处理HTTP请求，管理会话和连接，处理信令消息
 */
import { Request, Response } from 'express';
import Offer from './offer';
import Answer from './answer';
import Candidate from './candidate';
import { v4 as uuid } from 'uuid';
import { onGetAllConnectionIds, onGetOnlineUsers as onGetWsOnlineUsers,  } from './websockethandler';
import { log, LogLevel } from '../log';
/**
 * 断开连接记录类
 * 用于记录断开连接的信息
 */
class Disconnection {
  id: string;        // 连接ID
  datetime: number;  // 断开连接的时间戳

  /**
   * 构造函数
   * @param id 连接ID
   * @param datetime 断开连接的时间戳
   */
  constructor(id: string, datetime: number) {
    this.id = id;
    this.datetime = datetime;
  }
}

// 会话超时时间（毫秒）
const TimeoutRequestedTime = 10000; // 10sec

// 是否为私有模式
let isPrivate: boolean;

/**
 * 客户端会话映射
 * 键: 会话ID
 * 值: 该会话的连接ID集合
 */
const clients: Map<string, Set<string>> = new Map<string, Set<string>>();

/**
 * 会话最后请求时间映射
 * 键: 会话ID
 * 值: 最后请求的时间戳
 */
const lastRequestedTime: Map<string, number> = new Map<string, number>();

/**
 * 连接对映射
 * 键: 连接ID
 * 值: [会话ID1, 会话ID2]
 */
const connectionPair: Map<string, [string, string]> = new Map<string, [string, string]>(); // key = connectionId

/**
 * 会话的offer映射
 * 键: 会话ID
 * 值: 该会话的连接ID到Offer对象的映射
 */
const offers: Map<string, Map<string, Offer>> = new Map<string, Map<string, Offer>>(); // key = sessionId

/**
 * 会话的answer映射
 * 键: 会话ID
 * 值: 该会话的连接ID到Answer对象的映射
 */
const answers: Map<string, Map<string, Answer>> = new Map<string, Map<string, Answer>>(); // key = sessionId

/**
 * 会话的candidate映射
 * 键: 会话ID
 * 值: 该会话的连接ID到Candidate数组的映射
 */
const candidates: Map<string, Map<string, Candidate[]>> = new Map<string, Map<string, Candidate[]>>(); // key = sessionId

/**
 * 会话的断开连接记录映射
 * 键: 会话ID
 * 值: 该会话的Disconnection对象数组
 */
const disconnections: Map<string, Disconnection[]> = new Map<string, Disconnection[]>(); // key = sessionId

/**
 * 获取或创建会话的连接ID集合
 * @param sessionId 会话ID
 * @returns 连接ID的Set集合
 */
function getOrCreateConnectionIds(sessionId: string): Set<string> {
  let connectionIds = null;
  // 检查会话是否已存在
  if (!clients.has(sessionId)) {
    // 如果不存在，创建新的连接ID集合
    connectionIds = new Set<string>();
    // 将新的连接ID集合与会话关联
    clients.set(sessionId, connectionIds);
  }
  // 获取会话的连接ID集合
  connectionIds = clients.get(sessionId);
  // 返回连接ID集合
  return connectionIds;
}

/**
 * 重置处理器状态
 * @param mode 通信模式（public或private）
 */
function reset(mode: string): void {
  // 设置是否为私有模式
  isPrivate = mode == "private";
  // 清空所有映射
  clients.clear();
  connectionPair.clear();
  offers.clear();
  answers.clear();
  candidates.clear();
  disconnections.clear();
}

/**
 * 检查会话ID是否有效
 * @param req Express请求对象
 * @param res Express响应对象
 * @param next 下一个中间件函数
 */
function checkSessionId(req: Request, res: Response, next): void {
  // 如果是根路径，直接通过
  if (req.url === '/') {
    next();
    return;
  }
  // 从请求头获取会话ID
  const id: string = req.header('session-id');
  // 检查会话是否存在
  if (!clients.has(id)) {
    res.sendStatus(404);
    return;
  }
  // 更新会话的最后请求时间
  lastRequestedTime.set(id, Date.now());
  // 继续处理请求
  next();
}

/**
 * 删除连接
 * @param sessionId 会话ID
 * @param connectionId 连接ID
 * @param datetime 时间戳
 */
function _deleteConnection(sessionId:string, connectionId:string, datetime:number) {
  // 从会话的连接ID集合中删除连接ID
  clients.get(sessionId).delete(connectionId);

  // 处理私有模式
  if(isPrivate) {
    if (connectionPair.has(connectionId)) {
      const pair = connectionPair.get(connectionId);
      // 找到另一个会话ID
      const otherSessionId = pair[0] == sessionId ? pair[1] : pair[0];
      if (otherSessionId) {
        if (clients.has(otherSessionId)) {
          // 从另一个会话的连接ID集合中删除连接ID
          clients.get(otherSessionId).delete(connectionId);
          // 向另一个会话的断开连接记录中添加记录
          const array1 = disconnections.get(otherSessionId);
          array1.push(new Disconnection(connectionId, datetime));
        }
      }
    }
  } else {
    // 公共模式：向所有其他会话的断开连接记录中添加记录
    disconnections.forEach((array, id) => {
      if (id == sessionId)
        return;
      array.push(new Disconnection(connectionId, datetime));
    });
  }

  // 从连接对映射中删除
  connectionPair.delete(connectionId);
  // 从会话的offer映射中删除
  offers.get(sessionId).delete(connectionId);
  // 从会话的answer映射中删除
  answers.get(sessionId).delete(connectionId);
  // 从会话的candidate映射中删除
  candidates.get(sessionId).delete(connectionId);

  // 向当前会话的断开连接记录中添加记录
  const array2 = disconnections.get(sessionId);
  array2.push(new Disconnection(connectionId, datetime));
}

/**
 * 删除会话
 * @param sessionId 会话ID
 */
function _deleteSession(sessionId: string) {
  // 如果会话存在，删除其所有连接
  if(clients.has(sessionId)) {
    for(const connectionId of Array.from(clients.get(sessionId))) {
      _deleteConnection(sessionId, connectionId, Date.now());
    }
  }
  // 从所有映射中删除会话
  offers.delete(sessionId);
  answers.delete(sessionId);
  candidates.delete(sessionId);
  clients.delete(sessionId);
  disconnections.delete(sessionId);
}

/**
 * 检查超时会话
 */
function _checkForTimedOutSessions(): void {
  // 遍历所有会话
  for (const sessionId of Array.from(clients.keys()))
  {
    // 如果会话没有最后请求时间，跳过
    if(!lastRequestedTime.has(sessionId))
      continue;
    // 如果会话未超时，跳过
    if(lastRequestedTime.get(sessionId) > Date.now() - TimeoutRequestedTime)
      continue;
    // 删除超时会话
    _deleteSession(sessionId);
    log(LogLevel.log, `deleted sessionId:${sessionId} by timeout.`);
  }
}

/**
 * 获取会话的连接ID列表
 * @param sessionId 会话ID
 * @returns 连接ID数组
 */
function _getConnection(sessionId: string): string[] {
  // 检查超时会话
  _checkForTimedOutSessions();
  // 返回会话的连接ID集合的数组形式
  return Array.from(clients.get(sessionId));
}

/**
 * 获取会话的断开连接记录
 * @param sessionId 会话ID
 * @param fromTime 起始时间戳
 * @returns 断开连接记录数组
 */
function _getDisconnection(sessionId: string, fromTime: number): Disconnection[] {
  // 检查超时会话
  _checkForTimedOutSessions();
  let arrayDisconnections: Disconnection[] = [];
  // 如果断开连接记录存在，获取该会话的断开连接记录
  if (disconnections.size != 0 && disconnections.has(sessionId)) {
    arrayDisconnections = disconnections.get(sessionId);
  }

  // 如果指定了起始时间，过滤出时间戳大于等于起始时间的记录
  if (fromTime > 0) {
    arrayDisconnections = arrayDisconnections.filter((v) => v.datetime >= fromTime);
  }
  return arrayDisconnections;
}

/**
 * 获取会话的offer列表
 * @param sessionId 会话ID
 * @param fromTime 起始时间戳
 * @returns [连接ID, Offer]数组
 */
function _getOffer(sessionId: string, fromTime: number): [string, Offer][] {
  let arrayOffers: [string, Offer][] = [];

  // 如果offer映射不为空
  if (offers.size != 0) {
    // 处理私有模式
    if (isPrivate) {
      // 如果会话存在offer记录，获取该会话的offer列表
      if (offers.has(sessionId)) {
        arrayOffers = Array.from(offers.get(sessionId));
      }
    } else {
      // 公共模式：获取所有其他会话的offer列表
      const otherSessionMap = Array.from(offers).filter(x => x[0] != sessionId);
      arrayOffers = [].concat(...Array.from(otherSessionMap, x => Array.from(x[1], y => [y[0], y[1]])));
    }
  }

  // 如果指定了起始时间，过滤出时间戳大于等于起始时间的offer
  if (fromTime > 0) {
    arrayOffers = arrayOffers.filter((v) => v[1].datetime >= fromTime);
  }
  return arrayOffers;
}

/**
 * 获取会话的answer列表
 * @param sessionId 会话ID
 * @param fromTime 起始时间戳
 * @returns [连接ID, Answer]数组
 */
function _getAnswer(sessionId: string, fromTime: number): [string, Answer][] {
  let arrayAnswers: [string, Answer][] = [];

  // 如果answer映射不为空且会话存在answer记录，获取该会话的answer列表
  if (answers.size != 0 && answers.has(sessionId)) {
    arrayAnswers = Array.from(answers.get(sessionId));
  }

  // 如果指定了起始时间，过滤出时间戳大于等于起始时间的answer
  if (fromTime > 0) {
    arrayAnswers = arrayAnswers.filter((v) => v[1].datetime >= fromTime);
  }
  return arrayAnswers;
}

/**
 * 获取会话的candidate列表
 * @param sessionId 会话ID
 * @param fromTime 起始时间戳
 * @returns [连接ID, Candidate]数组
 */
function _getCandidate(sessionId: string, fromTime: number): [string, Candidate][] {
  // 获取会话的连接ID列表
  const connectionIds = Array.from(clients.get(sessionId));
  const arr: [string, Candidate][] = [];
  // 遍历每个连接ID
  for (const connectionId of connectionIds) {
    // 获取连接对
    const pair = connectionPair.get(connectionId);
    if (pair == null) {
      continue;
    }
    // 找到另一个会话ID
    const otherSessionId = sessionId === pair[0] ? pair[1] : pair[0];
    // 如果另一个会话不存在candidate记录或该连接ID不存在candidate记录，跳过
    if (!candidates.get(otherSessionId) || !candidates.get(otherSessionId).get(connectionId)) {
      continue;
    }
    // 获取该连接ID的candidate列表，并过滤出时间戳大于等于起始时间的candidate
    const arrayCandidates = candidates.get(otherSessionId).get(connectionId)
      .filter((v) => v.datetime >= fromTime);
    // 如果没有符合条件的candidate，跳过
    if (arrayCandidates.length === 0) {
      continue;
    }
    // 将符合条件的candidate添加到结果数组中
    for (const candidate of arrayCandidates) {
      arr.push([connectionId, candidate]);
    }
  }
  return arr;
}

/**
 * @swagger
 * /signaling/answer:
 *   get:
 *     summary: 获取answer列表
 *     description: 获取当前会话的answer信令消息列表
 *     security:
 *       - sessionAuth: []
 *     parameters:
 *       - in: query
 *         name: fromtime
 *         schema:
 *           type: number
 *         description: 起始时间戳，用于过滤消息
 *     responses:
 *       200:
 *         description: 成功获取answer列表
 *         content:
 *           application/json:
 *             schema:
 *               type: object
 *               properties:
 *                 answers:
 *                   type: array
 *                   items:
 *                     type: object
 *                     properties:
 *                       connectionId:
 *                         type: string
 *                         description: 连接ID
 *                       sdp:
 *                         type: string
 *                         description: SDP描述
 *                       type:
 *                         type: string
 *                         description: 消息类型
 *                       datetime:
 *                         type: number
 *                         description: 时间戳
 */
function getAnswer(req: Request, res: Response): void {
  // 从请求查询参数中获取`fromtime`参数
  const fromTime: number = req.query.fromtime ? Number(req.query.fromtime) : 0;
  // 从请求头获取会话ID
  const sessionId: string = req.header('session-id');
  // 获取会话的answer列表
  const answers: [string, Answer][] = _getAnswer(sessionId, fromTime);
  // 返回JSON响应，包含answer列表
  res.json({ answers: answers.map((v) => ({ connectionId: v[0], sdp: v[1].sdp, type: "answer", datetime: v[1].datetime })) });
}

/**
 * @swagger
 * /signaling/connection:
 *   get:
 *     summary: 获取连接列表
 *     description: 获取当前会话的连接列表
 *     security:
 *       - sessionAuth: []
 *     responses:
 *       200:
 *         description: 成功获取连接列表
 *         content:
 *           application/json:
 *             schema:
 *               type: object
 *               properties:
 *                 connections:
 *                   type: array
 *                   items:
 *                     type: object
 *                     properties:
 *                       connectionId:
 *                         type: string
 *                         description: 连接ID
 *                       type:
 *                         type: string
 *                         description: 消息类型
 *                       datetime:
 *                         type: number
 *                         description: 时间戳
 */
function getConnection(req: Request, res: Response): void {
  // 从请求头获取会话ID
  const sessionId: string = req.header('session-id');
  // 获取会话的连接ID列表
  const connections = _getConnection(sessionId);
  // 返回JSON响应，包含连接列表
  res.json({ connections: connections.map((v) => ({ connectionId: v, type: "connect", datetime: Date.now() })) });
}

/**
 * @swagger
 * /signaling/offer:
 *   get:
 *     summary: 获取offer列表
 *     description: 获取当前会话的offer信令消息列表
 *     security:
 *       - sessionAuth: []
 *     parameters:
 *       - in: query
 *         name: fromtime
 *         schema:
 *           type: number
 *         description: 起始时间戳，用于过滤消息
 *     responses:
 *       200:
 *         description: 成功获取offer列表
 *         content:
 *           application/json:
 *             schema:
 *               type: object
 *               properties:
 *                 offers:
 *                   type: array
 *                   items:
 *                     type: object
 *                     properties:
 *                       connectionId:
 *                         type: string
 *                         description: 连接ID
 *                       sdp:
 *                         type: string
 *                         description: SDP描述
 *                       polite:
 *                         type: boolean
 *                         description: 是否为polite模式
 *                       type:
 *                         type: string
 *                         description: 消息类型
 *                       datetime:
 *                         type: number
 *                         description: 时间戳
 */
function getOffer(req: Request, res: Response): void {
  // 从请求查询参数中获取`fromtime`参数
  const fromTime: number = req.query.fromtime ? Number(req.query.fromtime) : 0;
  // 从请求头获取会话ID
  const sessionId: string = req.header('session-id');
  // 获取会话的offer列表
  const offers = _getOffer(sessionId, fromTime);
  // 返回JSON响应，包含offer列表
  res.json({ offers: offers.map((v) => ({ connectionId: v[0], sdp: v[1].sdp, polite: v[1].polite, type: "offer", datetime: v[1].datetime })) });
}

/**
 * @swagger
 * /signaling/candidate:
 *   get:
 *     summary: 获取candidate列表
 *     description: 获取当前会话的candidate信令消息列表
 *     security:
 *       - sessionAuth: []
 *     parameters:
 *       - in: query
 *         name: fromtime
 *         schema:
 *           type: number
 *         description: 起始时间戳，用于过滤消息
 *     responses:
 *       200:
 *         description: 成功获取candidate列表
 *         content:
 *           application/json:
 *             schema:
 *               type: object
 *               properties:
 *                 candidates:
 *                   type: array
 *                   items:
 *                     type: object
 *                     properties:
 *                       connectionId:
 *                         type: string
 *                         description: 连接ID
 *                       candidate:
 *                         type: string
 *                         description: ICE候选者信息
 *                       sdpMLineIndex:
 *                         type: number
 *                         description: SDP媒体行索引
 *                       sdpMid:
 *                         type: string
 *                         description: SDP媒体ID
 *                       type:
 *                         type: string
 *                         description: 消息类型
 *                       datetime:
 *                         type: number
 *                         description: 时间戳
 */
function getCandidate(req: Request, res: Response): void {
  // 从请求查询参数中获取`fromtime`参数
  const fromTime: number = req.query.fromtime ? Number(req.query.fromtime) : 0;
  // 从请求头获取会话ID
  const sessionId: string = req.header('session-id');
  // 获取会话的candidate列表
  const candidates = _getCandidate(sessionId, fromTime);
  // 返回JSON响应，包含candidate列表
  res.json({ candidates: candidates.map((v) => ({ connectionId: v[0], candidate: v[1].candidate, sdpMLineIndex: v[1].sdpMLineIndex, sdpMid: v[1].sdpMid, type: "candidate", datetime: v[1].datetime })) });
}

/**
 * @swagger
 * /signaling:
 *   get:
 *     summary: 获取所有信令消息
 *     description: 获取当前会话的所有信令消息，包括连接、断开连接、offer、answer和candidate
 *     security:
 *       - sessionAuth: []
 *     parameters:
 *       - in: query
 *         name: fromtime
 *         schema:
 *           type: number
 *         description: 起始时间戳，用于过滤消息
 *     responses:
 *       200:
 *         description: 成功获取所有信令消息
 *         content:
 *           application/json:
 *             schema:
 *               type: object
 *               properties:
 *                 messages:
 *                   type: array
 *                   items:
 *                     type: object
 *                     properties:
 *                       connectionId:
 *                         type: string
 *                         description: 连接ID
 *                       type:
 *                         type: string
 *                         description: 消息类型
 *                       datetime:
 *                         type: number
 *                         description: 时间戳
 *                       sdp:
 *                         type: string
 *                         description: SDP描述（仅offer和answer消息）
 *                       polite:
 *                         type: boolean
 *                         description: 是否为polite模式（仅offer消息）
 *                       candidate:
 *                         type: string
 *                         description: ICE候选者信息（仅candidate消息）
 *                       sdpMLineIndex:
 *                         type: number
 *                         description: SDP媒体行索引（仅candidate消息）
 *                       sdpMid:
 *                         type: string
 *                         description: SDP媒体ID（仅candidate消息）
 *                 datetime:
 *                   type: number
 *                   description: 当前时间戳
 */
function getAll(req: Request, res: Response): void {
  // 从请求查询参数中获取`fromtime`参数
  const fromTime: number = req.query.fromtime ? Number(req.query.fromtime) : 0;
  // 从请求头获取会话ID
  const sessionId: string = req.header('session-id');
  // 获取各种信令消息
  const connections = _getConnection(sessionId);
  const offers = _getOffer(sessionId, fromTime);
  const answers: [string, Answer][] = _getAnswer(sessionId, fromTime);
  const candidates: [string, Candidate][] = _getCandidate(sessionId, fromTime);
  const disconnections: Disconnection[] = _getDisconnection(sessionId, fromTime);
  const datetime = lastRequestedTime.get(sessionId);

  let array: any[] = [];

  // 合并所有信令消息
  array = array.concat(connections.map((v) => ({ connectionId: v, type: "connect", datetime: datetime })));
  array = array.concat(offers.map((v) => ({ connectionId: v[0], sdp: v[1].sdp, polite: v[1].polite, type: "offer", datetime: v[1].datetime })));
  array = array.concat(answers.map((v) => ({ connectionId: v[0], sdp: v[1].sdp, type: "answer", datetime: v[1].datetime })));
  array = array.concat(candidates.map((v) => ({ connectionId: v[0], candidate: v[1].candidate, sdpMLineIndex: v[1].sdpMLineIndex, sdpMid: v[1].sdpMid, type: "candidate", datetime: v[1].datetime })));
  array = array.concat(disconnections.map((v) => ({ connectionId: v.id, type: "disconnect", datetime: v.datetime })));

  // 按时间戳排序
  array.sort((a, b) => a.datetime - b.datetime);
  // 返回JSON响应，包含所有信令消息
  res.json({ messages: array, datetime: datetime });
}

/**
 * @swagger
 * /signaling:
 *   put:
 *     summary: 创建会话
 *     description: 创建一个新的会话，并返回会话ID
 *     responses:
 *       200:
 *         description: 成功创建会话
 *         content:
 *           application/json:
 *             schema:
 *               type: object
 *               properties:
 *                 sessionId:
 *                   type: string
 *                   description: 新创建的会话ID
 */
function createSession(sessionId: string, res: Response): void;
function createSession(req: Request, res: Response): void;

function createSession(req: string | Request, res: Response): void {
  // 确定会话ID
  const sessionId: string = typeof req === "string" ? req : uuid();
  // 为会话创建各种映射
  clients.set(sessionId, new Set<string>());
  offers.set(sessionId, new Map<string, Offer>());
  answers.set(sessionId, new Map<string, Answer>());
  candidates.set(sessionId, new Map<string, Candidate[]>());
  disconnections.set(sessionId, []);
  // 返回JSON响应，包含会话ID
  res.json({ sessionId: sessionId });
}

/**
 * @swagger
 * /signaling:
 *   delete:
 *     summary: 删除会话
 *     description: 删除当前会话及其所有连接
 *     security:
 *       - sessionAuth: []
 *     responses:
 *       200:
 *         description: 成功删除会话
 */
function deleteSession(req: Request, res: Response): void {
  // 从请求头获取会话ID
  const id: string = req.header('session-id');
  // 删除会话
  _deleteSession(id);
  // 返回200状态码表示请求处理成功
  res.sendStatus(200);
}

/**
 * @swagger
 * /signaling/connection:
 *   put:
 *     summary: 创建连接
 *     description: 创建一个新的连接，并返回连接信息
 *     security:
 *       - sessionAuth: []
 *     requestBody:
 *       required: true
 *       content:
 *         application/json:
 *           schema:
 *             type: object
 *             properties:
 *               connectionId:
 *                 type: string
 *                 description: 连接ID
 *     responses:
 *       200:
 *         description: 成功创建连接
 *         content:
 *           application/json:
 *             schema:
 *               type: object
 *               properties:
 *                 connectionId:
 *                   type: string
 *                   description: 连接ID
 *                 polite:
 *                   type: boolean
 *                   description: 是否为polite模式
 *                 type:
 *                   type: string
 *                   description: 消息类型
 *                 datetime:
 *                   type: number
 *                   description: 时间戳
 *       400:
 *         description: 请求参数错误
 */
function createConnection(req: Request, res: Response): void {
  // 从请求头获取会话ID
  const sessionId: string = req.header('session-id');
  // 从请求体获取连接ID
  const { connectionId } = req.body;
  // 获取会话的最后请求时间
  const datetime = lastRequestedTime.get(sessionId);

  // 检查连接ID是否存在
  if (connectionId == null) {
    res.status(400).send({ error: new Error(`connectionId is required`) });
    return;
  }
  let polite = true;
  // 处理私有模式
  if (isPrivate) {
    if (connectionPair.has(connectionId)) {
      const pair = connectionPair.get(connectionId);

      // 检查连接ID是否已被使用
      if (pair[0] != null && pair[1] != null) {
        const err = new Error(`${connectionId}: This connection id is already used.`);
        log(LogLevel.warn, err.message);
        res.status(400).send({ error: err });
        return;
      } else if (pair[0] != null) {
        // 找到配对连接
        connectionPair.set(connectionId, [pair[0], sessionId]);
        // 添加连接ID到另一个会话
        const map = getOrCreateConnectionIds(pair[0]);
        map.add(connectionId);
      }
    } else {
      // 创建新的连接对
      connectionPair.set(connectionId, [sessionId, null]);
      polite = false;
    }
  }

  // 添加连接ID到当前会话
  const connectionIds = getOrCreateConnectionIds(sessionId);
  connectionIds.add(connectionId);
  // 返回JSON响应，包含连接信息
  res.json({ connectionId: connectionId, polite: polite, type: "connect", datetime: datetime });
}

/**
 * @swagger
 * /signaling/connection:
 *   delete:
 *     summary: 删除连接
 *     description: 删除指定的连接
 *     security:
 *       - sessionAuth: []
 *     requestBody:
 *       required: true
 *       content:
 *         application/json:
 *           schema:
 *             type: object
 *             properties:
 *               connectionId:
 *                 type: string
 *                 description: 连接ID
 *     responses:
 *       200:
 *         description: 成功删除连接
 *         content:
 *           application/json:
 *             schema:
 *               type: object
 *               properties:
 *                 connectionId:
 *                   type: string
 *                   description: 连接ID
 */
function deleteConnection(req: Request, res: Response): void {
  // 从请求头获取会话ID
  const sessionId: string = req.header('session-id');
  // 从请求体获取连接ID
  const { connectionId } = req.body;
  // 获取会话的最后请求时间
  const datetime = lastRequestedTime.get(sessionId);

  // 删除连接
  _deleteConnection(sessionId, connectionId, datetime);

  // 返回JSON响应，包含连接ID
  res.json({ connectionId: connectionId });
}

/**
 * @swagger
 * /signaling/offer:
 *   post:
 *     summary: 发送offer信令
 *     description: 发送offer信令消息
 *     security:
 *       - sessionAuth: []
 *     requestBody:
 *       required: true
 *       content:
 *         application/json:
 *           schema:
 *             type: object
 *             properties:
 *               connectionId:
 *                 type: string
 *                 description: 连接ID
 *               sdp:
 *                 type: string
 *                 description: SDP描述
 *     responses:
 *       200:
 *         description: 成功发送offer信令
 */
function postOffer(req: Request, res: Response): void {
  const sessionId: string = req.header('session-id');
  const { connectionId } = req.body;
  const datetime = lastRequestedTime.get(sessionId);
  let keySessionId = null;
  let polite = false;

  if (isPrivate) {
    if (connectionPair.has(connectionId)) {
      const pair = connectionPair.get(connectionId);
      keySessionId = pair[0] == sessionId ? pair[1] : pair[0];
      if (keySessionId != null) {
        polite = true;
        const map = offers.get(keySessionId);
        map.set(connectionId, new Offer(req.body.sdp, datetime, polite));
      }
    }
    res.sendStatus(200);
    return;
  }

  if(!connectionPair.has(connectionId))
  {
    connectionPair.set(connectionId, [sessionId, null]);
  }

  keySessionId = sessionId;
  const map = offers.get(keySessionId);
  map.set(connectionId, new Offer(req.body.sdp, datetime, polite));

  res.sendStatus(200);
}

/**
 * @swagger
 * /signaling/answer:
 *   post:
 *     summary: 发送answer信令
 *     description: 发送answer信令消息
 *     security:
 *       - sessionAuth: []
 *     requestBody:
 *       required: true
 *       content:
 *         application/json:
 *           schema:
 *             type: object
 *             properties:
 *               connectionId:
 *                 type: string
 *                 description: 连接ID
 *               sdp:
 *                 type: string
 *                 description: SDP描述
 *     responses:
 *       200:
 *         description: 成功发送answer信令
 */
function postAnswer(req: Request, res: Response): void {
  const sessionId: string = req.header('session-id');
  const { connectionId } = req.body;
  const datetime = lastRequestedTime.get(sessionId);
  const connectionIds = getOrCreateConnectionIds(sessionId);
  connectionIds.add(connectionId);

  if (!connectionPair.has(connectionId)) {
    res.sendStatus(200);
    return;
  }

  // add connectionPair
  const pair = connectionPair.get(connectionId);
  const otherSessionId = pair[0] == sessionId ? pair[1] : pair[0];
  if (!clients.has(otherSessionId)) {
    // already deleted
    res.sendStatus(200);
    return;
  }

  if (!isPrivate) {
    connectionPair.set(connectionId, [otherSessionId, sessionId]);
  }

  const map = answers.get(otherSessionId);
  map.set(connectionId, new Answer(req.body.sdp, datetime));

  // update datetime for candidates
  const mapCandidates = candidates.get(otherSessionId);
  if (mapCandidates) {
    const arrayCandidates = mapCandidates.get(connectionId);
    if (arrayCandidates) {
      for (const candidate of arrayCandidates) {
        candidate.datetime = datetime;
      }
    }
  }
  res.sendStatus(200);
}

/**
 * @swagger
 * /signaling/candidate:
 *   post:
 *     summary: 发送candidate信令
 *     description: 发送candidate信令消息
 *     security:
 *       - sessionAuth: []
 *     requestBody:
 *       required: true
 *       content:
 *         application/json:
 *           schema:
 *             type: object
 *             properties:
 *               connectionId:
 *                 type: string
 *                 description: 连接ID
 *               candidate:
 *                 type: string
 *                 description: ICE候选者信息
 *               sdpMLineIndex:
 *                 type: number
 *                 description: SDP媒体行索引
 *               sdpMid:
 *                 type: string
 *                 description: SDP媒体ID
 *     responses:
 *       200:
 *         description: 成功发送candidate信令
 */
function postCandidate(req: Request, res: Response): void {
  const sessionId: string = req.header('session-id');
  const { connectionId } = req.body;
  const datetime = lastRequestedTime.get(sessionId);

  const map = candidates.get(sessionId);
  if (!map.has(connectionId)) {
    map.set(connectionId, []);
  }
  const arr = map.get(connectionId);
  const candidate = new Candidate(req.body.candidate, req.body.sdpMLineIndex, req.body.sdpMid, datetime);
  arr.push(candidate);
  res.sendStatus(200);
}

/**
 * @swagger
 * /signaling/connection-ids:
 *   get:
 *     summary: 获取所有连接ID
 *     description: 获取所有当前活跃的连接ID
 *     security:
 *       - sessionAuth: []
 *     responses:
 *       200:
 *         description: 成功获取连接ID列表
 *         content:
 *           application/json:
 *             schema:
 *               type: object
 *               properties:
 *                 connectionIds:
 *                   type: array
 *                   items:
 *                     type: string
 *                     description: 连接ID
 *                 totalCount:
 *                   type: number
 *                   description: 总连接数
 */
function getAllConnectionIds(req: Request, res: Response): void {
  // 获取所有连接ID
  const connectionIds = onGetAllConnectionIds();
  // 返回JSON响应，包含连接ID列表和总数量
  res.json({ connectionIds: connectionIds, totalCount: connectionIds.length });
}

/**
 * 获取在线WebSocket用户列表
 * @param req HTTP请求对象
 * @param res HTTP响应对象
 */
/**
 * @swagger
 * /signaling/users:
 *   get:
 *     summary: 获取全部在线WebSocket用户列表
 *     description: 获取所有当前已建立WebSocket连接的用户，包括未加入房间的大厅用户；支持按 connectionId 过滤指定房间内的用户
 *     parameters:
 *       - in: query
 *         name: connectionId
 *         schema:
 *           type: string
 *         required: false
 *         description: 连接ID，传入时仅返回该房间内的在线用户
 *     responses:
 *       200:
 *         description: 成功获取在线用户列表
 *         content:
 *           application/json:
 *             schema:
 *               type: object
 *               properties:
 *                 users:
 *                   type: array
 *                   items:
 *                     type: object
 *                     properties:
 *                       connectionId:
 *                         type: string
 *                         description: 所属连接ID
 *                       participantId:
 *                         type: string
 *                         description: 参与者ID
 *                       role:
 *                         type: string
 *                         enum: [host, participant, idle]
 *                         description: 角色
 *                       socketId:
 *                         type: string
 *                         description: WebSocket连接ID
 *                       userId:
 *                         type: string
 *                         description: 用户ID
 *                       name:
 *                         type: string
 *                         description: 用户名称
 *                       avatar:
 *                         type: string
 *                         description: 用户头像URL
 *                 totalCount:
 *                   type: number
 *                   description: 在线WebSocket用户总数
 */
function getOnlineUsers(req: Request, res: Response): void {
  const connectionId = typeof req.query.connectionId === 'string' ? req.query.connectionId : undefined;
  const users = onGetWsOnlineUsers(connectionId);
  res.json({ users: users, totalCount: users.length });
}
/**
 * 导出HTTP处理器函数
 */
export {
  reset,             // 重置处理器状态
  checkSessionId,    // 检查会话ID是否有效
  getAll,            // 获取所有信令消息
  getConnection,     // 获取连接列表
  getOffer,          // 获取offer列表
  getAnswer,         // 获取answer列表
  getCandidate,      // 获取candidate列表
  createSession,     // 创建会话
  deleteSession,     // 删除会话
  createConnection,  // 创建连接
  deleteConnection,  // 删除连接
  postOffer,         // 处理offer信令消息
  postAnswer,        // 处理answer信令消息
  postCandidate,     // 处理candidate信令消息
  getAllConnectionIds, // 获取所有连接ID
  getOnlineUsers     // 获取在线WebSocket用户列表
};
