import { useCallback, useEffect, useRef } from 'react';
import { type ChatMessage, getWsUrl } from '../api';
import { useAuth } from '../auth/AuthContext';
import { playChatSound, playAlertSound } from '../utils/notifySound';

type ChatIncomingHandler = (msg: ChatMessage) => void;
export type PresenceUpdate = { studentId: number; online: boolean; classId?: number };
export type StudentViolationEvent = {
  studentId: number;
  studentName?: string;
  studentCode?: string;
  kind: string;
  reason: string;
  monitorMode?: string;
  classId?: number;
};

const chatHandlers = new Set<ChatIncomingHandler>();
const presenceHandlers = new Set<(p: PresenceUpdate) => void>();
const violationHandlers = new Set<(v: StudentViolationEvent) => void>();

export function onStaffChatMessage(handler: ChatIncomingHandler): () => void {
  chatHandlers.add(handler);
  return () => { chatHandlers.delete(handler); };
}

export function onStudentPresence(handler: (p: PresenceUpdate) => void): () => void {
  presenceHandlers.add(handler);
  return () => { presenceHandlers.delete(handler); };
}

export function onStudentViolation(handler: (v: StudentViolationEvent) => void): () => void {
  violationHandlers.add(handler);
  return () => { violationHandlers.delete(handler); };
}

function scheduleBackoff(attempt: number): number {
  const base = Math.min(1000 * 2 ** Math.min(attempt, 4), 10000);
  return base + Math.floor(Math.random() * 250);
}

export function kindLabel(kind: string): string {
  switch (kind) {
    case 'app_closed': return 'Tự đóng app';
    case 'unclean_shutdown': return 'Tắt đột ngột';
    case 'multi_monitor': return 'Nhiều màn hình';
    case 'user_switch': return 'Đổi user';
    case 'session_change': return 'Khóa / đổi phiên';
    case 'virtual_desktop': return 'Desktop ảo';
    case 'wifi': return 'WiFi trái phép';
    case 'guard': return 'Vi phạm môi trường';
    default: return kind || 'Vi phạm';
  }
}

/** WebSocket luôn bật khi đã login — chat + presence + violation + keepalive. */
export function StaffChatSocket() {
  const { staff, token } = useAuth();
  const staffIdRef = useRef(0);

  useEffect(() => {
    staffIdRef.current = staff?.id ?? 0;
  }, [staff?.id]);

  const dispatchChat = useCallback((msg: ChatMessage) => {
    chatHandlers.forEach((h) => h(msg));
  }, []);

  useEffect(() => {
    if (!token || !staff?.id) return;

    const wsUrl = getWsUrl(`/ws?role=teacher&staffId=${staff.id}`);
    let ws: WebSocket | null = null;
    let retryTimer: ReturnType<typeof setTimeout> | null = null;
    let pingTimer: ReturnType<typeof setInterval> | null = null;
    let closed = false;
    let attempt = 0;

    const clearPing = () => {
      if (pingTimer) {
        clearInterval(pingTimer);
        pingTimer = null;
      }
    };

    const connect = () => {
      if (closed) return;
      ws = new WebSocket(wsUrl);

      ws.onopen = () => {
        attempt = 0;
        clearPing();
        pingTimer = setInterval(() => {
          if (ws?.readyState === WebSocket.OPEN) {
            ws.send(JSON.stringify({ event: 'client:ping', data: {} }));
          }
        }, 15000);
      };

      ws.onmessage = (ev) => {
        try {
          const payload = JSON.parse(ev.data);
          if (payload.event === 'client:pong') return;
          if (payload.event === 'presence:update') {
            const studentId = Number(payload.data?.studentId ?? 0);
            if (!studentId) return;
            presenceHandlers.forEach((h) => h({
              studentId,
              online: !!payload.data?.online,
              classId: Number(payload.data?.classId ?? 0) || undefined,
            }));
            return;
          }
          if (payload.event === 'teacher:student-violation') {
            const studentId = Number(payload.data?.studentId ?? 0);
            if (!studentId) return;
            playAlertSound();
            violationHandlers.forEach((h) => h({
              studentId,
              studentName: payload.data?.studentName || '',
              studentCode: payload.data?.studentCode || '',
              kind: String(payload.data?.kind || ''),
              reason: String(payload.data?.reason || ''),
              monitorMode: payload.data?.monitorMode || '',
              classId: Number(payload.data?.classId ?? 0) || undefined,
            }));
            return;
          }
          if (payload.event !== 'chat:message') return;
          const msg = payload.data as ChatMessage;
          const targetStaff = Number(msg.targetStaffId ?? msg.staffId ?? 0);
          if (targetStaff > 0 && targetStaff !== staffIdRef.current) return;
          dispatchChat(msg);
        } catch {
          /* ignore */
        }
      };

      ws.onclose = () => {
        clearPing();
        if (!closed) {
          retryTimer = setTimeout(connect, scheduleBackoff(attempt++));
        }
      };
    };

    connect();

    return () => {
      closed = true;
      clearPing();
      if (retryTimer) clearTimeout(retryTimer);
      ws?.close();
    };
  }, [token, staff?.id, dispatchChat]);

  return null;
}

export { playChatSound, playAlertSound };
