import { MatrixClient } from 'matrix-js-sdk';
import { useMemo, useRef } from 'react';
import { TYPING_TIMEOUT_MS } from '../state/typingMembers';

type TypingStatusUpdater = (typing: boolean) => void;

// `disabled` is the caller's opt-out for surfaces where typing
// notifications would leak to the wrong audience. The Matrix
// `m.typing` EDU is strictly room-scoped (the spec has no `thread_id`
// field), so a thread composer that called `mx.sendTyping(roomId, ...)`
// would broadcast «X is typing» to every member watching the main
// channel chat — even though the user is privately drafting in a
// thread drawer. The drawer passes `disabled=true` to keep the
// indicator absent rather than misleading. Returns a stable noop
// when disabled so call sites keep their stable identity.
export const useTypingStatusUpdater = (
  mx: MatrixClient,
  roomId: string,
  disabled = false
): TypingStatusUpdater => {
  const statusSentTsRef = useRef<number>(0);

  const sendTypingStatus: TypingStatusUpdater = useMemo(() => {
    statusSentTsRef.current = 0;
    if (disabled) {
      return () => {
        /* noop: typing leaks across thread/main boundary by spec */
      };
    }
    return (typing) => {
      if (typing) {
        if (Date.now() - statusSentTsRef.current < TYPING_TIMEOUT_MS) {
          return;
        }

        mx.sendTyping(roomId, true, TYPING_TIMEOUT_MS);
        const sentTs = Date.now();
        statusSentTsRef.current = sentTs;

        // Don't believe server will timeout typing status;
        // Clear typing status after timeout if already not;
        setTimeout(() => {
          if (statusSentTsRef.current === sentTs) {
            mx.sendTyping(roomId, false, TYPING_TIMEOUT_MS);
            statusSentTsRef.current = 0;
          }
        }, TYPING_TIMEOUT_MS);
        return;
      }

      if (Date.now() - statusSentTsRef.current < TYPING_TIMEOUT_MS) {
        mx.sendTyping(roomId, false, TYPING_TIMEOUT_MS);
      }
      statusSentTsRef.current = 0;
    };
  }, [mx, roomId, disabled]);

  return sendTypingStatus;
};
