import type { RealtimeChannel } from '@supabase/supabase-js';
import { useEffect, useState } from 'react';

import { supabase } from './supabase';

// Observes the `call-presence:<conversationId>` channel for every conversation
// the user is a member of and returns the first one (if any) that currently
// has peers other than the viewer in the call. Enables a "call is live —
// rejoin" affordance in the sidebar for conversations the viewer never
// joined, mirroring Discord's active-voice indicator.
//
// Uses polling on each channel's `presenceState()` to side-step Supabase's
// topic-based channel dedupe (see useCallPresence.ts).
export function useAnyActiveCall(
  conversationIds: readonly string[],
  myId: string | null,
): { conversationId: string; userIds: string[] } | null {
  const [byConv, setByConv] = useState<Record<string, string[]>>({});

  const key = conversationIds.join(',');

  useEffect(() => {
    if (conversationIds.length === 0) {
      setByConv({});
      return;
    }

    const tracked: Array<{ id: string; ch: RealtimeChannel; owns: boolean }> = [];
    for (const id of conversationIds) {
      const ch = supabase.channel('call-presence:' + id, {
        config: {
          presence: {
            key: 'obs-' + Math.random().toString(36).slice(2, 8),
            enabled: true,
          },
        },
      });
      const owns = ch.state === 'closed';
      if (owns) void ch.subscribe();
      tracked.push({ id, ch, owns });
    }

    const resync = () => {
      setByConv((prev) => {
        const next: Record<string, string[]> = {};
        let changed = false;
        for (const { id, ch } of tracked) {
          const presState = ch.presenceState() as Record<
            string,
            Array<Record<string, unknown>>
          >;
          const ids = new Set<string>();
          for (const list of Object.values(presState)) {
            for (const e of list) {
              const uid = e?.userId;
              if (typeof uid === 'string') ids.add(uid);
            }
          }
          const arr = Array.from(ids).sort();
          next[id] = arr;
          const prevArr = prev[id] ?? [];
          if (prevArr.length !== arr.length || !arr.every((v, i) => v === prevArr[i])) {
            changed = true;
          }
        }
        // Also pick up removed conv ids.
        if (!changed && Object.keys(prev).length !== Object.keys(next).length) {
          changed = true;
        }
        return changed ? next : prev;
      });
    };

    resync();
    const pollId = window.setInterval(resync, 1500);

    return () => {
      window.clearInterval(pollId);
      for (const { ch, owns } of tracked) {
        if (owns) void supabase.removeChannel(ch);
      }
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [key]);

  for (const id of conversationIds) {
    const users = byConv[id] ?? [];
    const others = myId ? users.filter((u) => u !== myId) : users;
    if (others.length > 0) {
      return { conversationId: id, userIds: others };
    }
  }
  return null;
}
