<script setup lang="ts">
import * as echarts from 'echarts'

type StatItem = {
  name?: string
  category?: string
  value?: number | string
}

const props = defineProps<{
  data: StatItem[]
  loading?: boolean
}>()

const chartRef = ref<HTMLDivElement>()
let chart: echarts.ECharts | null = null
let resizeObserver: ResizeObserver | null = null

const palette = [
  '#1688f5',
  '#35cdb2',
  '#ffbd59',
  '#ff6f91',
  '#8c7cff',
  '#4eb3ff',
  '#52c41a',
  '#fa8c16',
  '#13c2c2',
  '#722ed1',
  '#eb2f96',
  '#2f54eb'
]

const chartData = computed(() =>
  props.data.map((item) => ({
    name: item.name || item.category || '未知',
    value: Number(item.value ?? 0)
  }))
)

const total = computed(() => chartData.value.reduce((sum, item) => sum + item.value, 0))
const legendItems = computed(() => chartData.value)

const escapeHtml = (value: string) =>
  value.replace(/[&<>"']/g, (char) => {
    const entities: Record<string, string> = {
      '&': '&amp;',
      '<': '&lt;',
      '>': '&gt;',
      '"': '&quot;',
      "'": '&#39;'
    }
    return entities[char]
  })

const formatTooltip = (params: {
  color?: string
  marker?: string
  name?: string
  percent?: number
  value?: number | string
}) => {
  const color = typeof params.color === 'string' ? params.color : palette[0]
  const marker =
    params.marker ||
    `<span style="display:inline-block;width:8px;height:8px;margin-right:6px;border-radius:50%;background:${color};"></span>`
  const name = escapeHtml(params.name || '未知')
  const value = params.value ?? 0
  const percent = typeof params.percent === 'number' ? params.percent.toFixed(2) : '0.00'

  return `<div style="line-height:1.8;font-size:14px;">${marker}<span>${name}</span><br/><span style="padding-left:14px;">${value} 台 (${percent}%)</span></div>`
}

const chartOption = computed(() => ({
  color: palette,
  tooltip: {
    trigger: 'item',
    backgroundColor: '#fff',
    borderColor: '#e8edf5',
    borderWidth: 1,
    padding: [8, 10],
    textStyle: {
      color: '#172033',
      fontSize: 14
    },
    extraCssText: 'box-shadow: 0 10px 24px rgba(15, 23, 42, 0.12); border-radius: 10px;',
    formatter: formatTooltip
  },
  series: [
    {
      type: 'pie',
      radius: ['56%', '90%'],
      center: ['50%', '50%'],
      minAngle: 8,
      avoidLabelOverlap: true,
      stillShowZeroSum: false,
      label: { show: false },
      labelLine: { show: false },
      itemStyle: {
        borderWidth: 0
      },
      emphasis: {
        scale: true,
        scaleSize: 4,
        itemStyle: {
          shadowBlur: 10,
          shadowColor: 'rgba(15, 23, 42, 0.14)'
        }
      },
      data: chartData.value
    }
  ]
}))

const renderChart = () => {
  if (!chartRef.value) return
  if (props.loading || chartData.value.length === 0) {
    chart?.clear()
    return
  }
  if (!chart) {
    chart = echarts.init(chartRef.value, undefined, { renderer: 'canvas' })
  }
  chart.setOption(chartOption.value, true)
}

watch(
  () => [props.loading, props.data],
  () => nextTick(renderChart),
  { deep: true, immediate: true }
)

onMounted(() => {
  nextTick(renderChart)
  if (chartRef.value) {
    resizeObserver = new ResizeObserver(() => chart?.resize())
    resizeObserver.observe(chartRef.value)
  }
})

onBeforeUnmount(() => {
  resizeObserver?.disconnect()
  chart?.dispose()
  chart = null
})
</script>

<template>
  <section class="device-status-card">
    <div class="card-header">
      <div>
        <h3>设备状态</h3>
      </div>
      <span class="soft-badge">{{ chartData.length }} 类</span>
    </div>

    <div class="status-body">
      <div class="chart-wrap">
        <div v-show="chartData.length > 0 && !loading" ref="chartRef" class="chart-el"></div>
        <div v-if="chartData.length === 0 || loading" class="empty-state">
          {{ loading ? '加载中...' : '暂无状态数据' }}
        </div>
        <div v-if="chartData.length > 0 && !loading" class="chart-center">
          <span>合计</span>
          <strong>{{ total }}</strong>
        </div>
      </div>

      <div class="legend-list">
        <div v-for="(item, index) in legendItems" :key="item.name" class="legend-item">
          <span
            class="legend-dot"
            :style="{ backgroundColor: palette[index % palette.length] }"></span>
          <span class="legend-name">{{ item.name }}</span>
          <strong>{{ item.value }}</strong>
        </div>
      </div>
    </div>
  </section>
</template>

<style scoped lang="scss">
.device-status-card {
  position: relative;
  min-width: 0;
  min-height: 164px;
  padding: 12px 14px 10px;
  overflow: hidden;
  background: #fff;
  border: 1px solid #e8edf5;
  border-radius: 16px;
  box-shadow: 0 10px 26px rgb(15 23 42 / 8%);
  container-type: inline-size;
}

.device-status-card::before,
.device-status-card::after {
  position: absolute;
  pointer-events: none;
  border-radius: 999px;
  content: '';
}

.device-status-card::before {
  top: -50px;
  left: -34px;
  width: 118px;
  height: 118px;
  background: rgb(53 205 178 / 10%);
}

.device-status-card::after {
  right: -38px;
  bottom: -46px;
  width: 126px;
  height: 126px;
  background: rgb(22 136 245 / 8%);
  border: 1px solid rgb(22 136 245 / 10%);
}

.card-header,
.status-body,
.legend-item {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
}

.card-header {
  justify-content: space-between;
}

h3 {
  margin: 0;
  font-size: 16px;
  font-weight: 700;
  color: #25324a;
}

.soft-badge {
  padding: 5px 11px;
  font-size: 12px;
  color: #1688f5;
  background: #edf7ff;
  border: 1px solid #d8ecff;
  border-radius: 999px;
}

.status-body {
  display: grid;
  margin-top: 6px;
  grid-template-columns: minmax(240px, 1fr) minmax(300px, 330px);
  gap: 10px;
}

.chart-wrap {
  position: relative;
  min-width: 0;
}

.chart-el,
.empty-state {
  height: 168px;
}

.chart-center {
  position: absolute;
  top: 50%;
  left: 50%;
  display: flex;
  font-size: 12px;
  color: #8b98ac;
  pointer-events: none;
  transform: translate(-50%, -50%);
  flex-direction: column;
  align-items: center;
}

.chart-center strong {
  margin-top: 3px;
  font-size: 18px;
  line-height: 1;
  color: #25324a;
}

.legend-list {
  display: grid;
  width: min(100%, 330px);
  max-height: 168px;
  min-width: 0;
  padding-right: 4px;
  overflow: auto;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 7px 8px;
  justify-self: end;
}

.legend-item {
  min-width: 0;
  padding: 0;
  font-size: 12px;
  color: #526178;
  background: transparent;
  border: 0;
}

.legend-dot {
  width: 9px;
  height: 9px;
  margin-right: 6px;
  border-radius: 50%;
  flex: none;
}

.legend-name {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  flex: 1;
}

.legend-item strong {
  min-width: 24px;
  margin-left: 6px;
  color: #172033;
  text-align: right;
}

.empty-state {
  display: flex;
  font-size: 13px;
  color: #9aa6b8;
  align-items: center;
  justify-content: center;
}

@container (max-width: 620px) {
  .status-body {
    grid-template-columns: minmax(220px, 1fr) minmax(150px, 176px);
  }

  .legend-list {
    width: min(100%, 176px);
    grid-template-columns: minmax(0, 1fr);
  }
}

@media (width <= 1440px) {
  .status-body {
    grid-template-columns: minmax(190px, 1fr) minmax(132px, 156px);
  }

  .legend-list {
    width: min(100%, 156px);
    grid-template-columns: minmax(0, 1fr);
  }
}
</style>
