import { useEffect, useRef } from 'react';
import { MatrixClient, MatrixEvent, MatrixEventEvent, Room } from 'matrix-js-sdk';
import { roomHaveNotification, unreadIsOnlyVerification } from '../../utils/room';
import { markAsRead } from '../../utils/notifications';

/**
 * A COMPLETED in-room device-verification request is a plain `m.room.message`
 * that permanently keeps a DM's server/SDK notification count > 0 (it matches the
 * default DM push rule and there's no recency gate), so the DM re-lights as unread
 * on every fresh sync. `getUnreadInfo`'s suppression hides the dot, but the raw
 * SDK count stays "dirty" (desktop badge, other consumers) and the SDK re-inflates
 * it on every decrypt. The only durable, SDK-supported fix is a read receipt that
 * covers the request event.
 *
 * This hook sends that receipt — but ONLY when a room's ENTIRE unread span is
 * verification-flow events (`unreadIsOnlyVerification`), so it can never mark a
 * real unread message read. It fires at most once per room per session, after the
 * tail decrypts (the count is only attributable to the request post-decryption).
 * `markAsRead` honours the user's private-read-receipt setting.
 */
export const useAutoMarkVerificationRead = (mx: MatrixClient): void => {
  const doneRef = useRef<Set<string>>(new Set());

  useEffect(() => {
    const done = doneRef.current;

    const maybeMark = (room: Room) => {
      const { roomId } = room;
      if (done.has(roomId)) return;
      if (room.getMyMembership() !== 'join') return;
      // Only touch rooms the SDK actually counts as notifying...
      if (!roomHaveNotification(room)) return;
      // ...and only when the whole unread span is a completed verification.
      if (!unreadIsOnlyVerification(room, mx.getUserId())) return;

      done.add(roomId);
      markAsRead(mx, roomId, false).catch(() => {
        // Let a later decrypt/sweep retry on transient failure.
        done.delete(roomId);
      });
    };

    // Sweep once on mount (after initial sync some verification tails are already
    // decrypted), then re-check whenever an event decrypts — the count only
    // becomes attributable to the verification request once it's decrypted.
    mx.getRooms().forEach(maybeMark);

    const onDecrypted = (event: MatrixEvent) => {
      const roomId = event.getRoomId();
      const room = roomId ? mx.getRoom(roomId) : null;
      if (room) maybeMark(room);
    };
    mx.on(MatrixEventEvent.Decrypted, onDecrypted);
    return () => {
      mx.removeListener(MatrixEventEvent.Decrypted, onDecrypted);
    };
  }, [mx]);
};
