'use client';

/**
 * Shared typing indicator hook for rooms, issues, and PRs.
 * Wraps the room-context's typing logic for use in non-room contexts.
 *
 * Usage:
 *   const { typingUsers } = useTypingIndicator({ roomId, wsClient });
 *   // or in issue/PR context:
 *   const { typingUsers } = useTypingIndicator({ projectName, issueNumber });
 */

import { useState, useEffect, useRef } from 'react';
import type { RoomWsClient } from '@/lib/room-ws-client';
import type { TypingStartPayload, TypingStopPayload } from '@/lib/ws-protocol';

export interface TypingUser {
  userId: string;
  username: string;
  avatarUrl?: string;
}

interface UseTypingIndicatorOptions {
  /** Room ID for room-scoped typing (used in room context) */
  roomId?: string;
  /** WebSocket client */
  wsClient?: RoomWsClient | null;
  /** Timeout in ms before a typing user is considered idle. Default: 4000ms */
  timeout?: number;
}

export interface UseTypingIndicatorReturn {
  /** Users currently typing in this context */
  typingUsers: TypingUser[];
  /** Send a typing start event */
  sendTypingStart: () => void;
  /** Send a typing stop event */
  sendTypingStop: () => void;
}

/** Debounce timer ref helper */
function createTypingTracker(timeoutMs: number) {
  const timers = new Map<string, ReturnType<typeof setTimeout>>();

  function set(userId: string, onExpire: () => void) {
    clear(userId);
    timers.set(userId, setTimeout(onExpire, timeoutMs));
  }

  function clear(userId: string) {
    const existing = timers.get(userId);
    if (existing !== undefined) {
      clearTimeout(existing);
      timers.delete(userId);
    }
  }

  function clearAll() {
    for (const t of timers.values()) clearTimeout(t);
    timers.clear();
  }

  return { set, clear, clearAll };
}

export function useTypingIndicator({
  roomId,
  wsClient,
  timeout = 4000,
}: UseTypingIndicatorOptions): UseTypingIndicatorReturn {
  const [typingUsers, setTypingUsers] = useState<TypingUser[]>([]);
  const trackerRef = useRef(createTypingTracker(timeout));
  const roomIdRef = useRef(roomId);

  // Keep roomId ref current
  useEffect(() => {
    roomIdRef.current = roomId;
  }, [roomId]);

  // Register WS callbacks
  useEffect(() => {
    if (!wsClient || !roomId) return;

    const tracker = trackerRef.current;

    const handleTypingStart = (payload: TypingStartPayload) => {
      // Only care about typing in this room
      if (payload.room_id !== roomIdRef.current) return;

      tracker.set(payload.user_id, () => {
        setTypingUsers((prev) => prev.filter((u) => u.userId !== payload.user_id));
      });

      setTypingUsers((prev) => {
        if (prev.some((u) => u.userId === payload.user_id)) return prev;
        return [
          ...prev,
          {
            userId: payload.user_id,
            username: payload.username,
            avatarUrl: payload.avatar_url,
          },
        ];
      });
    };

    const handleTypingStop = (payload: TypingStopPayload) => {
      if (payload.room_id !== roomIdRef.current) return;
      tracker.clear(payload.user_id);
      setTypingUsers((prev) => prev.filter((u) => u.userId !== payload.user_id));
    };

    wsClient.updateCallbacks({
      onTypingStart: handleTypingStart,
      onTypingStop: handleTypingStop,
    });

    return () => {
      tracker.clearAll();
      wsClient.updateCallbacks({ onTypingStart: undefined, onTypingStop: undefined });
      setTypingUsers([]);
    };
  }, [wsClient, roomId, timeout]);

  const sendTypingStart = () => {
    if (!wsClient || !roomId) return;
    wsClient.sendTyping?.(roomId, 'start');
  };

  const sendTypingStop = () => {
    if (!wsClient || !roomId) return;
    wsClient.sendTyping?.(roomId, 'stop');
  };

  return { typingUsers, sendTypingStart, sendTypingStop };
}
