import { useEffect, useState, useCallback } from 'react';
import { usePusherClient } from '@/lib/pusher-provider';
import type { ChannelMessage } from '@/lib/pusher-client';

interface UseChannelResult {
  /** Current set of humanIds present in the channel */
  presence: string[];
  /** Messages received on this channel (since the hook mounted) */
  messages: ChannelMessage[];
  /** Send a message to the channel */
  sendMessage: (payload: unknown) => void;
}

/**
 * Subscribe to a pusher channel. Manages presence tracking and message delivery.
 * Subscribes on mount, unsubscribes on unmount.
 *
 * @param channelId - The channel to subscribe to, or null to skip.
 */
export function useChannel(channelId: string | null): UseChannelResult {
  const client = usePusherClient();
  const [presence, setPresence] = useState<string[]>([]);
  const [messages, setMessages] = useState<ChannelMessage[]>([]);

  useEffect(() => {
    if (!client || !channelId) return;

    client.subscribe(channelId);

    const onSubscribed = (msg: { presence?: string[] }) => {
      setPresence(msg.presence ?? []);
    };

    const onJoin = (msg: { humanId?: string }) => {
      const humanId = msg.humanId;
      if (!humanId) return;
      setPresence((prev) =>
        prev.includes(humanId) ? prev : [...prev, humanId],
      );
    };

    const onLeave = (msg: { humanId?: string }) => {
      if (msg.humanId) {
        setPresence((prev) => prev.filter((id) => id !== msg.humanId));
      }
    };

    const onMessage = (msg: { humanId?: string; payload?: unknown }) => {
      const humanId = msg.humanId;
      if (!humanId) return;
      setMessages((prev) => [...prev, { humanId, payload: msg.payload }]);
    };

    client.on(channelId, 'subscribed', onSubscribed);
    client.on(channelId, 'join', onJoin);
    client.on(channelId, 'leave', onLeave);
    client.on(channelId, 'message', onMessage);

    return () => {
      client.off(channelId, 'subscribed', onSubscribed);
      client.off(channelId, 'join', onJoin);
      client.off(channelId, 'leave', onLeave);
      client.off(channelId, 'message', onMessage);
      client.unsubscribe(channelId);
      setPresence([]);
      setMessages([]);
    };
  }, [client, channelId]);

  const sendMessage = useCallback(
    (payload: unknown) => {
      if (client && channelId) {
        client?.sendMessage(channelId, payload);
      }
    },
    [client, channelId],
  );

  return { presence, messages, sendMessage };
}
