<template>
  <div class="fault-rule-drawer">
    <el-drawer v-model="isShowDrawer" :title="title" direction="rtl" size="100%"
               modal-class="model-dev-opn"
               :before-close="handleBeforeClose" @opened="onDrawerOpened">
      <main class="wh-full flex">
        <EdfsWrap title="点位组" isCollapse :collapsed="collapsed" @collapse="onCollapse"
                  :style="{width: `${collapsed ? 0 : 600}px`}">
          <PointGroupTree
            v-if="isShowDrawer"
            :data="pointGroup"
            @device-select="onGroupChange"
            :groupChangeLoading="groupChangeLoading"
            @onchangePoints="onchangePoints"
            :pointList="pointList"
            :loadingPoints="loadingPoints"
            :isTransfer="props.isTransfer"
            :siteInfo="props.siteInfo"
            ref="pointGroupTreeRef"/>
        </EdfsWrap>
        <div class="flex-1 p-4 h-full overflow-hidden relative" v-loading="loading"
             element-loading-text="数据加载中请耐心等待..."
        >
          <div
            class="absolute inset-0 z-[99] flex items-center justify-center bg-white/80 backdrop-blur-sm"
            v-if="isFetching"
          >
            <div class="w-full max-w-[600px] space-y-10 p-6">
              <div
                v-for="deviceInfo in pointInfoData"
                :key="deviceInfo.id"
                class="space-y-3 text-center bg-white/90 p-5 rounded-xl shadow"
              >
                <div class="font-semibold text-gray-700 text-lg">
                  {{ chartGroupMap?.get(deviceInfo.id)?.cnName }} 数据加载中…
                </div>

                <el-progress
                  :text-inside="true"
                  :stroke-width="20"
                  :percentage="deviceInfo.progress"
                />

                <div class="text-gray-600 text-base">已查询
                  <span class="text-green-600 font-semibold">
                    {{ deviceInfo.fetchLimit }}
                  </span>/<span class="text-blue-600 font-semibold">{{
                      deviceInfo.total
                    }}</span>，剩余<span
                    class="text-red-500 font-semibold">{{
                      deviceInfo.total - deviceInfo.fetchLimit
                    }}</span>
                </div>
              </div>
            </div>
          </div>

          <div class="flex w-full items-center gap-16">
            <div class="w-400px">
              <el-date-picker
                v-model="time"
                type="datetimerange"
                value-format="YYYY-MM-DD HH:mm:ss"
                range-separator="到"
                :default-value="getBeforeMonth"
                start-placeholder="开始时间"
                end-placeholder="结束时间"
                :disabled-date="disabledDate"
              />
            </div>
            <el-button type="primary" @click="loadChardData2">查询数据</el-button>
            查询最近
            <el-input-number :key="refreshKey" v-model="num" :min="1" :max="diffHours"
                             @input="handleInput"/>
            小时
          </div>
          <NewDataChart v-if="isShowChart" :chart-datas="chartData" :legends="legends"
                        :axis-data="Array.from(axisData)" ref="chartRef"/>
        </div>
      </main>
    </el-drawer>
  </div>
</template>

<script setup lang="ts">
import NewDataChart from '../../component/newDataChart.vue'
import PointGroupTree from './PointGroupTree.vue'
import type { IMyPoint, IOfflineDevice, IOnlineDevice } from '../../type'
import {
  getDeviceDetails,
  getPointGroup,
  getPoints,
  type IGetDeviceDataParams,
  type IPointGroupOV,
  type IPointGroupParams,
  type IPointsParams,
  type ISite,
} from '@/api/module/transfer'
import { useMessage } from '@/composables/useMessage'
import dayjs from 'dayjs'
import EdfsWrap from "@/components/Edfs-wrap.vue";
import { bms_cellRewriteName } from "@/views/stationData/utils";
import { debounce } from 'lodash-es'
import {
  type DeviceFetchInfo,
  useFetcher
} from "@/views/stationData/transfer/components/useFetcher";

type ChartParamsMap = {
  name: string
  columns: IMyPoint[]
}

const time = ref<[string, string]>()

const env = import.meta.env

const num = ref<number>()
const diffHours = ref<number>()
const refreshKey = ref(0)

const handleInput = debounce(async (val: number) => {
  if (diffHours.value && val > diffHours.value) {
    num.value = diffHours.value
    refreshKey.value++
    await nextTick()
  } else if (val < 1) {
    num.value = 1
    refreshKey.value++
    await nextTick()
  } else {
    num.value = val
  }

  const device = curDevice.value as IOfflineDevice
  const endTime =
    device.end_time ?
      dayjs(device.end_time).valueOf() : dayjs().valueOf()

  const startTime = dayjs(endTime).subtract(num.value, 'hour').valueOf()
  time.value = [dayjs(startTime).format('YYYY-MM-DD HH:mm:ss'), dayjs(endTime).format('YYYY-MM-DD HH:mm:ss')]
}, 300)


const isShowDrawer = defineModel<boolean>()
const title = computed(() =>
  (
    props.isTransfer ?
      '数据详情' : env.VITE_APP_ENV === 'local'
        ? `已导出数据详情` : '已导入数据详情'
  )
)
const message = useMessage()

const pointGroupTreeRef = ref<InstanceType<typeof PointGroupTree>>()
const props = defineProps<{
  siteInfo: ISite | null
  isTransfer: boolean
}>()

const emit = defineEmits(['on-save'])

const pointList = ref<IMyPoint[]>([])

const curDevice = ref<IOfflineDevice | IOnlineDevice>()

async function open(device: IOfflineDevice | IOnlineDevice) {
  curDevice.value = device
  onCollapse(false)
  await loadPointGroup()
    .then(async () => {
      await loadDeviceDetails()
    })
    .catch(() => {
      message.error('获取点位组数据失败')
      fullscreenLoading.value?.close()
    })
  const deviceOff = curDevice.value as IOfflineDevice
  if (!deviceOff.start_time || !deviceOff.end_time) {
    diffHours.value = 168 // 默认一周时间
    return
  }
  const start = dayjs(deviceOff.start_time)
  const end = dayjs(deviceOff.end_time)
  diffHours.value = end.diff(start, "hour") + 1;
}


const loadingPoints = ref(false)

async function loadPoints() {
  if (!curGroup.value?.type) {
    message.error('请先选择点位组')
    return
  }
  const params: IPointsParams = {
    type: curGroup.value.type,
  }
  if (props.isTransfer) {
    const onlineDevice = curDevice.value as IOnlineDevice
    params.isLocal = false
    params.host = onlineDevice.clientIp
  } else {
    const offlineDevice = curDevice.value as IOfflineDevice
    params.sn = offlineDevice.sn
    params.site = props.siteInfo!.name
    params.isLocal = true
  }
  loadingPoints.value = true
  const res = await getPoints(params)
  if (res.code === 0) {
    const data = Array.isArray(res?.data) ? res.data : []
    pointList.value = data.map((i: any) => ({
      label: i.cnName,
      addr: i.addr,
      unit: i.unit || '',
      parentName: curGroupName.value,
    }))
  }
  loadingPoints.value = false
  return res
}

async function loadDeviceDetails() {
  if (!fullscreenLoading.value) {
    openFullScreen()
  }

  const pointsRes = await loadPoints()
  if (!pointsRes || pointsRes.code !== 0) {
    message.error('获取点位数据失败')
    fullscreenLoading.value?.close()
    return
  }
  isShowDrawer.value = true
  groupChangeLoading.value = false
  fullscreenLoading.value?.close()
}

const chartData = reactive(new Map<string, any[]>())
const axisData = new Set<string>()
const legends = ref<{ addr: string; label: string, unit: string }[]>([])

const loadingChart = ref(false)
const loading = ref(false)

async function loadPointChartData(params: IGetDeviceDataParams, abort?: AbortController) {
  return await getDeviceDetails(params, abort)
}

function buildOptions(groupId: string): Omit<IGetDeviceDataParams, 'limit' | 'offset'> {
  const timeArr = time.value as [string, string]
  const currentGroup = chartParamsMap.get(groupId)
  if (!currentGroup) {
    return {} as Omit<IGetDeviceDataParams, 'limit' | 'offset'>
  }
  const options: Omit<IGetDeviceDataParams, 'limit' | 'offset'> = {
    columns: ['ts', ...currentGroup.columns.map(column => column.addr)],
    name: groupId,
    startTime: timeArr[0],
    endTime: timeArr[1],
    isLocal: !props.isTransfer,
    host: props.isTransfer ? (curDevice.value as IOnlineDevice).clientIp : '',
  }

  if (env.VITE_APP_ENV !== 'local' || !props.isTransfer) {
    options.site_id = props.siteInfo!.name || ''
    options.device_id = curDevice.value?.sn || ''
  }
  return options
}

const pointInfoData = ref<DeviceFetchInfo[]>([])
const { devices, isFetching, startFetching, abortAll } = useFetcher(loadPointChartData)

watch(devices, (newValue) => {
  if (!newValue) return
  pointInfoData.value = newValue
  loading.value = false
}, { deep: true })

async function loadChardData2() {
  loading.value = true
  clearData()
  const groupIds = Array.from(chartParamsMap.keys())
  if (!groupIds.length) {
    loading.value = false
    message.error('请先选择点位')
    return
  }
  await startFetching(groupIds, buildOptions, 1000)
  if (!devices.value || !devices.value.length) {
    loading.value = false
    clearData()
    message.error('获取设备数据失败')
    return
  }
  for (const device of devices.value) {
    setChartData2(device.id, device.data)
  }
}

function setChartData2(groupName: string, data: any[]) {
  const chartParams = chartParamsMap.get(groupName)
  if (!chartParams) return

  for (const column of chartParams.columns) {
    const groupInfo = chartGroupMap.get(groupName)
    if (!groupInfo) continue
    legends.value.push({
      addr: `${groupName}-${column.addr}`,
      label: `${groupInfo.cnName}-${column.label}`,
      unit: column.unit || ''
    })
  }

  data.forEach((data: any[]) => {
    const [ts, val, addr] = data
    const time = dayjs(Number(ts)).format('YYYY-MM-DD HH:mm:ss.SSS')
    if (addr) {
      const colData = chartData.get(`${groupName}-${addr}`)
      const value = Number(Number(val).toFixed(5))
      if (colData) {
        colData.push([time, value])
      } else {
        chartData.set(`${groupName}-${addr}`, [[time, value]])
      }
    }
  })
}

function handleBeforeClose(done: () => void) {
  ElMessageBox.confirm('你确定要关闭吗?')
    .then(() => {
      if (isFetching) {
        abortAll()
      }
      time.value = undefined
      isShowDrawer.value = false
      clearData()
      fullscreenLoading.value = null
      chartParamsMap.clear()
      chartGroupMap.clear()
      done()
    })
    .catch(() => {

    })
}

function clearData() {
  legends.value = []
  pointInfoData.value = []
  chartData.clear()
}

function resetChartStatus() {
  loadingChart.value = false
  nextTick(() => {
    isShowChart.value = true
  })
}

const chartRef = ref<InstanceType<typeof NewDataChart>>()
const isShowChart = ref(false)

function onDrawerOpened() {
  nextTick(() => {
    isShowChart.value = true
  })
}

const fullscreenLoading = ref<any>(null)
const openFullScreen = () => {
  fullscreenLoading.value = ElLoading.service({
    lock: true,
    text: '数据加载中,请稍后...',
    background: 'rgba(255, 255, 255, 0.8)',
  })
}

const pointGroup = ref<IPointGroupOV[]>([])
const curGroup = ref<IPointGroupOV>()
const curGroupName = ref<string>()

async function loadPointGroup() {
  const params: IPointGroupParams = {}
  if (props.isTransfer) {
    const onlineDevice = curDevice.value as IOnlineDevice
    params.isLocal = false
    params.host = onlineDevice.clientIp
  } else {
    const offlineDevice = curDevice.value as IOfflineDevice
    params.sn = offlineDevice.sn
    params.site = props.siteInfo!.name
    params.isLocal = true
  }

  const res = await getPointGroup(params)
  if (res.code === 0) {
    curGroup.value = res.data[0]
    curGroupName.value = res.data[0]?.name
    pointGroup.value = Array.isArray(res?.data) ? bms_cellRewriteName(res.data) : []
    return Promise.resolve()
  } else {
    return Promise.reject()
  }
}

const groupChangeLoading = ref<boolean>(false)

function onGroupChange(item: IPointGroupOV) {
  console.log(item)
  if (!item?.type) {
    return
  }
  groupChangeLoading.value = true
  curGroup.value = item
  curGroupName.value = item.name
  loadDeviceDetails()
}


const chartParamsMap = new Map<string, ChartParamsMap>()
const chartGroupMap = new Map<string, IPointGroupOV>()

function onchangePoints(checkPoints: IMyPoint[]) {
  if (!curGroup?.value || !curGroupName?.value) return message.error('请选择设备')

  const currentCheckPoints = checkPoints.filter((r: any) => r.parentName === curGroupName.value)
  chartParamsMap.set(curGroupName.value, {
    name: curGroupName.value,
    columns: currentCheckPoints
  })
  chartGroupMap.set(curGroupName.value, curGroup.value)

  if (!currentCheckPoints.length) {
    chartParamsMap.delete(curGroupName.value)
    chartGroupMap.delete(curGroupName.value)
  }
}

const disabledDate = (time: any) => {
  const current = dayjs(time)
  if (props.isTransfer) return current.isAfter(dayjs(), 'day')
  try {
    const deviceOff = curDevice.value as IOfflineDevice
    const start = dayjs(deviceOff.start_time).format('YYYY-MM-DD')
    const end = dayjs(deviceOff.end_time).format('YYYY-MM-DD')
    return current.isBefore(start, 'day') || current.isAfter(end, 'day')
  } catch (e) {
    console.log('disableDate error', e)
    return current.isAfter(dayjs(), 'day')
  }

}

const collapsed = ref(false)

function onCollapse(value?: boolean) {
  collapsed.value = value ?? !collapsed.value
}

const getBeforeMonth = dayjs().startOf('month').subtract(1, 'month').startOf('month').toDate()
defineExpose({
  open,
  openFullScreen,
})
</script>

<style scoped lang="scss">
.fault-rule-drawer {
  font-size: 16px;

  :deep(.edfs-wrap) {
    width: auto;
  }

  :deep(.el-drawer__header) {
    color: var(--text-color);
  }
}
</style>
