<template>
  <div class="flex-col gap-16 wh-full">
    <el-button type="primary" @click="onBack" class="w-150px">
      <i class="i-line-md:arrow-left"></i>返回站点数据
    </el-button>
    <EdfsWrap title="设备列表" class="flex-1" useScrollBar>
      <template #title-right v-if="isTransfer">
        <template v-if="isBatchTransfer">
          <el-button type="primary" @click="onBatchSave"> 确定迁移 </el-button>
          <el-button type="info" @click="onBatchCancel"> 取消 </el-button>
        </template>
        <template v-else>
          <el-button type="primary" @click="onBatchTransfer"> 批量迁移 </el-button>
        </template>
      </template>
      <div class="device-list-wrap">
        <el-checkbox-group v-model="onlineDeviceCheckList">
          <div class="device-item" v-for="item in devices">
            <div class="device-item-header">
              <div class="flex items-center">
                <el-checkbox :value="item.sn" v-if="isBatchTransfer">
                  <div>设备ID: {{ item.sn }}</div>
                </el-checkbox>
                <div v-else>
                  <div>设备ID: {{ item.sn }}</div>
                </div>
              </div>

              <div class="flex items-center gap-col-2">
                <el-tooltip
                  content="数据迁移"
                  v-if="isTransfer && item.status === '在线'"
                >
                  <i
                    class="i-line-md:cloud-alt-upload-loop :hover:color-[#8ACE6A] color-[#4B9E5F] cursor-pointer text-20px"
                    @click="onTransfer(item as IOnlineDevice)"
                  ></i>
                </el-tooltip>
                <el-tooltip content="详情">
                  <div
                    class="i-material-symbols:info-outline :hover:color-[#8ACE6A] color-[#4B9E5F] cursor-pointer text-20px"
                    @click="onDeviceDetails(item)"
                  ></div>
                </el-tooltip>
              </div>
            </div>

            <div class="device-item-body">
              <template v-if="isTransfer">
                <template v-for="key in Object.keys(onlineDeviceMap)">
                  <div class="info-item" v-if="isTransfer && key === 'status'">
                    <div>{{ onlineDeviceMap.status }}:</div>
                    <el-tag :type="item.status === '在线' ? 'success' : 'danger'">
                      {{ item.status }}
                    </el-tag>
                  </div>
                  <div class="info-item" v-else>
                    <div>{{ onlineDeviceMap[key as keyof typeof onlineDeviceMap] }}:</div>
                    <div>{{ item[key] }}</div>
                  </div>
                </template>
              </template>
              <template v-else>
                <template v-for="key in Object.keys(offlineDeviceMap)">
                  <div class="info-item" v-if="key === 'create_time'">
                    <div>
                      {{ offlineDeviceMap[key as keyof typeof offlineDeviceMap] }}:
                    </div>
                    <div>{{ dayjs(item[key]).format('YYYY-MM-DD HH:mm:ss') }}</div>
                  </div>
                  <div class="info-item" v-else>
                    <div>
                      {{ offlineDeviceMap[key as keyof typeof offlineDeviceMap] }}:
                    </div>
                    <div>{{ item[key] }}</div>
                  </div>
                </template>
              </template>
            </div>
          </div>
        </el-checkbox-group>
      </div>
    </EdfsWrap>
    <EdfsWrap title="迁移进度" class="transfer-wrap h-[42%]" v-if="isShowTransfer">
      <div class="flex-col gap-col-10 wh-full">
        <div class="flex items-center gap-col-1">
          <div class="flex-1 flex items-center">
            <el-progress
              :percentage="100"
              class="flex-1"
              :stroke-width="18"
              :text-inside="true"
              :status="
                ['progress', 'success', undefined].includes(transferStatus)
                  ? 'success'
                  : 'exception'
              "
            >
              {{
                transferStatusMap[transferStatus as keyof typeof transferStatusMap] ?? ''
              }}
            </el-progress>
          </div>
          <el-button
            v-if="transferStatus === 'progress'"
            type="primary"
            @click="onStopTransfer"
            >停止迁移</el-button
          >
        </div>
        <div class="transfer-log-wrap">
          <div class="text-16px font-500">迁移日志</div>
          <el-scrollbar class="h-full">
            <div
              v-for="i in curTransferLog"
              :class="i.status === 'failed' ? 'text-red-500' : ''"
              class="text-gray-600"
            >
              {{ i.msg }}
            </div>
          </el-scrollbar>
        </div>
      </div>
    </EdfsWrap>
  </div>

  <TransferDlg
    ref="transferDlgRef"
    @on-save="onSave"
    :is-batch-transfer="isBatchTransfer"
  />
  <DeviceDrawer
    v-model="isShowDetails"
    ref="deviceDrawerRef"
    :siteInfo="siteInfo"
    :is-transfer="isTransfer"
  />
</template>

<script setup lang="ts">
import dayjs from 'dayjs'

import TransferDlg from './components/transferDlg.vue'
import ZMQWorker from '@/composables/useZMQJsonWorker'
import {
  getPubInitData,
  type ManualAction,
  type PublishMsg,
  type PubMsgData,
  type TimeoutMsg,
  type ZmqStatus,
} from '@/utils/zmq'
import { useTransferDataStore } from '@/stores/transferData'
import { storeToRefs } from 'pinia'
import type { IOfflineDevice, IOnlineDevice } from './type'
import { useMessage } from '@/composables/useMessage'
import { getDeviceList, type ISiteList } from '@/api/module/transfer'
import DeviceDrawer from './components/deviceDrawer.vue'
import { getTransferTopic, postTransferTopic } from './utils'
const transferDlgRef = ref<typeof TransferDlg>()
const router = useRouter()
const route = useRoute()
const siteInfo = ref<ISiteList>(
  route.query.site ? JSON.parse(route.query.site as string) : null
)
const type = ref<'export' | 'details'>(route.query.type as 'export' | 'details')

const isTransfer = computed(() => type.value === 'export')

const isShowTransfer = computed(() => isTransfer.value && !!curTransferLog.value.length)

const message = useMessage()

const worker = ZMQWorker.getInstance()

const zmqStatus = inject<Ref<ZmqStatus>>('zmqStatus')!
const transferDataStore = useTransferDataStore()
const { devicesMap } = storeToRefs(transferDataStore)

const transferStatusMap = {
  progress: '迁移中',
  success: '迁移成功',
  failed: '迁移失败',
  timeout: '迁移超时',
}

const pubIdWithDevice = new Map<string, { device: IOnlineDevice; action: ManualAction }>()

const curTransferLog = ref<
  { msg: string; host: string; status: 'success' | 'padding' | 'failed' }[]
>([])

const transferStatus = ref<'progress' | 'success' | 'failed' | 'timeout' | undefined>()

const devices = computed(() => {
  return isTransfer.value ? Array.from(devicesMap.value.values()) : deviceList.value
}) as Ref<any[]>

function onSave(msg: PublishMsg<'export'>, device: IOnlineDevice) {
  curTransferLog.value = []
  worker.publish(postTransferTopic, msg, true, zmqTimeoutCb)
  pubIdWithDevice.set(msg.id, { device, action: 'export' })
  worker.subscribe(getTransferTopic, zmqExportCb, msg.id)
  if (isBatchTransfer.value) {
    onBatchCancel()
  }
}

const statusMap = {
  200: 'success',
  1002: 'padding',
  1003: 'failed',
}

function zmqExportCb(msg: PubMsgData) {
  const { feedback, result, id } = msg
  if (feedback && feedback[0]) {
    const status = feedback[1]
      ? (statusMap[feedback[1] as keyof typeof statusMap] as
          | 'success'
          | 'padding'
          | 'failed')
      : 'failed'
    curTransferLog.value.push({
      msg: `主机【${feedback[0]}】: ${feedback[1]}`,
      host: feedback[0],
      status,
    })
  }
  // 找到 status 为 failed 的
  transferStatus.value = 'progress'
  if (result !== 'progress') {
    const curMsgInfo = pubIdWithDevice.get(id)!
    if (!curMsgInfo) return

    const { device, action } = curMsgInfo
    if (device) {
      if (result === 'success') {
        const res = setTransferStatus()
        if (res === 0) {
          message.success(`迁移成功`)
          transferStatus.value = 'success'
        } else {
          message.error(`迁移失败,请检查迁移日志`)
          transferStatus.value = 'failed'
        }
      } else if (['failed', 'failure'].includes(result)) {
        message.error(`迁移失败`)
        transferStatus.value = 'failed'
      }
      pubIdWithDevice.delete(msg.id)
    }
  }
}

function setTransferStatus() {
  const failed = curTransferLog.value.filter(i => i.status === 'failed')
  for (const f of failed) {
    curTransferLog.value.forEach(j => {
      if (f.host === j.host) {
        j.status = 'failed'
      }
    })
  }
  return failed.length
}

function onStopTransfer() {
  message.confirm('是否确认停止迁移?').then(() => {
    const msg = getPubInitData<'cancel'>('cancel', [], 'no')
    worker.publish(postTransferTopic, msg)
    message.success('迁移已取消')
    clearTransferData()
  })
}

function clearTransferData() {
  curTransferLog.value = []
  transferStatus.value = undefined
  pubIdWithDevice.clear()
}

function zmqTimeoutCb(msg: TimeoutMsg) {
  const { device, action } = pubIdWithDevice.get(msg.timeoutId)!
  if (device && action === 'export') {
    message.error(`迁移超时,请重新稍后尝试`)
    pubIdWithDevice.delete(msg.timeoutId)
  }
}

const onlineDeviceMap: Record<
  keyof Omit<IOnlineDevice, 'lastUpdated' | 'sn' | 'isChecked'>,
  string
> = {
  status: '状态',
  stationName: '站点名称',
  clientIp: '客户端IP',
  footprint: '数据占用空间',
}
const offlineDeviceMap: Record<
  keyof Pick<IOfflineDevice, 'stationName' | 'db' | 'create_time'>,
  string
> = {
  stationName: '站点名称',
  db: '数据库',
  create_time: '创建时间',
}

const onlineDeviceCheckList = ref<string[]>([])

const isBatchTransfer = ref(false)
function onBatchTransfer() {
  isBatchTransfer.value = true
}

function onBatchSave() {
  if (!onlineDeviceCheckList.value.length) {
    message.error('请选择要迁移的设备')
    return
  }
  const checkList = onlineDeviceCheckList.value.map(sn => {
    return devicesMap.value.get(sn)
  })

  const clientIpList = checkList
    .map(item => item?.clientIp)
    .filter(Boolean)
    .join(',')
  const pathList = checkList
    .map(item => `${item?.stationName}/${item?.sn}`)
    .filter(Boolean)
    .join(',')

  transferDlgRef.value?.open(checkList[0], clientIpList, pathList)
}

function onBatchCancel() {
  isBatchTransfer.value = false
  onlineDeviceCheckList.value = []
}
function onTransfer(item: IOnlineDevice) {
  transferDlgRef.value?.open(item)
}

function onBack() {
  router.push('/station')
}

// 监听页面刷新
window.onbeforeunload = function () {
  stop()
}

onBeforeRouteLeave(async (to, from, next) => {
  if (transferStatus.value === 'progress') {
    try {
      await message.confirm('当前迁移尚未完成，是否确认离开？')
      window.location.href = to.fullPath
    } catch (error) {
      next(false)
    }
  } else {
    next()
  }
})

const deviceList = ref<IOfflineDevice[]>()

async function loadDeviceList() {
  const res = await getDeviceList(siteInfo.value.id)
  if (res.code === 200 || res.code === 0) {
    deviceList.value = res.data
  }
}

onMounted(() => {
  if (!isTransfer.value) {
    loadDeviceList()
  }
})

const isShowDetails = ref(false)
const deviceDrawerRef = ref<typeof DeviceDrawer>()
function onDeviceDetails(item: IOfflineDevice) {
  deviceDrawerRef.value?.openFullScreen()
  deviceDrawerRef.value?.open(item)
}
</script>

<style scoped lang="scss">
.transfer-log-wrap {
  margin-top: 10px;
  height: calc(100% - 30px);
  @apply border-radius-8px bg-[#F9FAFB] p-10;
  :deep(.el-scrollbar) {
    height: calc(100% - 20px);
  }
}
.device-list-wrap {
  @apply wh-full;
  :deep(.el-checkbox-group) {
    @apply wh-full flex flex-wrap gap-col-6 gap-row-4;
  }
  :deep(.el-checkbox__inner) {
    width: 18px;
    height: 18px;
    &::after {
      left: 6px;
      top: 3px;
    }
  }
  :deep(.el-checkbox__label) {
    @apply text-14px font-500 text-[#313131];
  }
  :deep(.el-checkbox__input.is-checked + .el-checkbox__label) {
    color: var(--el-color-primary);
  }
  .device-item {
    @apply w-289 h-160 border border-solid border-[#E0E0E0] rounded-8px p-x-14 p-y-10 flex-col;
    .device-item-header {
      @apply w-full text-black text-16px font-500 flex items-center justify-between;
      .info {
        font-size: 14px;
        color: #f1bf63;
        cursor: pointer;
        text-decoration: underline;
        &:hover {
          color: #8ace6a;
        }
      }
    }
    .device-item-body {
      @apply flex-1 flex-col m-t-10 color-[#6C727F] text-14px;
      .info-item {
        @apply flex-1 flex items-center gap-col-2;
      }
    }
  }
}
</style>
