<template>
  <div class="smart-chart-card" :class="{ 'is-horizontal': isHorizontalBar }">
    <div class="smart-chart-header">
      <div>
        <strong>{{ chart.title }}</strong>
        <span v-if="displaySubtitle">{{ displaySubtitle }}</span>
      </div>
      <em v-if="chart.unit">{{ chart.unit }}</em>
    </div>
    <v-chart class="smart-chart" :option="chartOption" autoresize />
    <div v-if="sourceText" class="smart-chart-source">{{ sourceText }}</div>
  </div>
</template>

<script setup>
import { computed, nextTick, onMounted } from "vue"
import * as echarts from "echarts"
import VChart from "vue-echarts"

const emit = defineEmits(["ready"])

const props = defineProps({
  chart: {
    type: Object,
    required: true,
  },
})

const palette = ["#30dcff", "#27f0c0", "#ffd76c", "#7aa7ff", "#ff8f6b", "#a6f06d"]
const scopeLabel = "\u53e3\u5f84"

const chartOption = computed(() => {
  const rows = (props.chart.rows || []).filter((row) => Number.isFinite(Number(row.value)))
  if (props.chart.type === "pie") return buildPieOption(rows)
  if (props.chart.type === "line") return buildLineOption(rows)
  return buildBarOption(rows)
})

const isHorizontalBar = computed(() => {
  const rows = props.chart.rows || []
  return props.chart.type === "bar" && shouldUseHorizontalBar(rows)
})

const displaySubtitle = computed(() => {
  const subtitle = normalizeSubtitle(props.chart.subtitle)
  if (subtitle) return subtitle

  const source = props.chart.source || {}
  const period = normalizeSourceMeta(source.period || source.dataPeriod || props.chart.period)
  const unit = props.chart.unit ? `单位：${props.chart.unit}` : ""
  return [period, unit].filter(Boolean).join(" · ")
})

const sourceText = computed(() => {
  const source = props.chart.source || {}
  const sourceLabel = getSourceLabel(source)
  const period = normalizeSourceMeta(source.period || source.dataPeriod || props.chart.period)
  const generatedAt = normalizeSourceMeta(source.generatedAt || source.updateTime || source.updatedAt, true)
  const parts = [sourceLabel, period, generatedAt ? `更新 ${generatedAt}` : ""].filter(Boolean)
  return parts.length ? `数据来源：${parts.join(" · ")}` : "数据来源：业务统计库"
})

onMounted(() => {
  nextTick(() => {
    window.requestAnimationFrame(() => emit("ready"))
  })
})

function buildBarOption(rows) {
  if (shouldUseHorizontalBar(rows)) return buildHorizontalBarOption(rows)

  return {
    animationDuration: 700,
    grid: {
      left: 52,
      right: 26,
      top: 28,
      bottom: 54,
    },
    tooltip: buildTooltip(),
    xAxis: {
      type: "category",
      data: rows.map((row) => row.name),
      axisTick: { show: false },
      axisLine: { lineStyle: { color: "rgba(48, 220, 255, 0.28)" } },
      axisLabel: {
        color: "rgba(223, 250, 255, 0.76)",
        fontSize: 11,
        interval: 0,
        rotate: rows.length > 6 ? 28 : 0,
      },
    },
    yAxis: {
      type: "value",
      axisLine: { show: false },
      axisTick: { show: false },
      splitLine: { lineStyle: { color: "rgba(48, 220, 255, 0.1)", type: "dashed" } },
      axisLabel: {
        color: "rgba(223, 250, 255, 0.58)",
        fontSize: 11,
      },
    },
    series: [
      {
        name: props.chart.title,
        type: "bar",
        barWidth: rows.length > 7 ? 16 : 22,
        data: rows.map((row, index) => ({
          value: row.value,
          name: row.name,
          itemStyle: {
            borderRadius: [8, 8, 0, 0],
            color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
              { offset: 0, color: palette[index % palette.length] },
              { offset: 1, color: "rgba(48, 220, 255, 0.08)" },
            ]),
          },
        })),
        label: {
          show: true,
          position: "top",
          color: "#ffffff",
          fontSize: 11,
          formatter: ({ value }) => formatValue(value),
        },
      },
    ],
  }
}

function buildHorizontalBarOption(rows) {
  return {
    animationDuration: 700,
    grid: {
      left: 78,
      right: 72,
      top: 22,
      bottom: 20,
    },
    tooltip: {
      ...buildTooltip(),
      trigger: "axis",
      axisPointer: { type: "shadow" },
    },
    xAxis: {
      type: "value",
      axisLine: { show: false },
      axisTick: { show: false },
      splitLine: { lineStyle: { color: "rgba(48, 220, 255, 0.1)", type: "dashed" } },
      axisLabel: {
        color: "rgba(223, 250, 255, 0.58)",
        fontSize: 11,
      },
    },
    yAxis: {
      type: "category",
      inverse: true,
      data: rows.map((row) => row.name),
      axisTick: { show: false },
      axisLine: { lineStyle: { color: "rgba(48, 220, 255, 0.22)" } },
      axisLabel: {
        color: "rgba(223, 250, 255, 0.82)",
        fontSize: 12,
      },
    },
    series: [
      {
        name: props.chart.title,
        type: "bar",
        barWidth: 13,
        data: rows.map((row, index) => ({
          value: row.value,
          name: row.name,
          itemStyle: {
            borderRadius: [0, 8, 8, 0],
            color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [
              { offset: 0, color: "rgba(48, 220, 255, 0.16)" },
              { offset: 1, color: palette[index % palette.length] },
            ]),
          },
        })),
        label: {
          show: true,
          position: "right",
          color: "#ffffff",
          fontSize: 11,
          formatter: ({ value }) => formatValue(value),
        },
      },
    ],
  }
}

function buildPieOption(rows) {
  return {
    animationDuration: 700,
    tooltip: buildTooltip(),
    legend: {
      orient: "vertical",
      right: 10,
      top: "middle",
      itemWidth: 10,
      itemHeight: 10,
      textStyle: {
        color: "rgba(223, 250, 255, 0.78)",
        fontSize: 11,
      },
    },
    series: [
      {
        name: props.chart.title,
        type: "pie",
        radius: ["48%", "68%"],
        center: ["35%", "52%"],
        avoidLabelOverlap: true,
        label: {
          color: "#fff",
          fontSize: 11,
          formatter: "{b}\n{d}%",
        },
        labelLine: {
          lineStyle: { color: "rgba(223, 250, 255, 0.42)" },
        },
        itemStyle: {
          borderColor: "rgba(3, 18, 31, 0.92)",
          borderWidth: 3,
        },
        data: rows.map((row, index) => ({
          name: row.name,
          value: row.value,
          itemStyle: { color: palette[index % palette.length] },
        })),
      },
    ],
  }
}

function buildLineOption(rows) {
  return {
    animationDuration: 760,
    grid: {
      left: 52,
      right: 28,
      top: 30,
      bottom: 48,
    },
    tooltip: {
      ...buildTooltip(),
      trigger: "axis",
      axisPointer: {
        type: "line",
        lineStyle: { color: "rgba(255, 215, 108, 0.52)" },
      },
    },
    xAxis: {
      type: "category",
      boundaryGap: false,
      data: rows.map((row) => row.name),
      axisTick: { show: false },
      axisLine: { lineStyle: { color: "rgba(48, 220, 255, 0.28)" } },
      axisLabel: {
        color: "rgba(223, 250, 255, 0.76)",
        fontSize: 11,
        interval: 0,
      },
    },
    yAxis: {
      type: "value",
      axisLine: { show: false },
      axisTick: { show: false },
      splitLine: { lineStyle: { color: "rgba(48, 220, 255, 0.1)", type: "dashed" } },
      axisLabel: {
        color: "rgba(223, 250, 255, 0.58)",
        fontSize: 11,
      },
    },
    series: [
      {
        name: props.chart.title,
        type: "line",
        smooth: true,
        symbol: "circle",
        symbolSize: 8,
        lineStyle: {
          width: 3,
          color: "#30dcff",
        },
        itemStyle: {
          color: "#ffd76c",
          borderColor: "#041522",
          borderWidth: 2,
        },
        areaStyle: {
          color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
            { offset: 0, color: "rgba(48, 220, 255, 0.24)" },
            { offset: 1, color: "rgba(48, 220, 255, 0.02)" },
          ]),
        },
        label: {
          show: true,
          position: "top",
          color: "#ffffff",
          fontSize: 11,
          formatter: ({ value }) => formatValue(value),
        },
        data: rows.map((row) => ({
          value: row.value,
          name: row.name,
        })),
      },
    ],
  }
}

function buildTooltip() {
  return {
    trigger: "item",
    backgroundColor: "rgba(2, 13, 22, 0.94)",
    borderColor: "rgba(48, 220, 255, 0.34)",
    borderWidth: 1,
    textStyle: {
      color: "#fff",
      fontSize: 12,
    },
    formatter: (params) => {
      const row = (props.chart.rows || []).find((item) => item.name === params.name)
      const unit = row?.unit || props.chart.unit || ""
      const extra = row?.extra ? `<br/><span style="color:rgba(223,250,255,.62)">${row.extra}</span>` : ""
      return `${params.marker}${params.name}: ${formatValue(params.value)}${unit}${extra}`
    },
  }
}

function shouldUseHorizontalBar(rows = []) {
  return rows.length > 6 || rows.some((row) => String(row.name || "").length > 4)
}

function getSourceLabel(source = {}) {
  const sourceName = normalizeSourceMeta(source.sourceName || source.name || source.label)
  if (sourceName) return sourceName
  const mode = String(source.mode || "").trim()
  if (/openapi|api|stat/i.test(mode)) return "业务统计库"
  if (/local|mock|fallback/i.test(mode)) return "本地统计"
  return "业务统计库"
}

function normalizeSourceMeta(value, dateOnly = false) {
  const text = String(value || "").trim()
  if (!text) return ""
  if (dateOnly && /^\d{4}-\d{2}-\d{2}/.test(text)) return text.slice(0, 10)
  if (isTechnicalSourceText(text)) return ""
  return text
}

function normalizeSubtitle(value) {
  const text = String(value || "").trim()
  if (!text) return ""

  const scopePattern = new RegExp(scopeLabel, "g")
  const statScopePattern = new RegExp(`统计${scopeLabel}`, "g")
  const cleaned = text
    .replace(statScopePattern, "统计数据")
    .replace(scopePattern, "数据")
    .replace(/来源[：:]\s*openApi\s*统计库\s*[a-zA-Z0-9_./:-]*[，,、]?\s*/gi, "")
    .replace(/openApi\s*统计库\s*/gi, "")
    .replace(/\b[a-zA-Z][a-zA-Z0-9]*(?:_[a-zA-Z0-9]+){2,}\b/g, "")
    .replace(/[，,、]\s*[，,、]+/g, "，")
    .replace(/^[\s，,、:：]+|[\s，,、]+$/g, "")

  if (!cleaned || /^来源[：:]?$/.test(cleaned) || isTechnicalSourceText(cleaned)) return ""
  return cleaned
}

function isTechnicalSourceText(text) {
  return /^[a-zA-Z0-9_./:-]+$/.test(text) && (text.includes("_") || text.length > 24)
}

function formatValue(value) {
  const number = Number(value)
  if (!Number.isFinite(number)) return "--"
  return Number.isInteger(number) ? number.toLocaleString("zh-CN") : number.toLocaleString("zh-CN", { maximumFractionDigits: 2 })
}
</script>

<style lang="scss">
.smart-chart-card {
  width: min(620px, 100%);
  height: 292px;
  margin-top: 12px;
  box-sizing: border-box;
  border: 1px solid rgba(48, 220, 255, 0.24);
  background:
    linear-gradient(135deg, rgba(6, 37, 50, 0.86), rgba(4, 19, 32, 0.82)),
    radial-gradient(circle at 22% 8%, rgba(48, 220, 255, 0.12), transparent 34%);
  box-shadow: inset 0 0 28px rgba(48, 220, 255, 0.08), 0 14px 32px rgba(0, 0, 0, 0.22);
}

.smart-chart-header {
  height: 52px;
  padding: 10px 14px 0;
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  box-sizing: border-box;
}

.smart-chart-header strong {
  display: block;
  color: #fff;
  font-size: 16px;
  line-height: 1.2;
}

.smart-chart-header span {
  display: block;
  margin-top: 5px;
  color: rgba(223, 250, 255, 0.58);
  font-size: 12px;
}

.smart-chart-header em {
  padding: 3px 9px;
  border: 1px solid rgba(255, 215, 108, 0.3);
  color: #ffd76c;
  font-style: normal;
  font-size: 12px;
  background: rgba(255, 215, 108, 0.08);
}

.smart-chart {
  width: 100%;
  height: 216px;
}

.smart-chart-source {
  height: 22px;
  padding: 0 14px;
  box-sizing: border-box;
  color: rgba(223, 250, 255, 0.48);
  font-size: 11px;
  line-height: 18px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
</style>
