<template>
  <!-- 音频/视频通话主容器 -->
  <div class="TUICall-container" v-if="callParticipantInfo?.selfInfo?.status !== CallStatus.IDLE">
    <!-- 顶部菜单栏 -->
    <view class='topBar' v-if="callParticipantInfo?.selfInfo?.status === CallStatus.CONNECTED">
      <view class="call-duration">
        <text>{{ formatDuration(duration) }}</text>
      </view>
    </view>

    <!-- 本地头像遮罩层 -->
    <view @click="!isLocalStreamMain && toggleViewSize()" :class="isLocalStreamMain ? 'big-overlay' : 'small-overlay'"
      v-if="mediaType === CallMediaType.VIDEO && !isCameraOpen">
      <Avatar :avatarStyle="isLocalStreamMain ? bigOverlayAvatarStyle : smallOverlayAvatarStyle"
        :src="callParticipantInfo?.selfInfo.avatarUrl || IMG_DEFAULT_AVATAR" />
      <view :class="isLocalStreamMain ? 'big-overlay-mask' : 'small-overlay-mask'"></view>
    </view>

    <!-- 本地流 -->
    <div
      :class="(mediaType === CallMediaType.AUDIO || !isCameraOpen) ? 'player-audio' : (isLocalStreamMain ? 'big-video' : 'small-video')"
      @click="!isLocalStreamMain && toggleViewSize()">

      <TRTCPusher :key="pusherId" :id="pusherId" v-if="pusherId" />
    </div>

    <!-- 远端头像遮罩层 -->
    <view :class="!isLocalStreamMain ? 'big-overlay' : 'small-overlay'" @click="isLocalStreamMain && toggleViewSize()"
      v-if="mediaType === CallMediaType.AUDIO || (mediaType === CallMediaType.VIDEO && callParticipantInfo?.selfInfo?.status === CallStatus.CONNECTED && !callParticipantInfo?.allParticipants[0]?.isCameraOpened)">
      <Avatar :avatarStyle="!isLocalStreamMain ? bigOverlayAvatarStyle : smallOverlayAvatarStyle"
        :src="callParticipantInfo?.allParticipants[0]?.avatarUrl || IMG_DEFAULT_AVATAR" />
      <view :class="!isLocalStreamMain ? 'big-overlay-mask' : 'small-overlay-mask'"></view>
    </view>

    <!-- 远端流 -->
    <view
      :class="(mediaType === CallMediaType.AUDIO || callParticipantInfo?.selfInfo?.status === CallStatus.CALLING || !callParticipantInfo?.allParticipants[0]?.isCameraOpened) ? 'player-audio' : (!isLocalStreamMain ? 'big-video' : 'small-video')"
      @click="isLocalStreamMain && toggleViewSize()">
      <TRTCPlayer :id="`${callParticipantInfo?.allParticipants[0]?.id}_0`" ref="player"
        :stream-id="`${callParticipantInfo?.allParticipants[0]?.id}_0`" />
    </view>

    <!-- 用户信息 -->
    <view v-if="mediaType === CallMediaType.AUDIO || callParticipantInfo?.selfInfo?.status === CallStatus.CALLING"
      class="voice-invite-message">
      <Avatar :avatarStyle="avatarStyle"
        :src="callParticipantInfo?.allParticipants[0]?.avatarUrl || IMG_DEFAULT_AVATAR" />
      <text class="nick-name">
        {{ callParticipantInfo?.allParticipants[0]?.name || callParticipantInfo?.allParticipants[0]?.id }}
      </text>
    </view>

    <!-- 通话状态提示 -->
    <div class="tips">
      <text v-if="showConnectedTip">已接通</text>
      <div v-if="!showConnectedTip && callParticipantInfo.selfInfo.status !== CallStatus.CONNECTED">
        <text v-if="callParticipantInfo?.selfInfo?.role !== CallRole.CALLER">
          {{ mediaType === CallMediaType.AUDIO ? '邀请你进行语音通话' : '邀请你进行视频通话' }}
        </text>
        <text v-else>等待对方接受</text>
      </div>
    </div>

    <!-- 主叫呼叫阶段按钮 -->
    <view class="footer"
      v-if="callParticipantInfo?.selfInfo?.status === CallStatus.CALLING && callParticipantInfo?.selfInfo?.role === CallRole.CALLER">
      <view class="btn-operate">
        <view class="btn-operate-item">
          <view class="call-operate" style="background-color: #ED4651;" @click="CallerHangupHandler">
            <image v-if="isCallBtnClickable" :src="IMG_HANGUP" mode="aspectFit" />
            <image v-else class="img-loading" :src="IMG_LOADING" mode="aspectFit"></image>
          </view>
          <text>挂断</text>
        </view>
      </view>
    </view>

    <!-- 被叫呼叫阶段按钮 -->
    <view class="footer"
      v-if="callParticipantInfo?.selfInfo?.status === CallStatus.CALLING && callParticipantInfo?.selfInfo?.role !== CallRole.CALLER">
      <view class="btn-operate" style="gap: 40px">
        <view class="btn-operate-item">
          <view class="call-operate" style="background-color: #ED4651;" @click="reject">
            <image :src="IMG_HANGUP" mode="aspectFit" />
          </view>
          <text>挂断</text>
        </view>
        <view class="btn-operate-item">
          <view class="call-operate" style="background-color: #51C271;" @click="acceptHandler">
            <image v-if="isAcceptBtnClickable" :src="IMG_ACCEPT" mode="aspectFit" />
            <image v-else class="img-loading" :src="IMG_LOADING" mode="aspectFit"></image>
          </view>
          <text>接听</text>
        </view>
      </view>
    </view>

    <!-- 语音通话接听阶段按钮 -->
    <view class="footer"
      v-if="mediaType === CallMediaType.AUDIO && callParticipantInfo?.selfInfo?.status === CallStatus.CONNECTED">
      <view class="btn-operate">
        <view class="btn-operate-item" @click="microPhoneHandler">
          <view class="call-operate" :style="buttonBgColor(isMicrophoneOpen)">
            <image :src="isMicrophoneOpen ? IMG_AUDIO_TRUE : IMG_AUDIO_FALSE" mode="aspectFit"></image>
          </view>
          <text>{{ isMicrophoneOpen ? '麦克风已开启' : '麦克风已关闭' }}</text>
        </view>
        <view class="btn-operate-item">
          <view class="call-operate" style="background-color: #ED4651;" @click="hangupHandler">
            <image mode="aspectFit" v-if="isHangupBtnClickable" :src="IMG_HANGUP" />
            <image mode="aspectFit" v-else class="img-loading" :src="IMG_LOADING"></image>
          </view>
          <text>挂断</text>
        </view>
        <view class="btn-operate-item" @click="setAudioRoute">
          <view class="call-operate" :style="buttonBgColor(isSpeakerOpen)">
            <image mode="aspectFit" class="btn-image" :src="isSpeakerOpen ? IMG_SPEAKER_TRUE : IMG_SPEAKER_FALSE">
            </image>
          </view>
          <text>{{ isSpeakerOpen ? '扬声器已开启' : '扬声器已关闭' }}</text>
        </view>
      </view>
    </view>

    <!-- 视频通话接听阶段按钮 -->
    <view class="footer"
      v-if="mediaType === CallMediaType.VIDEO && callParticipantInfo?.selfInfo?.status === CallStatus.CONNECTED">
      <view class="btn-operate">
        <view class="btn-operate-item" @click="microPhoneHandler">
          <view class="call-operate" :style="buttonBgColor(isMicrophoneOpen)">
            <image :src="isMicrophoneOpen ? IMG_AUDIO_TRUE : IMG_AUDIO_FALSE" mode="aspectFit"></image>
          </view>
          <text>{{ isMicrophoneOpen ? '麦克风已开启' : '麦克风已关闭' }}</text>
        </view>
        <view class="btn-operate-item" @click="setAudioRoute">
          <view class="call-operate" :style="buttonBgColor(isSpeakerOpen)">
            <image mode="aspectFit" class="btn-image" :src="isSpeakerOpen ? IMG_SPEAKER_TRUE : IMG_SPEAKER_FALSE">
            </image>
          </view>
          <text>{{ isSpeakerOpen ? '扬声器已开启' : '扬声器已关闭' }}</text>
        </view>
        <view class="btn-operate-item" @click="cameraHandler">
          <view class="call-operate" :style="buttonBgColor(isCameraOpen)">
            <image mode="aspectFit" class="btn-image" :src="isCameraOpen ? IMG_CAMERA_TRUE : IMG_CAMERA_FALSE"></image>
          </view>
          <text>{{ isCameraOpen ? '摄像头已开启' : '摄像头已关闭' }}</text>
        </view>
      </view>
      <view class="btn-operate">
        <view class="btn-operate-item">
          <view class="call-operate" style="background-color: #ED4651;" @click="hangupHandler">
            <image v-if="isHangupBtnClickable" :src="IMG_HANGUP" mode="aspectFit" />
            <image v-else class="img-loading" :src="IMG_LOADING" mode="aspectFit"></image>
          </view>
          <view v-if="isCameraOpen" class="switch-camera">
            <image :src="IMG_SWITCH_CAMERA" @click="switchCamera" mode="aspectFit"/>
          </view>
          <text>挂断</text>
        </view>
      </view>
    </view>
  </div>
</template>

<script lang="ts" setup>
import { ref, watch, computed } from 'vue';
import { onUnload } from '@dcloudio/uni-app'
import Avatar from '../Avatar/Avatar.vue';
import TRTCPusher from '@tencentcloud/trtc-component-uniapp/src/components/TRTCPusher.vue';
import TRTCPlayer from '@tencentcloud/trtc-component-uniapp/src/components/TRTCPlayer.vue';
import IMG_HANGUP from '../../assets/call/hangup.svg';
import IMG_ACCEPT from '../../assets/call/accept.svg';
import IMG_AUDIO_TRUE from '../../assets/call/microphone-open.svg';
import IMG_AUDIO_FALSE from '../../assets/call/microphone-close.svg';
import IMG_SPEAKER_TRUE from '../../assets/call/speaker-open.svg';
import IMG_SPEAKER_FALSE from '../../assets/call/speaker-close.svg';
import IMG_CAMERA_TRUE from '../../assets/call/camera-open.svg';
import IMG_CAMERA_FALSE from '../../assets/call/camera-close.svg';
import IMG_SWITCH_CAMERA from '../../assets/call/switch-camera.svg';
import IMG_DEFAULT_AVATAR from '../../assets/base/default-avatar.png';
import IMG_LOADING from '../../assets/call/loading.png';
import { formatDuration } from '../../utils/index';
import { CallMediaType, AudioPlayBackDevice } from '@trtc/call-engine-lite-wx';
import { CallStatus, CallRole } from '../../constants/call';
import { useCallListState, useCallParticipantState, useDeviceState } from '../../index';

const {
  inviterId,
  mediaType,
  duration,
  pusherId,
  accept,
  reject,
  hangup,
} = useCallListState();
const { callParticipantInfo } = useCallParticipantState();

const { 
  currentAudioRoute,
  openLocalCamera, closeLocalCamera,
  openLocalMicrophone, closeLocalMicrophone,
  switchCamera, setAudioRoute,
} = useDeviceState();

const isCallBtnClickable = ref((inviterId.value || '').length > 0 ? true : false);
const isAcceptBtnClickable = ref(true);
const isHangupBtnClickable = ref(true);
const isLocalStreamMain = ref(mediaType.value === CallMediaType.AUDIO ? false : true);
const isMicrophoneOpen = computed(() => callParticipantInfo?.value.selfInfo?.isMicrophoneOpened);
const isCameraOpen = computed(() => callParticipantInfo?.value.selfInfo?.isCameraOpened);
const isSpeakerOpen = computed(() => currentAudioRoute.value !== AudioPlayBackDevice.EAR);
const showConnectedTip = ref(false);
const bigOverlayAvatarStyle = ref({
  position: 'absolute',
  width: '100%',
  height: '100%',
  objectFit: 'cover',
  zIndex: 1
});

const smallOverlayAvatarStyle = ref({
  position: 'absolute',
  width: '100%',
  height: '100%',
  objectFit: 'cover',
  zIndex: 99
});

const avatarStyle = ref({
  width: '100px',
  height: '100px',
  borderRadius: '12px',
  display: 'block',
  margin: '140px auto 15px'
});

function toggleViewSize() {
  if (mediaType.value === CallMediaType.VIDEO) {
    isLocalStreamMain.value = !isLocalStreamMain.value
  }
}

async function cameraHandler() {
  if (isCameraOpen.value) {
    await closeLocalCamera();
  } else {
    await openLocalCamera();
  }
}

async function microPhoneHandler() {
  if (isMicrophoneOpen.value) {
    await closeLocalMicrophone();
  } else {
    await openLocalMicrophone();
  }
}

async function CallerHangupHandler() {
  try {
    if (!isCallBtnClickable.value) return;

    await hangup();
  } catch (error) {
    isCallBtnClickable.value = true;
  }
}

async function acceptHandler() {
  try {
    if (!isAcceptBtnClickable.value) {
      console.warn(`previous accept is ongoing, please avoid repeat accept`);
      return;
    }
    isAcceptBtnClickable.value = false;
    await accept();
    isAcceptBtnClickable.value = true;
  } catch (error) {
    isAcceptBtnClickable.value = true;
  }
}

async function hangupHandler() {
  try {
    if (!isHangupBtnClickable.value) {
      console.warn(`previous hangup is ongoing, please avoid repeat hangup`);
      return;
    }
    isHangupBtnClickable.value = false;
    await hangup();
    isHangupBtnClickable.value = true;
  } catch (error) {
    isHangupBtnClickable.value = true;
  }
}

const buttonBgColor = computed(() => (isActive: boolean) => {
  return isActive ? { backgroundColor: '#FFFFFF', } : {
    backgroundColor: '#22262E',
    opacity: '0.5'
  };
})

watch(() => callParticipantInfo?.value?.selfInfo, (newObj, oldObj) => {
  const newStatus = newObj?.status;

  if (mediaType.value === CallMediaType.VIDEO) {
    isLocalStreamMain.value = newStatus === CallStatus.CALLING
  }

  if (mediaType.value === CallMediaType.AUDIO) {
    isLocalStreamMain.value = false;
  }

  if (newStatus === CallStatus.CONNECTED && oldObj?.status === CallStatus.CALLING) {
    showConnectedTip.value = true;
    setTimeout(() => {
      showConnectedTip.value = false;
    }, 1000);
  } else {
    showConnectedTip.value = false;
  }

  if (newStatus === CallStatus.IDLE) {
    isHangupBtnClickable.value = false;
    isAcceptBtnClickable.value = true;
    isHangupBtnClickable.value = true;
  }
});

watch(inviterId, (newVal, oldVal) => {
  isCallBtnClickable.value = (newVal || '').length > 0 ? true : false;
});

onUnload(() => {
  const callStatus = callParticipantInfo?.value?.selfInfo?.status;
  const callRole = callParticipantInfo?.value?.selfInfo?.role;

  if (callStatus === CallStatus.IDLE) return;
  // 已接通：页面卸载（返回、切后台、关闭小程序等）不主动 signaling 挂断，医生端可继续面诊；结束请点「挂断」
  if (callStatus === CallStatus.CONNECTED) return;
  if (callStatus === CallStatus.CALLING) {
    if (callRole === CallRole.CALLER) {
      hangup();
    } else {
      reject();
    }
  }
});

</script>

<style scoped lang="scss">
.TUICall-container {
  width: 100vw;
  height: 100vh;
  overflow: hidden;
  position: relative;
  bottom: 0;
  left: 0;
  margin: 0;
  background-color: #ffffff;

  .topBar {
    position: fixed;
    top: 20px;
    left: 50%;
    transform: translateX(-50%);
    display: flex;
    justify-content: center;
    width: 100%;
    z-index: 10;

    .call-duration {
      text-align: center;
      font-family: PingFang SC;
      font-weight: 500;
      font-size: 12px;
      color: #D5E0F2;
    }
  }

  .big-video {
    position: absolute;
    width: 100%;
    height: 100%;
    z-index: 10;
    background-color: black;
  }

  .big-overlay {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;

    .big-overlay-avatar {
      position: absolute;
      width: 100%;
      height: 100%;
      object-fit: cover;
      z-index: 1;
    }

    .big-overlay-mask {
      background-color: rgba(0, 0, 0, 0.5);
      position: absolute;
      width: 100%;
      height: 100%;
      object-fit: cover;
      z-index: 2;
      backdrop-filter: blur(12px);
      -webkit-backdrop-filter: blur(12px);
    }
  }

  .small-video {
    position: absolute;
    right: 16px;
    top: 100px;
    width: 100px;
    height: 178px;
    z-index: 100;
  }

  .small-overlay {
    position: absolute;
    right: 16px;
    top: 100px;
    width: 100px;
    height: 178px;
    z-index: 98;

    .small-overlay-avatar {
      position: absolute;
      width: 100%;
      height: 100%;
      object-fit: cover;
      z-index: 99;
    }

    .small-overlay-mask {
      position: absolute;
      background-color: rgba(0, 0, 0, 0.5);
      width: 100%;
      height: 100%;
      object-fit: cover;
      z-index: 100;
      backdrop-filter: blur(12px);
      -webkit-backdrop-filter: blur(12px);
    }
  }

  .player-audio {
    width: 0;
    height: 0;
  }

  .voice-invite-message {
    position: fixed;
    top: 30%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 100%;
    text-align: center;
    font-family: PingFang SC;
    color: #D5E0F2;
    font-weight: 500;
    z-index: 100;

    .nick-name {
      font-size: 18px;
      text-align: center;
    }
  }

  .tips {
    height: 14px;
    position: fixed;
    top: 70%;
    left: 50%;
    font-size: 14px;
    font-family: PingFang SC;
    transform: translate(-50%, -50%);
    color: #D5E0F2;
    font-weight: 500;
    z-index: 100;
  }

  .footer {
    position: absolute;
    bottom: 5vh;
    width: 100%;
    display: flex;
    justify-content: center;
    align-items: center;
    flex-direction: column;
    font-size: 14px;
    color: #f0e9e9;
    font-weight: 400;
    z-index: 100;

    .btn-operate {
      display: flex;
      flex-direction: initial;
      text-align: center;
      align-items: center;
      justify-content: center;
    }

    .btn-operate-item {
      display: flex;
      flex-direction: column;
      align-items: center;
      margin-bottom: 20px;

      text {
        font-family: PingFang SC;
        font-weight: 400;
        font-size: 12px;
        color: #D5E0F2;
      }

      .switch-camera {
        position: absolute;
        right: 98px;
        width: 32px;
        top: 60%;
        margin-left: 40px;
        height: 32px;

        image {
          width: 100%;
          height: 100%;
        }
      }

      .call-operate {
        width: 60px;
        height: 60px;
        border-radius: 50%;
        margin: 10px 10vw;
        box-sizing: border-box;
        display: flex;
        justify-content: center;
        align-items: center;

        image {
          width: 30px;
          height: 30px;
          background: none;
        }

        .img-loading {
          animation: rotate 1.5s linear infinite;
          width: 30px;
          height: 30px
        }

        @keyframes rotate {
          from {
            transform: rotate(0deg);
          }

          to {
            transform: rotate(360deg);
          }
        }

        text {
          font-family: PingFang SC;
          font-weight: 400;
          font-size: 12px;
          color: #D5E0F2;
        }
      }
    }
  }
}
</style>
