<template>
  <el-row :gutter="20">
    <el-col :span="6" :xs="24">
      <ContentWrap class="h-1/1">
        <div class="device-param-tree-toolbar">
          <el-input
            v-model="keyword"
            clearable
            :placeholder="t('DataCollection.DeviceParamAnalysis.treeSearchPlaceholder')"
            class="device-param-tree-toolbar__input"
            @input="handleKeywordChange"
          />
          <el-button :loading="treeLoading" @click="handleTreeRefresh">
            <Icon icon="ep:refresh" class="mr-5px" />
            {{ t('DataCollection.DeviceParamAnalysis.refreshButtonText') }}
          </el-button>
        </div>
        <div class="mt-12px">
          <el-tree
            ref="treeRef"
            v-loading="treeLoading"
            :data="treeData"
            :props="treeProps"
            :default-expanded-keys="defaultExpandedKeys"
            node-key="id"
            show-checkbox
            check-strictly
            @check="handleTreeCheck"
          >
            <template #default="{ data }">
              <span class="device-param-tree-node">
                <span class="device-param-tree-node__label">{{ data.label }}</span>
                <el-tag v-if="data.tag === 'equipment'" type="success" size="small" effect="plain">&#35774;&#22791;</el-tag>
              </span>
            </template>
          </el-tree>
        </div>
      </ContentWrap>
    </el-col>

    <el-col :span="18" :xs="24">
      <div class="analysis-groups">
        <ContentWrap v-if="!selectedGroups.length">
          <el-empty :description="t('DataCollection.DeviceParamAnalysis.emptySelectNodeDescription')" />
        </ContentWrap>

        <ContentWrap v-for="group in selectedGroups" :key="group.id">
          <el-form class="-mb-15px device-param-analysis-form" :inline="true" label-width="auto">
            <el-form-item :label="t('DataCollection.DeviceParamAnalysis.formTimeLabel')">
              <div>
                <el-date-picker
                  v-model="group.dateRange"
                  type="datetimerange"
                  :start-placeholder="t('DataCollection.DeviceParamAnalysis.formTimeStartPlaceholder')"
                  :end-placeholder="t('DataCollection.DeviceParamAnalysis.formTimeEndPlaceholder')"
                  value-format="YYYY-MM-DD HH:mm:ss"
                  :shortcuts="dateShortcuts"
                  class="!w-360px"
                  :disabled-date="disableFutureDate"
                  @change="(value) => handleDateRangeChange(group, value)"
                />
                <div class="mt-4px text-12px text-gray-500">最多选择 8 小时，且不能选择未来日期</div>
              </div>
            </el-form-item>
            <el-form-item>
              <el-button :disabled="group.chartLoading" @click="handleQuery(group)">
                <Icon icon="ep:search" class="mr-5px" />
                {{ t('DataCollection.DeviceParamAnalysis.searchButtonText') }}
              </el-button>
              <el-button :disabled="group.chartLoading" @click="resetQuery(group)">
                <Icon icon="ep:refresh" class="mr-5px" />
                {{ t('DataCollection.DeviceParamAnalysis.resetButtonText') }}
              </el-button>
            </el-form-item>
          </el-form>

          <el-alert :title="buildParamTitle(group.param)" type="info" :closable="false" class="mb-12px" />
          <div v-loading="group.chartLoading">
            <el-empty
              v-if="group.chartState === 'empty'"
              :description="t('DataCollection.DeviceParamAnalysis.emptyDescription')"
            />
            <EChart
              v-else-if="group.chartState === 'ready'"
              :key="group.chartRenderKey"
              :options="buildChartOption(group)"
              height="360px"
            />
          </div>
        </ContentWrap>
      </div>
    </el-col>
  </el-row>
</template>

<script setup lang="ts">
import type { EChartsOption } from 'echarts'
import dayjs from 'dayjs'
import { Echart as EChart } from '@/components/Echart'
import { OrganizationApi } from '@/api/mes/organization'
import { DeviceModelAttributeApi } from '@/api/iot/devicemodelattribute'
import { handleTree } from '@/utils/tree'

defineOptions({ name: 'DeviceParamAnalysis' })

const { t } = useI18n()

type TreeNodeType = 'device' | 'param'
type TreeNodeTag = 'equipment'

type DeviceTreeNode = {
  id: string
  label: string
  type: TreeNodeType
  tag?: TreeNodeTag
  children?: DeviceTreeNode[]
  orgClass?: string
  deviceId?: number
  modelId?: number
  paramKey?: string
  unit?: string
  paramCount?: number
  disabled?: boolean
}

type ApiTreeParameter = {
  id: number
  name: string
  code?: string
  unit?: string | null
}

type ApiTreeEquipment = {
  id: number
  name: string
  parameters?: ApiTreeParameter[]
}

type ApiTreeOrg = {
  id: number
  name: string
  orgClass?: string
  parentId?: number | null
  equipments?: ApiTreeEquipment[]
  children?: ApiTreeOrg[]
}

const message = useMessage()

const treeRef = ref()
const treeLoading = ref(false)
const keyword = ref('')
const treeProps = { children: 'children', label: 'label', disabled: 'disabled' }
const treeData = ref<DeviceTreeNode[]>([])
const defaultExpandedKeys = ref<string[]>([])

const DATE_TIME_FORMAT = 'YYYY-MM-DD HH:mm:ss'
const MAX_DATE_RANGE_HOURS = 8
const MAX_DATE_RANGE_MS = MAX_DATE_RANGE_HOURS * 60 * 60 * 1000
const lastValidDateRange = new Map<string, [string, string]>()

const disableFutureDate = (date: Date) => {
  return dayjs(date).isAfter(dayjs(), 'day')
}

const buildDefaultDateRange = (): [string, string] => {
  const end = dayjs()
  const start = end.subtract(2, 'hour')
  return [start.format(DATE_TIME_FORMAT), end.format(DATE_TIME_FORMAT)]
}

const createLastHoursShortcut = (hours: number) => {
  return {
    text: `最近${hours}小时`,
    value: () => {
      const end = dayjs().toDate()
      const start = dayjs().subtract(hours, 'hour').toDate()
      return [start, end]
    }
  }
}

const dateShortcuts = [
  createLastHoursShortcut(1),
  createLastHoursShortcut(2),
  createLastHoursShortcut(4),
  createLastHoursShortcut(8)
]

type ChartState = 'idle' | 'loading' | 'empty' | 'ready'

type SelectedGroup = {
  id: string
  param: DeviceTreeNode
  deviceId?: number
  modelId?: number
  dateRange: [string, string]
  requestSeq: number
  chartLoading: boolean
  chartState: ChartState
  chartXAxis: string[]
  chartSeries: Array<{ name: string; data: Array<number | null> }>
  chartRenderKey: number
}

const selectedGroups = ref<SelectedGroup[]>([])
const lastCheckedSignature = ref<string>('')

let keywordTimer: number | undefined
let treeCheckTimer: number | undefined
let pendingCheckedNodes: DeviceTreeNode[] = []
let pendingCheckedKeys: Array<string | number> = []
const handleKeywordChange = () => {
  if (keywordTimer) window.clearTimeout(keywordTimer)
  keywordTimer = window.setTimeout(() => {
    keywordTimer = undefined
    loadTree()
  }, 300)
}

const handleTreeRefresh = async () => {
  if (keywordTimer) {
    window.clearTimeout(keywordTimer)
    keywordTimer = undefined
  }
  await loadTree()
}

const toFiniteId = (value: any): number | undefined => {
  if (typeof value === 'number') return Number.isFinite(value) ? value : undefined
  if (typeof value === 'string') {
    if (/^\d+$/.test(value.trim())) return Number(value)
    const n = Number(value)
    return Number.isFinite(n) ? n : undefined
  }
  return undefined
}

const toNodeIds = (node: DeviceTreeNode): { deviceId?: number; modelId?: number } => {
  const modelId = typeof node.modelId === 'number' && Number.isFinite(node.modelId) ? node.modelId : undefined
  const deviceId = typeof node.deviceId === 'number' && Number.isFinite(node.deviceId) ? node.deviceId : undefined
  if (typeof deviceId === 'number') return { deviceId, modelId }

  const parts = String(node.id ?? '').split('-').filter(Boolean)
  const last = parts.length ? parts[parts.length - 1] : undefined
  const parsed = toFiniteId(last)
  if (typeof parsed !== 'number' || !Number.isFinite(parsed) || parsed <= 0) {
    return { modelId }
  }
  return { deviceId: parsed, modelId }
}

const buildParamTitle = (param: DeviceTreeNode) => {
  const unitText = param.unit ? ` (${param.unit})` : ''
  return t('DataCollection.DeviceParamAnalysis.selectedParamTitle', {
    label: param.label,
    unit: unitText
  })
}

const buildChartOption = (group: SelectedGroup): EChartsOption => {
  const unit = group.param?.unit
  return {
    tooltip: { trigger: 'axis' },
    legend: { top: 10, left: 'center', type: 'scroll' },
    grid: { left: 50, right: 60, top: 80, bottom: 40, containLabel: true },
    xAxis: {
      type: 'category',
      boundaryGap: false,
      data: group.chartXAxis
    },
    yAxis: {
      type: 'value',
      name: unit || ''
    },
    series: group.chartSeries.map((s) => ({
      type: 'line',
      name: s.name,
      smooth: false,
      showSymbol: false,
      data: s.data
    }))
  }
}

const buildTreeFromApi = (orgs: ApiTreeOrg[]): DeviceTreeNode[] => {
  const normalizeOrg = (org: any): ApiTreeOrg => {
    const children = Array.isArray(org?.children) ? org.children.map(normalizeOrg) : undefined
    const equipments = Array.isArray(org?.equipments) ? org.equipments : undefined
    const parentId = typeof org?.parentId === 'number' ? org.parentId : Number(org?.parentId ?? 0) || 0
    return {
      id: Number(org?.id ?? 0) || 0,
      name: String(org?.name ?? ''),
      orgClass: org?.orgClass ? String(org.orgClass) : undefined,
      parentId,
      equipments,
      children
    }
  }

  const normalizedOrgs: ApiTreeOrg[] = Array.isArray(orgs) ? orgs.map(normalizeOrg) : []
  const isNestedTree = normalizedOrgs.some((o) => typeof (o as any)?.children !== 'undefined')
  const orgTree = isNestedTree ? normalizedOrgs : (handleTree(normalizedOrgs, 'id', 'parentId', 'children') as ApiTreeOrg[])

  const toOrgNode = (org: ApiTreeOrg): DeviceTreeNode => {
    const orgChildren = Array.isArray(org?.children) ? org.children.map(toOrgNode) : []

    const equipments = Array.isArray(org?.equipments) ? org.equipments : []
    const equipmentNodes: DeviceTreeNode[] = equipments.map((eq) => {
      const params = Array.isArray(eq?.parameters) ? eq.parameters : []
      const paramNodes: DeviceTreeNode[] = params.map((p) => ({
        id: `param-${eq.id}-${p.id}`,
        label: p?.name ?? p?.code ?? String(p?.id ?? ''),
        type: 'param',
        deviceId: toFiniteId(eq.id),
        modelId: toFiniteId(p.id),
        paramKey: p?.code ? String(p.code) : undefined,
        unit: p?.unit ? String(p.unit) : undefined,
        disabled: false
      }))

      return {
        id: `equipment-${org.id}-${eq.id}`,
        label: eq?.name ?? String(eq?.id ?? ''),
        type: 'device',
        tag: 'equipment',
        deviceId: toFiniteId(eq.id),
        paramCount: params.length,
        children: paramNodes.length ? paramNodes : undefined,
        disabled: true
      }
    })

    const children = [...orgChildren, ...equipmentNodes]
    return {
      id: `org-${org.id}`,
      label: org?.name ?? String(org?.id ?? ''),
      type: 'device',
      orgClass: org?.orgClass ? String(org.orgClass) : undefined,
      children: children.length ? children : undefined,
      disabled: true
    }
  }

  return Array.isArray(orgTree) ? orgTree.map(toOrgNode) : []
}

const hasOrgClassInSubtree = (node: DeviceTreeNode, targetOrgClass: string): boolean => {
  const children = Array.isArray(node?.children) ? node.children : []
  for (const child of children) {
    if (child?.orgClass === targetOrgClass) return true
    if (hasOrgClassInSubtree(child, targetOrgClass)) return true
  }
  return false
}

const buildDefaultExpandedKeys = (nodes: DeviceTreeNode[], stopOrgClass: string): string[] => {
  const keys: string[] = []
  const walk = (list: DeviceTreeNode[]) => {
    for (const node of list) {
      if (node?.type === 'device' && node?.orgClass && node.orgClass !== stopOrgClass) {
        if (hasOrgClassInSubtree(node, stopOrgClass)) {
          keys.push(node.id)
        }
      }
      const children = Array.isArray(node?.children) ? node.children : []
      if (children.length) walk(children)
    }
  }
  walk(nodes)
  return Array.from(new Set(keys))
}

const extractApiOrgs = (res: any): ApiTreeOrg[] => {
  if (Array.isArray(res)) return res as ApiTreeOrg[]
  if (Array.isArray(res?.data)) return res.data as ApiTreeOrg[]
  if (Array.isArray(res?.result)) return res.result as ApiTreeOrg[]
  if (Array.isArray(res?.list)) return res.list as ApiTreeOrg[]
  return []
}

const loadTree = async () => {
  treeLoading.value = true
  try {
    const res = await OrganizationApi.deviceParameterAnalysis({ keyword: keyword.value || undefined, showDevices: 1 })
    treeData.value = buildTreeFromApi(extractApiOrgs(res))
    defaultExpandedKeys.value = buildDefaultExpandedKeys(treeData.value, 'pipeline')
    await nextTick()
    treeRef.value?.setExpandedKeys?.(defaultExpandedKeys.value)
    if (keyword.value) {
      treeRef.value?.setCurrentKey?.(undefined)
      treeRef.value?.setCheckedKeys?.([])
      selectedGroups.value = []
      lastCheckedSignature.value = ''
    }
  } catch {
    message.error(t('DataCollection.DeviceParamAnalysis.messageLoadTreeFailed'))
  } finally {
    treeLoading.value = false
  }
}

const normalizeDateRangeValue = (value: any): [string, string] | undefined => {
  if (!Array.isArray(value) || value.length !== 2) return undefined
  const start = value[0]
  const end = value[1]
  if (!start || !end) return undefined
  return [String(start), String(end)]
}

const ensureDateRangeWithin8Hours = (group: SelectedGroup, dateRange: [string, string]) => {
  const now = dayjs()
  let start = dayjs(dateRange[0])
  let end = dayjs(dateRange[1])
  if (!start.isValid() || !end.isValid()) return dateRange

  if (start.isAfter(now) && end.isAfter(now)) {
    end = now
    start = now.subtract(2, 'hour')
  } else {
    if (end.isAfter(now)) end = now
    if (start.isAfter(now)) start = end.subtract(2, 'hour')
  }

  const diffMs = end.valueOf() - start.valueOf()
  if (diffMs < 0) {
    end = now
    start = now.subtract(2, 'hour')
    const nextRange: [string, string] = [start.format(DATE_TIME_FORMAT), end.format(DATE_TIME_FORMAT)]
    return nextRange
  }
  if (diffMs <= MAX_DATE_RANGE_MS) {
    return [start.format(DATE_TIME_FORMAT), end.format(DATE_TIME_FORMAT)]
  }
  const clampedEnd = start.add(MAX_DATE_RANGE_HOURS, 'hour')
  const finalEnd = clampedEnd.isAfter(now) ? now : clampedEnd
  return [start.format(DATE_TIME_FORMAT), finalEnd.format(DATE_TIME_FORMAT)]
}

const ensureDateRange = (group: SelectedGroup) => {
  if (!group.dateRange || group.dateRange.length !== 2) {
    group.dateRange = buildDefaultDateRange()
    lastValidDateRange.set(group.id, group.dateRange)
    return
  }
  const normalized = normalizeDateRangeValue(group.dateRange)
  if (!normalized) {
    group.dateRange = buildDefaultDateRange()
    lastValidDateRange.set(group.id, group.dateRange)
    return
  }
  const nextRange = ensureDateRangeWithin8Hours(group, normalized)
  group.dateRange = nextRange
  lastValidDateRange.set(group.id, nextRange)
}

const handleDateRangeChange = (group: SelectedGroup, value: any) => {
  const normalized = normalizeDateRangeValue(value) || normalizeDateRangeValue(group.dateRange)
  if (!normalized) return

  const now = dayjs()
  const selectedStart = dayjs(normalized[0])
  const selectedEnd = dayjs(normalized[1])
  const hasFuture = (selectedStart.isValid() && selectedStart.isAfter(now)) || (selectedEnd.isValid() && selectedEnd.isAfter(now))

  const nextRange = ensureDateRangeWithin8Hours(group, normalized)
  const isClamped = nextRange[0] !== normalized[0] || nextRange[1] !== normalized[1]
  if (hasFuture) {
    message.warning('不能选择未来日期')
  } else if (isClamped) {
    message.warning('时间范围最多只能选择 8 小时')
  }
  group.dateRange = nextRange
  lastValidDateRange.set(group.id, nextRange)
}

const resetChartData = (group: SelectedGroup) => {
  group.chartXAxis = []
  group.chartSeries = []
  group.chartRenderKey++
}

const toNumber = (value: any) => {
  if (typeof value === 'number') return value
  if (typeof value === 'string') {
    const n = Number(value)
    return Number.isFinite(n) ? n : 0
  }
  if (Array.isArray(value)) return 0
  if (value && typeof value === 'object') {
    const maybe = value.value ?? value.val ?? value.count ?? value.amount
    const n = Number(maybe)
    return Number.isFinite(n) ? n : 0
  }
  return 0
}

const extractChartRows = (res: any): Record<string, any>[] => {
  if (Array.isArray(res)) return res as Record<string, any>[]
  if (Array.isArray(res?.data)) return res.data as Record<string, any>[]
  if (Array.isArray(res?.result)) return res.result as Record<string, any>[]
  if (Array.isArray(res?.list)) return res.list as Record<string, any>[]
  return []
}

const fetchGroupChart = async (group: SelectedGroup, notify: boolean) => {
  if (typeof group.deviceId !== 'number' || !Number.isFinite(group.deviceId)) return

  ensureDateRange(group)
  const [start, end] = group.dateRange
  if (!start || !end) return

  const buildDateTime = (date: string, suffix: string) => {
    return date.includes(':') ? date : `${date} ${suffix}`
  }

  const requestSeq = ++group.requestSeq
  group.chartState = 'loading'
  group.chartLoading = true
  resetChartData(group)
  try {
    const req: Record<string, any> = {
      deviceId: group.deviceId,
      collectionStartTime: buildDateTime(start, '00:00:00'),
      collectionEndTime: buildDateTime(end, '23:59:59')
    }
    if (typeof group.modelId === 'number' && Number.isFinite(group.modelId)) {
      req.modelId = group.modelId
    }
 
    const data = await DeviceModelAttributeApi.operationAnalysisDetails(req as any)
    if (requestSeq !== group.requestSeq) return
    const rows: Record<string, any>[] = extractChartRows(data)
    if (!rows.length) {
      group.chartXAxis = []
      group.chartSeries = []
      group.chartState = 'empty'
      if (notify) {
        message.warning(t('DataCollection.DeviceParamAnalysis.messageNodeNoParams'))
      }
      return
    }

    const firstRow = rows[0] || {}
    const keys = Object.keys(firstRow)

    if (keys.includes('collectTime') && keys.includes('attributeName') && keys.includes('addressValue')) {
      const sortedRows = [...rows].sort((a, b) =>
        String(a?.collectTime ?? '').localeCompare(String(b?.collectTime ?? ''))
      )
      if (requestSeq !== group.requestSeq) return

      const xAxis = Array.from(new Set(sortedRows.map((r) => String(r?.collectTime ?? ''))))
      const xIndexMap = new Map<string, number>()
      xAxis.forEach((x, idx) => xIndexMap.set(x, idx))
      group.chartXAxis = xAxis

      const seriesMap = new Map<string, Array<number | null>>()
      const ensureSeries = (name: string) => {
        if (!seriesMap.has(name)) {
          seriesMap.set(name, Array(xAxis.length).fill(null))
        }
        return seriesMap.get(name)!
      }

      sortedRows.forEach((row) => {
        const time = String(row?.collectTime ?? '')
        const idx = xIndexMap.get(time)
        if (typeof idx !== 'number') return
        const name = String(row?.attributeName ?? group.param?.label ?? '')
        const series = ensureSeries(name)
        series[idx] = toNumber(row?.addressValue)
      })

      group.chartSeries = Array.from(seriesMap.entries()).map(([name, data]) => ({ name, data }))
    } else {
      const xKey = keys.find((k) => /time|date|时间|日期/i.test(k))
      if (xKey) {
        const sortedRows = [...rows].sort((a, b) =>
          String(a?.[xKey] ?? '').localeCompare(String(b?.[xKey] ?? ''))
        )
        if (requestSeq !== group.requestSeq) return
        group.chartXAxis = sortedRows.map((r) => String(r?.[xKey] ?? ''))

        const seriesKeys = keys.filter((k) => k !== xKey)
        const seriesMap = new Map<string, Array<number | null>>()
        const ensureSeries = (name: string) => {
          if (!seriesMap.has(name)) {
            seriesMap.set(name, Array(sortedRows.length).fill(null))
          }
          return seriesMap.get(name)!
        }

        sortedRows.forEach((row, rowIndex) => {
          seriesKeys.forEach((k) => {
            const v = row?.[k]
            if (Array.isArray(v)) {
              v.forEach((item) => {
                const name = String(item?.attributeName ?? k)
                const series = ensureSeries(name)
                series[rowIndex] = toNumber(item?.addressValue ?? item?.value ?? item?.val)
              })
              return
            }
            const series = ensureSeries(k)
            series[rowIndex] = toNumber(v)
          })
        })

        group.chartSeries = Array.from(seriesMap.entries()).map(([name, data]) => ({ name, data }))
      } else {
        group.chartXAxis = keys
        const values = keys.map((k) => toNumber(firstRow[k]))
        group.chartSeries = [
          { name: group.param?.label || t('DataCollection.DeviceParamAnalysis.defaultSeriesName'), data: values }
        ]
      }
    }

    group.chartState = group.chartXAxis.length && group.chartSeries.length ? 'ready' : 'empty'
  } catch {
    if (notify) {
      message.error(t('DataCollection.DeviceParamAnalysis.messageFetchChartFailed'))
    }
    group.chartState = 'idle'
  } finally {
    if (requestSeq === group.requestSeq) {
      group.chartLoading = false
    }
  }
}

const syncGroupsByCheckedNodes = (checkedNodes: DeviceTreeNode[]) => {
  const ids = checkedNodes.map((n) => String(n.id))
  const existingIds = new Set(selectedGroups.value.map((g) => g.id))
  const nextIds = new Set(ids)

  selectedGroups.value = selectedGroups.value.filter((g) => nextIds.has(g.id))

  const toAdd = checkedNodes.filter((n) => !existingIds.has(String(n.id)))
  const addedGroups: SelectedGroup[] = []
  for (const node of toAdd) {
    const { deviceId, modelId } = toNodeIds(node)
    if (typeof deviceId !== 'number') {
      continue
    }
    const group: SelectedGroup = {
      id: String(node.id),
      param: node,
      deviceId,
      modelId,
      dateRange: buildDefaultDateRange(),
      requestSeq: 0,
      chartLoading: false,
      chartState: 'idle',
      chartXAxis: [],
      chartSeries: [],
      chartRenderKey: 0
    }
    selectedGroups.value.push(group)
    lastValidDateRange.set(group.id, group.dateRange)
    addedGroups.push(group)
  }
  return addedGroups
}

const handleTreeCheck = async (_node?: DeviceTreeNode, info?: any) => {
  const checkedNodes = (info?.checkedNodes ?? []) as DeviceTreeNode[]
  const checkedKeys = (info?.checkedKeys ?? []) as Array<string | number>
  pendingCheckedNodes = Array.isArray(checkedNodes) ? checkedNodes : []
  pendingCheckedKeys = Array.isArray(checkedKeys) ? checkedKeys : []
  if (treeCheckTimer) {
    window.clearTimeout(treeCheckTimer)
  }
  treeCheckTimer = window.setTimeout(async () => {
    treeCheckTimer = undefined
    const effectiveNodes = pendingCheckedNodes.filter((n) => n?.type === 'param')
    const signature = pendingCheckedKeys
      .map((k) => String(k ?? ''))
      .filter(Boolean)
      .sort()
      .join(',')
    if (signature === lastCheckedSignature.value) return
    lastCheckedSignature.value = signature

    const addedGroups = syncGroupsByCheckedNodes(effectiveNodes)
    const needFetchGroups = selectedGroups.value.filter((g) => g.chartState === 'idle' && !g.chartLoading)
    const ids = new Set<string>([...addedGroups.map((g) => g.id), ...needFetchGroups.map((g) => g.id)])
    const groups = selectedGroups.value.filter((g) => ids.has(g.id))
    await Promise.allSettled(groups.map((g) => fetchGroupChart(g, false)))
  }, 0)
}

const handleQuery = async (group: SelectedGroup) => {
  await fetchGroupChart(group, true)
}

const resetQuery = async (group: SelectedGroup) => {
  group.dateRange = buildDefaultDateRange()
  await fetchGroupChart(group, true)
}

onMounted(async () => {
  await loadTree()
})
</script>

<style scoped lang="scss">
.device-param-analysis-form{
    margin-bottom: 0px
}
.device-param-analysis-form :deep(.el-form-item__label) {
  min-width: 100px;
}

.analysis-groups {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.device-param-tree-toolbar {
  display: flex;
  align-items: center;
  gap: 8px;
}

.device-param-tree-toolbar__input {
  flex: 1;
  min-width: 0;
}

.device-param-tree-node {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
}

.device-param-tree-node__label {
  overflow: hidden;
  text-overflow: ellipsis;
}

:deep(.el-tree) {
  max-height: calc(100vh - 280px);
  overflow: auto;
}
</style>
