
import React, { createContext, useContext, useRef, useState, useEffect, useCallback } from "react";
import Peer from "simple-peer";
import { useMatrix } from "../matrix/MatrixProvider.jsx";

const WebRTCContext = createContext(null);

export function useWebRTC() {
  return useContext(WebRTCContext);
}

export function WebRTCProvider({ children }) {
  const [peers, setPeers] = useState([]); // [{ peerId, peer, stream }]
  const [localStream, setLocalStream] = useState(null);
  const [joined, setJoined] = useState(false);
  const peersRef = useRef({});
  const matrix = useMatrix();
  if (!matrix) {
    // Optionally render a fallback or nothing if Matrix context is not available
    return null;
  }
  const { client, user, currentRoomId } = matrix;
  const SIGNAL_EVENT = "org.aethex.voice.signal";
  const VOICE_ROOM = currentRoomId || "!foundation:matrix.org";

  // Helper: Send signal via Matrix event
  const sendSignal = useCallback((to, data) => {
    if (!client || !VOICE_ROOM) return;
    client.sendEvent(VOICE_ROOM, SIGNAL_EVENT, { to, from: user?.userId, data }, "");
  }, [client, VOICE_ROOM, user]);

  // Join a voice channel (start local audio, announce self)
  const joinVoice = async () => {
    if (localStream || !client || !user) return;
    try {
      const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
      setLocalStream(stream);
      setJoined(true);
      // Announce self to others
      client.sendEvent(VOICE_ROOM, SIGNAL_EVENT, { join: true, from: user.userId }, "");
    } catch (err) {
      alert("Could not access microphone: " + err.message);
    }
  };

  // Leave voice channel (close peers, announce leave)
  const leaveVoice = () => {
    if (localStream) {
      localStream.getTracks().forEach(track => track.stop());
      setLocalStream(null);
    }
    Object.values(peersRef.current).forEach(({ peer }) => peer.destroy());
    peersRef.current = {};
    setPeers([]);
    setJoined(false);
    if (client && user) {
      client.sendEvent(VOICE_ROOM, SIGNAL_EVENT, { leave: true, from: user.userId }, "");
    }
  };

  // Handle incoming Matrix signal events
  useEffect(() => {
    if (!client || !user || !VOICE_ROOM) return;
    const handler = (event) => {
      if (event.getType() !== SIGNAL_EVENT) return;
      const { from, to, data, join, leave } = event.getContent();
      if (from === user.userId) return;
      // Handle join: create peer if not exists
      if (join) {
        if (!peersRef.current[from]) {
          const initiator = user.userId > from; // simple deterministic initiator
          const peer = new Peer({ initiator, trickle: false, stream: localStream });
          peer.on("signal", signal => sendSignal(from, signal));
          peer.on("stream", remoteStream => {
            setPeers(p => [...p, { peerId: from, peer, stream: remoteStream }]);
          });
          peer.on("close", () => {
            setPeers(p => p.filter(x => x.peerId !== from));
            delete peersRef.current[from];
          });
          peersRef.current[from] = { peer };
        }
      }
      // Handle leave: remove peer
      if (leave && peersRef.current[from]) {
        peersRef.current[from].peer.destroy();
        delete peersRef.current[from];
        setPeers(p => p.filter(x => x.peerId !== from));
      }
      // Handle signal: pass to peer
      if (data && peersRef.current[from]) {
        peersRef.current[from].peer.signal(data);
      }
    };
    client.on("event", handler);
    return () => client.removeListener("event", handler);
  }, [client, user, VOICE_ROOM, localStream, sendSignal]);

  // Announce self to new joiners
  useEffect(() => {
    if (!joined || !client || !user) return;
    client.sendEvent(VOICE_ROOM, SIGNAL_EVENT, { join: true, from: user.userId }, "");
  }, [joined, client, user, VOICE_ROOM]);

  return (
    <WebRTCContext.Provider value={{ peers, localStream, joined, joinVoice, leaveVoice }}>
      {children}
    </WebRTCContext.Provider>
  );
}
