import { listPeerReadsForMessages, markMessagesRead } from '@chat-app/shared/chat';
import { useCallback, useEffect, useMemo, useState } from 'react';

import { supabase } from './supabase';

// Tracks which of our own messages the peer has read. For groups this would
// return a per-message Map<userId, readAt>; M1 is DM-focused so we just return
// a Set of message ids read by the single peer.
export function useMessageReads(
  messageIds: string[],
  peerUserId: string | undefined,
): { peerReadSet: Set<string>; refresh: () => Promise<void> } {
  const idsKey = useMemo(() => messageIds.join(','), [messageIds]);
  const [peerReadSet, setPeerReadSet] = useState<Set<string>>(new Set());

  const refresh = useCallback(async () => {
    if (!peerUserId || messageIds.length === 0) {
      setPeerReadSet(new Set());
      return;
    }
    try {
      const s = await listPeerReadsForMessages(supabase, messageIds, peerUserId);
      setPeerReadSet(s);
    } catch (err: unknown) {
      console.error('listPeerReadsForMessages failed', err);
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [peerUserId, idsKey]);

  useEffect(() => {
    void refresh();
    if (!peerUserId) return;
    const channel = supabase
      .channel('reads:' + peerUserId)
      .on(
        'postgres_changes',
        {
          event: 'INSERT',
          schema: 'public',
          table: 'message_reads',
          filter: 'user_id=eq.' + peerUserId,
        },
        () => {
          void refresh();
        },
      )
      .subscribe();
    return () => {
      void supabase.removeChannel(channel);
    };
  }, [peerUserId, refresh]);

  return { peerReadSet, refresh };
}

// Mark a batch of messages as read. Caller uses this when they arrive while
// the conversation is actively being viewed.
export async function markRead(messageIds: string[]): Promise<void> {
  await markMessagesRead(supabase, messageIds);
}
