<script setup lang="ts">
import { useUserStore } from '@/store/modules/user'
import { DICT_TYPE, getStrDictOptions } from '@/utils/dict'
import { rangeShortcuts } from '@/utils/formatTime'
import * as DeptApi from '@/api/system/dept'
import { handleTree } from '@/utils/tree'
import { IotDeviceApi } from '@/api/pms/device'
import { EChartsOption } from 'echarts'
import chart from './chart.vue'
import dayjs from 'dayjs'
import { useFullscreen } from '@vueuse/core'
import { Crop, FullScreen } from '@element-plus/icons-vue'

const userStore = useUserStore()
const userDeptId = userStore.getUser.deptId

interface DeviceData {
  id: number
  ifInline: string
  lastInlineTime: string
  deviceCode: string
  deviceName: string
  deptName: string
  vehicleName: string
  carOnline: string
  mqttUrl: string
}

interface DeviceQuery {
  deptId?: number
  ifInline?: string
}

const originalDeviceQuery: DeviceQuery = {
  deptId: userDeptId,
  ifInline: '0'
}

const deviceQuery = ref<DeviceQuery>({
  ...originalDeviceQuery
})

interface Query {
  deviceCodes: number[]
  time: string[]
}

const originalQuery: Query = {
  deviceCodes: [],
  time: [
    dayjs().subtract(5, 'minute').format('YYYY-MM-DD HH:mm:ss'),
    dayjs().format('YYYY-MM-DD HH:mm:ss')
  ]
  // time: [...rangeShortcuts[2].value().map((item) => dayjs(item).format('YYYY-MM-DD HH:mm:ss'))]
}

const query = ref<Query>({ ...originalQuery })

const deptLoading = ref(false)
const deptOptions = ref<any[]>([])

async function loadDeptOptions() {
  deptLoading.value = true
  try {
    function sortTreeBySort(treeNodes: Tree[]) {
      if (!treeNodes || !Array.isArray(treeNodes)) return treeNodes
      const sortedNodes = [...treeNodes].sort((a, b) => {
        const sortA = a.sort != null ? a.sort : 999999
        const sortB = b.sort != null ? b.sort : 999999
        return sortA - sortB
      })

      sortedNodes.forEach((node) => {
        if (node.children && Array.isArray(node.children)) {
          node.children = sortTreeBySort(node.children)
        }
      })
      return sortedNodes
    }

    const depts = await DeptApi.specifiedSimpleDepts(userDeptId)
    deptOptions.value = sortTreeBySort(handleTree(depts))
  } catch (error) {
  } finally {
    deptLoading.value = false
  }
}

const deviceLoading = ref(false)
const deviceOptions = ref<any[]>([])

async function loadDeviceOptions() {
  if (!deviceQuery.value.deptId) return

  deviceLoading.value = true
  try {
    const data = await IotDeviceApi.getBoardDevice({
      deptId: deviceQuery.value.deptId,
      ifInline: deviceQuery.value.ifInline,
      pageSize: 100
    })
    // const data = await IotDeviceApi.getIotDeviceTdPage({
    //   deptId: deviceQuery.value.deptId,
    //   ifInline: deviceQuery.value.ifInline,
    //   pageSize: 100
    // })
    deviceOptions.value = data.list.map((item: any) => ({
      label: item.deviceCode + '-' + item.deviceName,
      value: item.id,
      raw: item
    }))
    query.value.deviceCodes = deviceOptions.value
      .filter((i) => i.raw.ifInline === 3)
      .map((i) => i.value)
    handleDeviceChange(query.value.deviceCodes)
  } catch (error) {
    deviceOptions.value = []
  } finally {
    deviceLoading.value = false
  }
}

const deviceList = ref<DeviceData[]>([])
const chartOption = ref<EChartsOption>({})

async function handleDeviceChange(selectedIds: number[]) {
  deviceList.value = deviceList.value.filter((d) => selectedIds.includes(d.id))

  const currentIds = deviceList.value.map((d) => d.id)
  const newIds = selectedIds.filter((id) => !currentIds.includes(id))

  for (const id of newIds) {
    const option = deviceOptions.value.find((op) => op.value === id)
    if (option) {
      deviceList.value.push({
        id: id,
        ifInline: option.raw.ifInline,
        lastInlineTime: option.raw.lastInlineTime,
        deptName: option.raw.deptName,
        vehicleName: option.raw.vehicleName,
        carOnline: option.raw.carOnline ?? '',
        deviceCode: option.raw.deviceCode,
        deviceName: option.raw.deviceName,
        mqttUrl: option.raw.mqttUrl
      })
    }
  }
}

onMounted(() => {
  loadDeptOptions()
  loadDeviceOptions()
})

function handleDeptChange() {
  query.value = { ...originalQuery }
  deviceList.value = []
  chartOption.value = {}
  loadDeviceOptions()
}

const targetArea = ref(null)

const { toggle, isFullscreen } = useFullscreen(targetArea)

function handleRest() {
  deviceQuery.value = { ...originalDeviceQuery }
  query.value = { ...originalQuery }
  loadDeptOptions()
  loadDeviceOptions()
}

function handleInlineChange() {
  loadDeviceOptions()
}

const token = ref('')

async function getToken() {
  const res = await IotDeviceApi.getToken()

  token.value = res
}

onMounted(() => {
  getToken()
})
</script>

<template>
  <div
    ref="targetArea"
    class="relative w-full rounded-lg bg-[#020408] overflow-hidden min-h-[calc(100vh-20px-var(--top-tool-height)-var(--tags-view-height)-var(--app-footer-height))]"
  >
    <header
      class="relative w-full h-14 flex items-center justify-center select-none bg-[#0b1121] border-b border-white/5 shadow-lg"
    >
      <div
        class="absolute inset-0 opacity-20"
        style="background-image: radial-gradient(circle at 50% 50%, #083344 0%, transparent 50%)"
      >
      </div>

      <div class="absolute bottom-0 left-0 w-full h-[2px] bg-slate-800/50 overflow-hidden z-20">
        <div
          class="absolute top-0 bottom-0 w-[40%] bg-gradient-to-r from-transparent via-[#22d3ee] to-transparent shadow-[0_0_20px_#22d3ee] animate-scan-line"
        ></div>
      </div>

      <div class="absolute left-6 top-1/2 -translate-y-1/2 flex items-center gap-1 opacity-80">
        <div
          class="w-1 h-4 bg-cyan-400 skew-x-[-12deg] shadow-[0_0_5px_rgba(34,211,238,0.8)]"
        ></div>
        <div class="w-1 h-3 bg-cyan-700 skew-x-[-12deg]"></div>
        <div class="w-1 h-2 bg-cyan-900 skew-x-[-12deg]"></div>
      </div>

      <div
        class="absolute right-6 top-1/2 -translate-y-1/2 flex items-center gap-1 opacity-80 flex-row-reverse"
      >
        <div class="w-1 h-4 bg-cyan-400 skew-x-[12deg] shadow-[0_0_5px_rgba(34,211,238,0.8)]"></div>
        <div class="w-1 h-3 bg-cyan-700 skew-x-[12deg]"></div>
        <div class="w-1 h-2 bg-cyan-900 skew-x-[12deg]"></div>
      </div>

      <h1 class="z-10 text-2xl font-bold tracking-[0.5em] uppercase">
        <span
          class="text-transparent bg-clip-text bg-gradient-to-b from-white via-cyan-100 to-cyan-500 drop-shadow-[0_0_10px_rgba(34,211,238,0.8)]"
        >
          监控看板
        </span>
      </h1>
    </header>
    <div class="p-4">
      <el-form size="default" class="search-container grid grid-cols-6 gap-6">
        <div
          class="absolute left-0 top-0 w-[2px] h-full bg-gradient-to-b from-transparent via-cyan-500 to-transparent"
        ></div>
        <el-form-item class="col-span-1" label="部门">
          <el-cascader
            v-model="deviceQuery.deptId"
            :options="deptOptions"
            @change="handleDeptChange"
            popper-class="poper"
            :teleported="false"
            :show-all-levels="false"
            :props="{ checkStrictly: true, label: 'name', value: 'id' }"
            class="w-full"
            placeholder="请选择部门"
          />
        </el-form-item>
        <el-form-item class="col-span-1" label="在线状态">
          <el-select
            v-model="deviceQuery.ifInline"
            placeholder="请选择状态"
            clearable
            :teleported="false"
            popper-class="poper"
            class="w-full"
            :class="{ selected: Boolean(deviceQuery.ifInline) }"
            @change="handleInlineChange"
          >
            <el-option
              v-for="dict in getStrDictOptions(DICT_TYPE.IOT_DEVICE_STATUS)"
              :key="dict.value"
              :label="dict.label"
              :value="dict.value"
            />
          </el-select>
        </el-form-item>
        <el-form-item class="col-span-3" label="时间范围">
          <el-date-picker
            v-model="query.time"
            value-format="YYYY-MM-DD HH:mm:ss"
            type="datetimerange"
            start-placeholder="开始日期"
            end-placeholder="结束日期"
            :shortcuts="rangeShortcuts"
            :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
            :teleported="false"
            popper-class="poper"
            class="w-full"
          />
        </el-form-item>
        <el-form-item class="col-span-5 col-start-1" label="设备">
          <el-select
            v-model="query.deviceCodes"
            :options="deviceOptions"
            multiple
            placeholder="请选择设备"
            :teleported="false"
            popper-class="poper"
            class="w-full"
            tag-type="primary"
            filterable
            @change="handleDeviceChange"
          />
        </el-form-item>
        <el-form-item class="col-span-1 flex justify-end">
          <div class="flex gap-3 w-full justify-end">
            <el-button
              class="custom-btn primary-btn"
              :type="isFullscreen ? 'info' : 'primary'"
              :icon="isFullscreen ? Crop : FullScreen"
              @click="toggle"
            >
              {{ isFullscreen ? '退出全屏' : '全屏' }}
            </el-button>
            <el-button @click="handleRest" class="custom-btn reset-btn">重置</el-button>
          </div>
        </el-form-item>
      </el-form>
    </div>

    <div class="p-4 grid grid-cols-2 3xl:grid-cols-3 gap-6">
      <template v-for="item in deviceList" :key="item.id">
        <chart v-bind="item" :date="query.time" :token="token" />
      </template>
    </div>
  </div>
</template>

<style scoped>
@keyframes scan-line {
  0% {
    left: -40%;
    opacity: 0;
  }

  10% {
    opacity: 1;
  }

  90% {
    opacity: 1;
  }

  100% {
    left: 100%;
    opacity: 0;
  }
}

/* 5. 扫描线动画细节 */
@keyframes scan-line {
  0% {
    left: -40%;
    opacity: 0;
  }

  50% {
    opacity: 1;
  }

  100% {
    left: 100%;
    opacity: 0;
  }
}

.animate-scan-line {
  animation: scan-line 3s cubic-bezier(0.4, 0, 0.2, 1) infinite alternate;
}

.search-container {
  position: relative;
  padding: 24px;
  background: linear-gradient(135deg, rgb(11 17 33 / 90%) 0%, rgb(6 9 18 / 95%) 100%);
  border: 1px solid rgb(34 211 238 / 60%);
  border-radius: 4px;
  box-shadow: 0 10px 40px rgb(0 0 0 / 60%);
}

:deep(.el-form-item) {
  --background-color: rgb(2 4 8 / 80%) !important;
  --box-shadow: 0 0 0 1px rgb(34 211 238 / 20%) inset !important;
  --transition: all 0.3s ease;
  --active-box-shadow: 0 0 0 1px #22d3ee inset, 0 0 12px rgb(34 211 238 / 30%) !important;
  --bg-color-overlay: rgb(16 24 45) !important;
  --border-color: rgb(34 211 238 / 20%) !important;
  --text-color-regular: rgb(240 249 255 / 90%) !important;
  --text-color-primary: rgb(92 231 247 / 90%) !important;

  margin-bottom: 0;

  .el-form-item__label {
    padding-bottom: 4px;
    font-size: 14px;
    font-weight: 500;
    color: rgb(165 243 252 / 90%) !important;
  }

  .el-input__wrapper,
  .el-select__wrapper {
    background-color: var(--background-color);
    box-shadow: var(--box-shadow);
    transition: var(--transition);
  }

  .el-input__wrapper.is-focus,
  .is-focused,
  .is-active {
    box-shadow: var(--active-box-shadow);
  }

  .poper {
    --el-bg-color-overlay: var(--bg-color-overlay);
    --el-border-color-light: var(--border-color);
    --el-fill-color-light: var(--border-color);
    --el-text-color-regular: var(--text-color-regular);
    --el-text-color-primary: var(--text-color-primary);
    --el-border-color-extra-light: var(--border-color);
  }

  .el-cascader-node {
    &.is-active {
      box-shadow: none;
    }
  }

  .el-time-spinner__item.is-active {
    box-shadow: none;
  }

  .cancel {
    color: var(--el-color-danger);
  }

  .el-picker-panel__footer {
    .is-text {
      color: var(--el-color-danger);
    }

    .is-plain {
      color: var(--text-color-primary);
      background-color: var(--border-color);
      border-color: var(--border-color);
    }
  }

  .el-picker__popper {
    border-color: var(--border-color);

    .el-time-panel {
      border-color: var(--border-color);
    }

    .el-picker-panel__footer {
      .is-text {
        color: var(--el-color-danger);
      }

      .is-plain {
        color: var(--text-color-primary);
        background-color: var(--border-color);
        border-color: var(--border-color);
      }
    }
  }

  .el-input {
    --el-input-hover-border-color: var(--border-color);
  }

  .el-input__inner,
  .el-date-editor .el-range-input {
    color: var(--text-color-primary);
  }

  .selected {
    .el-select__placeholder {
      color: var(--text-color-primary);
    }
  }

  .el-tag {
    --el-tag-bg-color: var(--border-color);
    --el-tag-border-color: var(--border-color);
    --el-tag-text-color: var(--text-color-primary);
  }
}

.custom-btn {
  border: none;
  border-radius: 2px;
  transition: all 0.3s;
}

.primary-btn {
  color: #020617;
  background: linear-gradient(90deg, #0891b2 0%, #22d3ee 100%);
  box-shadow: 0 0 10px rgb(34 211 238 / 30%);
}

.primary-btn:hover {
  background: linear-gradient(90deg, #22d3ee 0%, #67e8f9 100%);
  transform: translateY(-1px);
  box-shadow: 0 0 20px rgb(34 211 238 / 50%);
}

.reset-btn {
  color: #94a3b8;
  background: rgb(255 255 255 / 5%);
  border: 1px solid rgb(148 163 184 / 30%);
}

.reset-btn:hover {
  color: #fff;
  background: rgb(255 255 255 / 10%);
  border-color: rgb(255 255 255 / 50%);
}
</style>
