import {
  joinSignalingChannel,
  sendSignal,
  ICE_SERVERS,
  type SignalMessage,
} from './signaling';
import type { RealtimeChannel } from '@supabase/supabase-js';

export interface ViewerHandle {
  stop: () => Promise<void>;
}

/**
 * Connects to a broadcaster's room and renders the incoming stream into the given <video>.
 */
export async function joinAsViewer(
  code: string,
  videoEl: HTMLVideoElement,
  onState: (s: 'connecting' | 'waiting' | 'live' | 'error', detail?: string) => void,
): Promise<ViewerHandle> {
  const viewerId = crypto.randomUUID();
  let pc: RTCPeerConnection | null = null;
  let channel: RealtimeChannel | null = null;

  onState('connecting');

  const handleMessage = async (msg: SignalMessage) => {
    if (msg.type === 'offer' && msg.viewerId === viewerId) {
      pc = new RTCPeerConnection({ iceServers: ICE_SERVERS });

      pc.ontrack = (ev) => {
        videoEl.srcObject = ev.streams[0];
        videoEl.play().catch(() => {/* autoplay may need user gesture */});
        onState('live');
      };

      pc.onicecandidate = (ev) => {
        if (ev.candidate && channel) {
          sendSignal(channel, {
            type: 'ice',
            viewerId,
            from: 'viewer',
            candidate: ev.candidate.toJSON(),
          });
        }
      };

      pc.onconnectionstatechange = () => {
        if (pc && ['failed', 'disconnected'].includes(pc.connectionState)) {
          onState('error', 'Conexão perdida');
        }
      };

      await pc.setRemoteDescription(msg.sdp);
      const answer = await pc.createAnswer();
      await pc.setLocalDescription(answer);
      if (channel) sendSignal(channel, { type: 'answer', viewerId, sdp: answer });
    } else if (msg.type === 'ice' && msg.viewerId === viewerId && msg.from === 'broadcaster') {
      if (pc) {
        try {
          await pc.addIceCandidate(msg.candidate);
        } catch (e) {
          console.warn('[viewer] addIceCandidate failed', e);
        }
      }
    }
  };

  channel = joinSignalingChannel(code, handleMessage);

  // Wait a tick for subscribe, then announce join
  setTimeout(() => {
    if (channel) {
      sendSignal(channel, { type: 'viewer-join', viewerId });
      onState('waiting');
    }
  }, 600);

  const stop = async () => {
    if (channel) {
      try { sendSignal(channel, { type: 'viewer-leave', viewerId }); } catch {}
      const { supabase } = await import('@/integrations/supabase/client');
      await supabase.removeChannel(channel);
    }
    if (pc) pc.close();
  };

  return { stop };
}
