import { createContext, useContext, useEffect, useRef, useState } from 'react';
import type { RealtimeChannel } from '@supabase/supabase-js';
import { supabase } from '../lib/supabase';

type OnlinePresenceContext = {
  onlineUserIds: Set<string>;
  isOnline: (userId: string) => boolean;
};

export const OnlinePresenceContext = createContext<OnlinePresenceContext>({
  onlineUserIds: new Set(),
  isOnline: () => false,
});

export function useOnlineUsers(): OnlinePresenceContext {
  return useContext(OnlinePresenceContext);
}

let sharedChannel: RealtimeChannel | null = null;
let subscriberCount = 0;
let onlineUserIds: Set<string> = new Set();
const listeners = new Set<(ids: Set<string>) => void>();

function notify() {
  const snapshot = new Set(onlineUserIds);
  listeners.forEach((fn) => fn(snapshot));
}

function ensureChannel(currentUserId: string) {
  if (sharedChannel) {
    console.log('[presence] channel already exists, skip ensure');
    return;
  }

  console.log('[presence] ensureChannel — opening for user', currentUserId);
  const ch = supabase.channel('presence:online', {
    config: { presence: { key: currentUserId } },
  });
  sharedChannel = ch;

  ch
    .on('presence', { event: 'sync' }, () => {
      const state = ch.presenceState();
      const keys = Object.keys(state);
      onlineUserIds = new Set(keys);
      console.log('[presence] sync — online users:', keys.length, keys);
      notify();
    })
    .subscribe(async (status: string) => {
      console.log('[presence] subscribe status:', status);
      if (status === 'SUBSCRIBED') {
        const result = await ch.track({ userId: currentUserId, online_at: new Date().toISOString() });
        console.log('[presence] track result:', result);
      }
    });
}

function teardownChannel() {
  if (!sharedChannel) return;
  sharedChannel.untrack().catch(() => {});
  supabase.removeChannel(sharedChannel);
  sharedChannel = null;
  onlineUserIds = new Set();
  notify();
}

export function untrackSelf() {
  sharedChannel?.untrack().catch(() => {});
}

export function retrackSelf(currentUserId: string) {
  sharedChannel
    ?.track({ userId: currentUserId, online_at: new Date().toISOString() })
    .catch(() => {});
}

export function useOnlinePresenceNode(currentUserId: string | null | undefined) {
  const [ids, setIds] = useState<Set<string>>(new Set(onlineUserIds));

  useEffect(() => {
    if (!currentUserId) return;

    subscriberCount++;
    ensureChannel(currentUserId);

    const listener = (next: Set<string>) => setIds(next);
    listeners.add(listener);

    return () => {
      listeners.delete(listener);
      subscriberCount--;
      if (subscriberCount <= 0) {
        subscriberCount = 0;
        teardownChannel();
      }
    };
  }, [currentUserId]);

  return ids;
}
