<template>
  <div class="webrtc-voice-container">
    <div class="call-status">
      <h2>{{ callStatus }}</h2>
      <div v-if="myPeerId" class="peer-id">
        {{ $t("voice.myId") }}: {{ myPeerId }}
      </div>
      <button @click="copyPeerId">{{ $t("voice.copy") }}</button>
    </div>
    <div class="delay-time">
      <h2>{{ $t("voice.delay") }}: {{ delayTime + "ms" }}</h2>
    </div>

    <div class="connection-controls" v-if="!isInCall">
      <input
        type="text"
        v-model="remotePeerId"
        :placeholder="$t('voice.enterPeerId')"
        :disabled="isInCall"
      />
      <button
        type="reset"
        class="call-btn start-call"
        @click="startCall"
        :disabled="!remotePeerId || isInCall"
      >
        {{ $t("voice.call") }}
      </button>
    </div>

    <div class="call-controls" v-if="isInCall">
      <button class="call-btn end-call" @click="endCall">
        {{ $t("voice.endCall") }}
      </button>

      <button class="mute-btn" :class="{ muted: isMuted }" @click="toggleMute">
        {{ isMuted ? $t("voice.unmute") : $t("voice.mute") }}
      </button>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted, onUnmounted } from "vue";
import Peer, { type MediaConnection } from "peerjs";

import { useI18n } from "vue-i18n";

const { t } = useI18n();

const myPeerId = ref("");
const remotePeerId = ref("");
const isInCall = ref(false);
const isMuted = ref(false);
const callStatus = ref(t("voice.preparing"));
const localStream = ref<MediaStream | null>(null);
const peer = ref<Peer | null>(null);
const currentCall = ref<MediaConnection | null>(null);
const delayTime = ref(0);
let statsInterval: number | null = null;

const initPeer = () => {
  peer.value = new Peer({
    config: {
      iceServers: [{ urls: "stun:8.134.35.244:3478" }],
    },
  });

  peer.value.on("open", (id) => {
    myPeerId.value = id;
    callStatus.value = t("voice.ready");
  });

  peer.value.on("call", async (call) => {
    try {
      const stream = await navigator.mediaDevices.getUserMedia({
        audio: true,
        video: false,
      });

      localStream.value = stream;
      call.answer(stream);
      handleCall(call);

      isInCall.value = true;
      callStatus.value = t("voice.inCall");
    } catch (error) {
      console.error("获取音频设备失败:", error);
      callStatus.value = t("voice.cannotAccessMic");
    }
  });

  peer.value.on("error", (error) => {
    console.error("PeerJS错误:", error);
    callStatus.value = t("voice.connectionError");
  });
};
const copyPeerId = () => {
  navigator.clipboard.writeText(myPeerId.value);
};
const updateDelayTime = async () => {
  delayTime.value = 0;
  if (currentCall.value && currentCall.value.peerConnection) {
    const stats = await currentCall.value.peerConnection.getStats();
    stats.forEach((report) => {
      if (report.type === "candidate-pair" && report.state === "succeeded") {
        delayTime.value += report.currentRoundTripTime * 1000; //currentRoundTripTime是指往返时间
      }
      if (report.type === "inbound-rtp" && report.kind === "audio") {
        delayTime.value += Math.round(
          report.jitter * 1000 ||
            0 + // 抖动缓冲区变化
              report.playoutDelay ||
            0, // 播放延迟
        );
      }
    });
  }
};
const handleCall = (call: MediaConnection) => {
  currentCall.value = call;

  statsInterval = window.setInterval(updateDelayTime, 1000);

  call.on("stream", (remoteStream) => {
    const audio = new Audio();
    audio.srcObject = remoteStream;
    audio.play();
  });

  call.on("close", () => {
    endCall();
  });
};

const startCall = async () => {
  if (!peer.value || !remotePeerId.value) return;

  try {
    const stream = await navigator.mediaDevices.getUserMedia({
      audio: true,
      video: false,
    });

    localStream.value = stream;
    const call = peer.value.call(remotePeerId.value, stream);
    handleCall(call);

    isInCall.value = true;
    callStatus.value = t("voice.inCall");
  } catch (error) {
    console.error("获取音频设备失败:", error);
    callStatus.value = t("voice.cannotAccessMic");
  }
};

const toggleMute = () => {
  if (localStream.value) {
    const audioTrack = localStream.value.getAudioTracks()[0];
    isMuted.value = !isMuted.value;
    audioTrack.enabled = !isMuted.value;
  }
};

const endCall = () => {
  if (statsInterval) {
    clearInterval(statsInterval);
    statsInterval = null;
  }

  if (currentCall.value) {
    currentCall.value.close();
    currentCall.value = null;
  }

  if (localStream.value) {
    localStream.value.getTracks().forEach((track) => track.stop());
    localStream.value = null;
  }

  isInCall.value = false;
  isMuted.value = false;
  callStatus.value = t("voice.ready");
  delayTime.value = 0;
};

onMounted(() => {
  initPeer();
});

onUnmounted(() => {
  endCall();
  if (peer.value) {
    peer.value.destroy();
  }
});
</script>

<style scoped>
.webrtc-voice-container {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-height: 100vh;
  background-color: #f5f5f5;
  padding: 20px;
}

.call-status {
  margin-bottom: 30px;
  text-align: center;
}

.call-status h2 {
  font-size: 24px;
  color: #333;
  margin-bottom: 10px;
}

.peer-id {
  font-size: 16px;
  color: #666;
  margin-top: 10px;
}

.connection-controls {
  display: flex;
  gap: 10px;
  margin-bottom: 20px;
  justify-content: center;
  align-items: center;
}

.connection-controls input {
  padding: 12px;
  border: 1px solid #ddd;
  border-radius: 25px;
  font-size: 16px;
  width: 200px;
  outline: none;
}

.connection-controls input:focus {
  border-color: #2196f3;
}

.call-controls {
  display: flex;
  gap: 20px;
  justify-content: center;
  align-items: center;
}

button {
  padding: 12px 24px;
  border: none;
  border-radius: 25px;
  font-size: 16px;
  cursor: pointer;
  transition: all 0.3s ease;
}

button:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.call-btn {
  min-width: 120px;
}

.start-call {
  background-color: #4caf50;
  color: white;
}

.end-call {
  background-color: #f44336;
  color: white;
}

.mute-btn {
  background-color: #2196f3;
  color: white;
}

.mute-btn.muted {
  background-color: #9e9e9e;
}

button:hover:not(:disabled) {
  transform: scale(1.05);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
}
</style>
