/**
 * 老师讲解 WebSocket 连接管理
 *
 * 功能说明：
 * 1. 系统加载时连接 WebSocket 服务（地址从环境变量 VITE_WS_URL 读取）
 * 2. 连接成功后，调用接口 /school/questionExplain/myClass 获取班级信息
 * 3. 获取到班级后，发送订阅消息：{"type":"subscribeTopic","msg":"class:{classId}"}
 * 4. 每 30 秒发送一次心跳保活
 * 5. 收到的消息统一处理，支持注册自定义消息回调
 * 6. 断线自动重连
 */
import { ref, shallowRef } from 'vue'
import questionExplainApi from '@/api/subject/questionExplain'
import { getCache } from '@/utils'
import { userStore } from '@/stores'

// ======================== 常量配置 ========================

/** 心跳发送间隔（毫秒） */
const HEARTBEAT_INTERVAL = 30_000

/** 断线重连延迟（毫秒） */
const RECONNECT_DELAY = 5_000

/** 最大重连次数，超过后停止重连 */
const MAX_RECONNECT_ATTEMPTS = 20

// ======================== 类型定义 ========================

/** WebSocket 连接状态枚举 */
export enum TeacherWsState {
  /** 未连接 */
  DISCONNECTED = 'disconnected',
  /** 连接中 */
  CONNECTING = 'connecting',
  /** 已连接 */
  CONNECTED = 'connected',
}

/** WebSocket 消息结构 */
export interface TeacherWsMessage {
  type: string
  msg?: any
  [key: string]: any
}

/** 消息回调函数类型 */
type MessageHandler = (data: TeacherWsMessage) => void

// ======================== 模块级单例状态 ========================
// 保证全局只有一个 WebSocket 连接实例

let ws: WebSocket | null = null
let heartbeatTimer: ReturnType<typeof setInterval> | null = null
let reconnectTimer: ReturnType<typeof setTimeout> | null = null
let reconnectAttempts = 0
let isManualClose = false
let visibilityHandler: (() => void) | null = null

/** 外部注册的消息处理回调集合 */
const messageHandlers: Set<MessageHandler> = new Set()

/** 连接状态（响应式） */
const connectionState = ref<TeacherWsState>(TeacherWsState.DISCONNECTED)

/** 最新收到的消息（响应式） */
const lastMessage = shallowRef<TeacherWsMessage | null>(null)

/** 班级信息（响应式） */
const classInfo = ref<any>(null)

// ======================== 内部方法 ========================

/** 获取带 token 的 WebSocket 连接地址 */
function getWsUrl(): string {
  const base = import.meta.env.VITE_WS_URL || ''
  if (!base) return ''
  const token = getCache('token') || ''
  return `${base}?token=${encodeURIComponent(token)}`
}

/** 启动心跳定时器，每 30 秒发送一次 ping */
function startHeartbeat() {
  stopHeartbeat()
  heartbeatTimer = setInterval(() => {
    sendMessage({ type: 'ping', msg: '' })
  }, HEARTBEAT_INTERVAL)
}

/** 停止心跳定时器 */
function stopHeartbeat() {
  if (heartbeatTimer) {
    clearInterval(heartbeatTimer)
    heartbeatTimer = null
  }
}

/** 清除重连定时器 */
function clearReconnectTimer() {
  if (reconnectTimer) {
    clearTimeout(reconnectTimer)
    reconnectTimer = null
  }
}

/** 尝试自动重连 */
function tryReconnect() {
  if (isManualClose) return
  if (reconnectAttempts >= MAX_RECONNECT_ATTEMPTS) {
    console.error('[TeacherExplain] 已达到最大重连次数，停止重连')
    return
  }
  clearReconnectTimer()
  reconnectTimer = setTimeout(() => {
    reconnectAttempts++
    console.log(`[TeacherExplain] 第 ${reconnectAttempts} 次重连...`)
    connect()
  }, RECONNECT_DELAY)
}

/**
 * 建立 WebSocket 连接
 * 如果已有活跃连接则跳过
 */
function connect() {
  if (ws && ws.readyState === WebSocket.OPEN) return

  const url = getWsUrl()
  if (!url) {
    console.error('[TeacherExplain] WebSocket 地址未配置，请检查环境变量 VITE_WS_URL')
    return
  }

  connectionState.value = TeacherWsState.CONNECTING
  isManualClose = false

  try {
    ws = new WebSocket(url)
  } catch (err) {
    console.error('[TeacherExplain] WebSocket 创建失败:', err)
    tryReconnect()
    return
  }

  ws.onopen = () => {
    console.log('[TeacherExplain] WebSocket 已连接')
    connectionState.value = TeacherWsState.CONNECTED
    reconnectAttempts = 0

    // 连接成功后，订阅已获取的班级
    subscribeClass()

    // 启动心跳
    startHeartbeat()

    // 查询当前讲解状态，结果走消息分发
    fetchCurrentExplainStatus()
  }

  ws.onclose = (event: CloseEvent) => {
    console.log('[TeacherExplain] WebSocket 已断开, code:', event.code)
    connectionState.value = TeacherWsState.DISCONNECTED
    stopHeartbeat()

    // 非手动关闭时自动重连
    if (!isManualClose) {
      tryReconnect()
    }
  }

  ws.onerror = (event: Event) => {
    console.error('[TeacherExplain] WebSocket 连接错误:', event)
  }

  ws.onmessage = (event: MessageEvent) => {
    try {
      // console.log('[TeacherExplain] 收到消息:', event)
      const rawData = (event.data as string).replace(/"recordId"\s*:\s*(\d+)/g, '"recordId":"$1"')
      const data: TeacherWsMessage = JSON.parse(rawData)
      lastMessage.value = data
      console.log('[TeacherExplain] 收到消息:', data)
      handleMessage(data)
    } catch (err) {
      console.error('[TeacherExplain] 消息解析失败:', event.data)
    }
  }
}

/**
 * 统一消息处理入口
 * 内部分发 + 调用外部注册的回调
 */
function handleMessage(data: TeacherWsMessage) {
  // 心跳响应不做业务处理
  if (data.type === 'pong') return

  // 调用所有已注册的外部消息回调
  messageHandlers.forEach(handler => {
    try {
      handler(data)
    } catch (err) {
      console.error('[TeacherExplain] 消息回调执行异常:', err)
    }
  })
}

/** 订阅班级主题（API 返回 { classId: '...' }，拼接为 "class:{classId}" 发送订阅） */
function subscribeClass() {
  if (!classInfo.value?.classId) return

  const classId = String(classInfo.value.classId)
  sendMessage({
    type: 'subscribeTopic',
    msg: 'class:' + classId,
  })
  console.log(`[TeacherExplain] 已订阅班级: ${classId}`)
}

/** 查询当前讲解状态，将结果伪装成 WebSocket 消息分发给所有回调 */
async function fetchCurrentExplainStatus() {
  const classId = classInfo.value?.classId
  if (!classId) return

  try {
    const res = await questionExplainApi.current(String(classId))
    console.log('[TeacherExplain] 当前讲解状态:', res)
    if (!res) return

    const type = res.explaining ? 'questionExplainStart' : 'questionExplainStop'
    handleMessage({ type, msg: res })
  } catch (err) {
    console.warn('[TeacherExplain] 查询当前讲解状态失败:', err)
  }
}

// ======================== 对外暴露方法 ========================

/**
 * 发送 WebSocket 消息
 * @param data 消息体，会被 JSON.stringify 后发送
 */
function sendMessage(data: TeacherWsMessage) {
  if (!ws || ws.readyState !== WebSocket.OPEN) {
    console.warn('[TeacherExplain] WebSocket 未连接，消息发送失败:', data)
    return
  }
  console.log('[TeacherExplain] 发送消息:', data)
  ws.send(JSON.stringify(data))
}

/**
 * 注册消息处理回调
 * 可在任意组件中调用，收到消息时会触发所有已注册的回调
 * @param handler 回调函数
 * @returns 取消注册的函数
 */
function onMessage(handler: MessageHandler): () => void {
  messageHandlers.add(handler)
  return () => {
    messageHandlers.delete(handler)
  }
}

/**
 * 初始化老师讲解 WebSocket
 * 流程：获取班级信息 → 建立 WebSocket 连接 → 订阅班级 → 启动心跳
 */
async function init() {
  const schoolId = userStore().userInfo?.schoolClass?.[0]?.schoolId
  if (Number(schoolId) === 125) {
    try {
      const res = await questionExplainApi.myClass()
      classInfo.value = res
      console.log('[TeacherExplain] 获取班级信息成功:', res)
    } catch (err) {
      console.warn('[TeacherExplain] 获取班级信息失败，仍尝试连接 WebSocket:', err)
    }
  }

  connect()
  startVisibilityListener()
}

/** 关闭 WebSocket 连接并清理所有资源 */
function close() {
  isManualClose = true
  stopHeartbeat()
  clearReconnectTimer()
  stopVisibilityListener()
  reconnectAttempts = 0

  if (ws) {
    ws.onclose = null
    ws.onerror = null
    ws.onmessage = null
    ws.onopen = null
    ws.close()
    ws = null
  }

  connectionState.value = TeacherWsState.DISCONNECTED
}

/** 断开并重新初始化（重新登录 / 页面恢复可见时调用） */
async function reconnect() {
  console.log('[TeacherExplain] 重新连接...')
  close()
  await init()
}

/** 页面恢复可见时：WS 断开则重连，未断开则刷新讲解状态 */
function onVisibilityChange() {
  if (document.hidden) return
  console.log('[TeacherExplain] 页面恢复可见')
  if (!ws || ws.readyState !== WebSocket.OPEN) {
    reconnect()
  } else {
    fetchCurrentExplainStatus()
  }
}

function startVisibilityListener() {
  stopVisibilityListener()
  visibilityHandler = onVisibilityChange
  document.addEventListener('visibilitychange', visibilityHandler)
}

function stopVisibilityListener() {
  if (visibilityHandler) {
    document.removeEventListener('visibilitychange', visibilityHandler)
    visibilityHandler = null
  }
}

/**
 * 老师讲解 WebSocket 组合式函数
 *
 * @example
 * ```ts
 * const { init, close, sendMessage, onMessage, connectionState, lastMessage, classInfo } = useTeacherExplain()
 *
 * // 初始化连接
 * init()
 *
 * // 注册消息回调
 * const unregister = onMessage((data) => {
 *   console.log('收到消息:', data)
 * })
 *
 * // 组件卸载时取消回调
 * onUnmounted(() => unregister())
 *
 * // 主动发送消息
 * sendMessage({ type: 'customType', msg: 'hello' })
 *
 * // 关闭连接
 * close()
 * ```
 */
export const useTeacherExplain = () => {
  return {
    /** 初始化连接（获取班级 → 连接 WebSocket → 订阅 → 心跳） */
    init,
    /** 关闭连接并清理资源 */
    close,
    /** 断开并重新初始化（重新登录时调用） */
    reconnect,
    /** 发送消息 */
    sendMessage,
    /** 注册消息回调，返回取消注册函数 */
    onMessage,
    /** 连接状态（响应式） */
    connectionState,
    /** 最新收到的消息（响应式） */
    lastMessage,
    /** 班级信息（响应式） */
    classInfo,
  }
}
