"use client";

import { useEffect, useRef, useState } from "react";
import io from "socket.io-client";
import Peer from "simple-peer";

const socket = io("http://localhost:5001");

export default function VoiceCall() {
  const [stream, setStream] = useState<MediaStream | null>(null);
  const [peer, setPeer] = useState<Peer.Instance | null>(null);
  const [pitchShift, setPitchShift] = useState<number>(1);
  const myAudio = useRef<HTMLAudioElement>(null);
  const otherAudio = useRef<HTMLAudioElement>(null);
  const audioContextRef = useRef<AudioContext | null>(null);
  const sourceNodeRef = useRef<MediaStreamAudioSourceNode | null>(null);
  const pitchNodeRef = useRef<any>(null);

  const applyPitchEffect = (audioStream: MediaStream) => {
    if (!audioContextRef.current) {
      audioContextRef.current = new AudioContext();
    }
    const audioContext = audioContextRef.current;

    // Create source node
    sourceNodeRef.current = audioContext.createMediaStreamSource(audioStream);

    // Create ScriptProcessor for pitch shifting
    const bufferSize = 4096;
    pitchNodeRef.current = audioContext.createScriptProcessor(bufferSize, 1, 1);

    pitchNodeRef.current.onaudioprocess = (
      audioProcessingEvent: AudioProcessingEvent
    ) => {
      const inputBuffer = audioProcessingEvent.inputBuffer;
      const outputBuffer = audioProcessingEvent.outputBuffer;

      for (
        let channel = 0;
        channel < outputBuffer.numberOfChannels;
        channel++
      ) {
        const inputData = inputBuffer.getChannelData(channel);
        const outputData = outputBuffer.getChannelData(channel);

        // Simple pitch shift by resampling
        for (let i = 0; i < outputBuffer.length; i++) {
          const index = Math.floor(i * pitchShift);
          outputData[i] = index < inputBuffer.length ? inputData[index] : 0;
        }
      }
    };

    // Connect nodes
    sourceNodeRef.current.connect(pitchNodeRef.current);
    pitchNodeRef.current.connect(audioContext.destination);

    return new MediaStream([audioStream.getAudioTracks()[0]]);
  };

  useEffect(() => {
    navigator.mediaDevices
      .getUserMedia({
        audio: {
          echoCancellation: true,
          noiseSuppression: true,
          autoGainControl: true,
          sampleRate: 48000,
          channelCount: 2,
        },
      })
      .then((audioStream) => {
        const processedStream = applyPitchEffect(audioStream);
        setStream(processedStream);
        if (myAudio.current) {
          myAudio.current.srcObject = processedStream;
        }
      })
      .catch((err) => console.error("Audio error:", err));

    return () => {
      if (pitchNodeRef.current) {
        pitchNodeRef.current.disconnect();
      }
      if (sourceNodeRef.current) {
        sourceNodeRef.current.disconnect();
      }
      if (audioContextRef.current) {
        audioContextRef.current.close();
      }
    };
  }, []);

  const callUser = () => {
    if (!stream) return;
    const peer = new Peer({
      initiator: true,
      trickle: false,
      stream,
      config: {
        iceServers: [
          { urls: "stun:stun.l.google.com:19302" },
          { urls: "stun:global.stun.twilio.com:3478" },
        ],
      },
    });
    peer.on("signal", (data) => socket.emit("offer", data));
    peer.on("stream", (userStream) => {
      console.log("Received voice stream from peer");
      if (otherAudio.current) {
        otherAudio.current.srcObject = userStream;
        console.log("Successfully set remote audio stream");
      }
    });

    socket.on("answer", (answer) => {
      console.log("Received answer from remote peer");
      peer.signal(answer);
    });
    socket.on("candidate", (candidate) => {
      console.log("Received ICE candidate");
      peer.signal(candidate);
    });

    setPeer(peer);
  };

  const receiveCall = () => {
    if (!stream) return;
    const peer = new Peer({
      initiator: false,
      trickle: false,
      stream,
      config: {
        iceServers: [
          { urls: "stun:stun.l.google.com:19302" },
          { urls: "stun:global.stun.twilio.com:3478" },
        ],
      },
    });

    socket.on("offer", (offer) => {
      console.log("Received call offer");
      peer.signal(offer);
    });

    peer.on("signal", (data) => {
      console.log("Generated answer");
      socket.emit("answer", data);
    });

    peer.on("stream", (userStream) => {
      console.log("Received voice stream from caller");
      if (otherAudio.current) {
        otherAudio.current.srcObject = userStream;
        console.log("Successfully set remote audio stream");
      }
    });

    setPeer(peer);
  };

  return (
    <div>
      <audio ref={myAudio} autoPlay muted />
      <audio ref={otherAudio} autoPlay />
      <button onClick={callUser}>Call</button>
      <button onClick={receiveCall}>Receive Call</button>
      <div>
        <label>
          Pitch Shift:
          <input
            type="range"
            min="0.5"
            max="2"
            step="0.1"
            value={pitchShift}
            onChange={(e) => setPitchShift(Number(e.target.value))}
          />
        </label>
      </div>
    </div>
  );
}
