<script setup lang="ts">
import { onUnmounted, ref, watch } from 'vue'
import Login from '@/components/login.vue'
import Gauge from '@/components/gauge.vue'
import Record from '@/components/record.vue'
import Battery from '@/components/battery.vue'
import Loading from '@/components/loading.vue'

const sleep = (ms: number) => new Promise((res) => setTimeout(res, ms))
const iceServers = [
  {
    urls: [ 'stun:caner.top:3478' ]
  },
  {
    urls: 'turn:caner.top:3478',
    username: 'admin',
    credential: '123456'
  }
]
const Peer = ref(null as null | RTCPeerConnection | undefined)
const isLogin = ref(false)
const remoteVideo = ref()
const showLoading = ref(true)
const winMaxOrMin = ref(false)
const micState = ref(false)
const audioState = ref(false)
const audioStateNum = ref(0)
const warnAudio = ref(false)
const quantity = ref(0)
const error = ref('')
const conctrlData = ref({
  v0: 128, v1: 128, v2: 128, v3: 128
})
const conctrlAnimation = ref(0)
const conctrlGrears = ref(false)
const conctrlNum = ref(0)
const SpeedValue = ref(0)

// 方向盘数据
function onContrlData() {
  if (showLoading.value) return
  window.$electron.send('sendMqtt', { type: 'conctrl', conctrl: { ...conctrlData.value } })
  conctrlAnimation.value = requestAnimationFrame(onContrlData)
}

// 关闭
function close(err?: string) {
  if (Peer.value) Peer.value?.close()
  if (remoteVideo.value) remoteVideo.value.srcObject = null
  isLogin.value = false
  showLoading.value = false
  error.value = err || ''
  Peer.value = null
  audioStateNum.value = 0
  quantity.value = 0
  cancelAnimationFrame(conctrlAnimation.value)
  console.log('退出')
}

// 初始化rtc
function initRTC() {
  try {
    Peer.value = new RTCPeerConnection({
      iceServers,
      bundlePolicy: 'max-bundle'
    })

    // listen state
    Peer.value.onicegatheringstatechange = () => {
      console.log('GatheringState: ', Peer.value?.iceGatheringState)
      if (Peer.value?.iceGatheringState === 'complete') {
        const answer = Peer.value.localDescription
        window.$electron.send('sendMqtt', answer)
      }
    }

    // listen track
    Peer.value.ontrack = async (evt) => {
      console.log('track', evt)
      remoteVideo.value.srcObject = evt.streams[0]
    }

    // listen changestate·
    Peer.value.oniceconnectionstatechange = async () => {
      const state = Peer.value?.iceConnectionState
      console.log('ICE状态', state)
      if (
        state === 'failed'
        || state === 'disconnected'
        || state === 'closed'
      ) {
        close('P2P通信失败')
      }

      // ICE连接成功
      if (state === 'connected') {
        await sleep(3000)
        showLoading.value = false
        onContrlData()
      }
    }
    console.log('rtc 初始化成功')
  } catch (error) {
    close('webrtc初始化失败')
  }
}

// 登录
async function login(data: { name: string, roomID: string }) {
  window.$electron.send('loginMqtt', { room: data.roomID, name: data.name })
}

// 档位计算
function countContrlData(v: number) {
  // 转10进制
  const num = parseInt(v.toString(), 10)
  if (conctrlNum.value % 2) {
    // 倒档
    return Math.floor(num / 2)
  }
  // 前进
  return Math.floor(((128 - (num / 2)) + 128))
}

// 发送语音
function sendAudio(blob: Blob) {
  window.$electron.send('sendMqtt', { type: 'Meadia', Meadia: blob })
}

// mqtt
window.$electron.on('message', async (msg: any) => {
  switch (msg.type) {
    case 'connect':
      console.log('连接成功')
      isLogin.value = true
      showLoading.value = true
      break
    case 'disconnect':
      close('服务器连接失败')
      break
    case 'join':
      window.$electron.send('sendMqtt', { type: 'startRTC' })
      console.log('开始rtc')

      initRTC()
      break
    case 'leave':
      close('对方断开连接')

      break
    case 'offer':
      {
        await Peer.value?.setRemoteDescription(msg)
        const answerd = await Peer.value?.createAnswer()
        await Peer.value?.setLocalDescription(answerd)
      }
      break
    case 'power':
      quantity.value = msg.power
      console.log('电量')

      break
    case 'speed':
      SpeedValue.value = Math.floor(msg.data)
      console.log('速度')

      break
    case 'contrl':
      {
        const db = msg.content
        // 倒档 ｜ 前进 =>右拨片
        conctrlGrears.value = db[6] === 2
        // 鸣笛 =>回车
        warnAudio.value = !!db[54]
        // 录音 =>左拨片
        micState.value = db[6] === 1
        // 静音 =>L3
        audioState.value = db[6] === 64
        // 控制
        conctrlData.value = {
          v0: 128,
          v1: 128,
          v2: parseInt(db[44].toString(), 10), // 方向盘
          v3: countContrlData(db[46]) // 油门
        }
      }
      console.log('遥控数据', conctrlData.value)
      break
    default:
      break
  }
})

// 窗口事件
function titleEvent(type: string) {
  if (type === 'maxWin') winMaxOrMin.value = !winMaxOrMin.value
  if (type === 'loginOut') {
    close()
    window.$electron.send('closeMqtt')
  } else {
    window.$electron?.send(type, winMaxOrMin.value)
  }
}

// 监听按钮状态
watch([ audioState, warnAudio, conctrlGrears ], () => {
  if (showLoading.value) return
  if (audioState.value) {
    audioStateNum.value++
    window.$electron.send('sendMqtt', { type: 'contrlAudio', contrlAudio: !!(audioStateNum.value % 2) })
  }
  if (conctrlGrears.value) {
    conctrlNum.value++
  }
  if (warnAudio.value) window.$electron.send('sendMqtt', { type: 'warnAudio', contrlAudio: !!(audioStateNum.value % 2) })
})

onUnmounted(() => close())

// 关闭loadingwin
window.$electron.send('close-loading')
</script>
<template>
  <template v-if="isLogin">
    <video
      ref="remoteVideo"
      autoplay
      playsinline
    />
    <div class="marke">
      <div class="marke-left">
        <!-- 音频状态 -->
        <Record
          class="marke-audio"
          :size="25"
          :audio-state="micState"
          @callBack="sendAudio"
        />
        <!-- 喇叭状态 -->
        <Icon
          name="audio"
          :size="25"
          :color="(!!(audioStateNum % 2)) ? '#00CED1' : 'rgba(0, 0, 0, 0.3)'"
        />
        <!-- 电量状态 -->
        <Battery :quantity="quantity" />
      </div>
      <div class="marke-right">
        <Icon
          name="min"
          :size="20"
          color="#fff"
          @click="titleEvent('minWin')"
        />
        <Icon
          :name="winMaxOrMin ? 'max' : 'maxMin'"
          :size="20"
          color="#fff"
          @click="titleEvent('maxWin')"
        />
        <Icon
          name="close"
          :size="20"
          color="#fff"
          @click="titleEvent('loginOut')"
        />
      </div>
    </div>
    <!-- 码数 -->
    <div class="gauge">
      <Gauge
        :value="SpeedValue"
        :gears="conctrlNum % 2 ? '倒档' : '前进'"
      />
    </div>
    <Loading v-if="showLoading" />
  </template>
  <Login
    v-else
    v-model="error"
    @loginBack="login"
  />
</template>
<style scoped lang="scss">
video {
  background: black;
  object-fit: fill;
  font-size: 0;
}

.marke {
  position: fixed;
  top: 0;
  left: 0;
  width: available;
  width: -webkit-fill-available;
  height: 0.35rem;
  z-index: 1;
  background: #666666;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  overflow: hidden;
  border-top-left-radius: 20px;
  border-top-right-radius: 20px;
  padding-left: 1.5rem;

  &>div {
    display: flex;
    align-items: center;
  }

  &-left {
    justify-content: center;
    flex: 1;
    -webkit-app-region: drag;

    &>* {
      margin: 0 0.18rem;
    }
  }

  &-right {
    display: flex;
    align-items: center;
    margin-right: 0.15rem;

    &>* {
      cursor: pointer;

      &:not(:first-child) {
        margin-left: 0.15rem;

      }
    }
  }
}

.gauge {
  position: fixed;
  bottom: 0;
  left: 50%;
  transform: translate(-50%, 0);
  width: 3rem;
  height: 1.65rem;
  z-index: 9;
}

/* 隐藏滚动条 */
::-webkit-scrollbar {
  width: 0 !important;
  display: none;
}
</style>
