import { normalizeResponseData, requestJson } from "./request"
import { getWfsFeatureProperties } from "./geoserver"
import { getLayerByKey as getLayerByKeyForRanking } from "@/config/layers"
import { getHongyuanTownshipNameByCode, hongyuanTownshipDisplayOrder } from "@/config/townshipBoundaries"

const OPEN_API_BASE = import.meta.env.VITE_OPEN_API_BASE || "/openApi"
const CXPT_GRASSLAND_AREA_WAN_MU = 756.37
const CXPT_WETLAND_AREA_WAN_MU = 291.82
const HONGYUAN_TOWN_DISPLAY_ORDER = hongyuanTownshipDisplayOrder.map(normalizeTownName)
const WETLAND_CHART_PALETTE = ["#32DCFF", "#24F6C4", "#6EA8FF", "#FFE06B", "#7EE269", "#9EA7FF"]
const WOODLAND_CHART_PALETTE = ["#2BD17E", "#8AE611", "#24F6C4", "#FFE06B", "#32DCFF", "#9EA7FF"]

function joinBase(path) {
  if (/^https?:\/\//.test(path)) return path
  return `${OPEN_API_BASE}${path.startsWith("/") ? path : `/${path}`}`
}

function post(path, body) {
  return requestJson(joinBase(path), {
    method: "POST",
    body: body ? JSON.stringify(body) : undefined,
    headers: {
      "Content-Type": "application/json",
    },
  })
}

function get(path, params) {
  return requestJson(joinBase(path), { params })
}

function pickValue(item, keys) {
  for (const key of keys) {
    if (item?.[key] !== undefined && item?.[key] !== null && item?.[key] !== "") {
      return item[key]
    }
  }
  return undefined
}

function toNumber(value) {
  if (value === undefined || value === null || value === "") return undefined
  const number = Number(value)
  return Number.isNaN(number) ? undefined : number
}

function formatNumber(value) {
  const number = toNumber(value)
  if (number === undefined) return undefined
  return Number.isInteger(number) ? number : Number(number.toFixed(2))
}

function normalizeAreaPartsToTotal(total, primary, secondary) {
  const totalNumber = toNumber(total)
  const primaryNumber = toNumber(primary)
  const secondaryNumber = toNumber(secondary)
  if (totalNumber === undefined || primaryNumber === undefined || secondaryNumber === undefined) {
    return [formatNumber(primary), formatNumber(secondary)]
  }
  const sourceTotal = primaryNumber + secondaryNumber
  if (!sourceTotal) return [0, 0]
  const normalizedPrimary = formatNumber((primaryNumber / sourceTotal) * totalNumber)
  return [normalizedPrimary, formatNumber(Math.max(totalNumber - normalizedPrimary, 0))]
}

function percentOf(value, total) {
  const number = toNumber(value)
  const totalNumber = toNumber(total)
  if (number === undefined || totalNumber === undefined || totalNumber === 0) return undefined
  return (number / totalNumber) * 100
}

function formatPercentExtra(row, total, label = "占比") {
  const percent = formatNumber(
    pickValue(row, ["areaPercent", "area_percent", "percent"]) ??
      percentOf(pickValue(row, ["areaWanMu", "value"]), total)
  )
  return percent === undefined ? "" : `${label} ${percent}%`
}

function formatRowPercentExtra(row, label = "") {
  const percent = formatNumber(pickValue(row, ["areaPercent", "area_percent", "percent"]))
  return percent === undefined ? "" : `${label}${percent}%`
}

function normalizeMetricItem(item, index = 0) {
  const name = pickValue(item, ["name", "title", "label", "zh", "itemName", "item_name"]) || `指标${index + 1}`
  const value = formatNumber(pickValue(item, ["value", "num", "count", "area", "acreage", "total"]))
  const unit = pickValue(item, ["unit", "unitName", "unit_name"]) || ""
  return {
    key: pickValue(item, ["id", "key", "code"]) || `${name}-${index}`,
    name,
    value,
    unit,
    source: item,
  }
}

function normalizeDataItems(data) {
  const rows = Array.isArray(data) ? data : data?.rows || data?.list || []
  return rows.map(normalizeMetricItem).filter((item) => item.name)
}

function normalizeWoodlandDistribution(data) {
  const core = data?.core || data?.summary || data || {}
  const mainType = (data?.typeDistribution || data?.typeStats || [])[0] || {}
  const mainEcology = (data?.ecologicalPosition || [])[0] || {}
  return [
    {
      key: "woodland-area",
      name: "林地总面积",
      value: formatNumber(pickValue(core, ["totalAreaWanMu", "total_area_wan_mu", "areaWanMu", "area_wan_mu"])),
      unit: "万亩",
    },
    {
      key: "woodland-main-type-rate",
      name: `${pickValue(mainType, ["name"]) || "主导类型"}占比`,
      value: formatNumber(pickValue(mainType, ["areaPercent", "area_percent", "percent"])),
      unit: "%",
    },
    {
      key: "woodland-ecology-area",
      name: "生态重点区面积",
      value: formatNumber(pickValue(mainEcology, ["areaWanMu", "value"])),
      unit: "万亩",
    },
  ]
}

function normalizeBasicGrassland(data) {
  const overview = data?.overview || data?.summary || data || {}
  const unit = pickValue(overview, ["areaUnit", "area_unit"]) || "万亩"
  const [basicArea, generalArea] = normalizeAreaPartsToTotal(
    CXPT_GRASSLAND_AREA_WAN_MU,
    pickValue(overview, ["basicAreaWanMu", "basic_area_wan_mu", "basicArea", "basic_area"]),
    pickValue(overview, ["generalAreaWanMu", "general_area_wan_mu", "generalArea", "general_area"]),
  )
  return [
    {
      key: "grassland-total-area",
      name: "草地面积",
      value: CXPT_GRASSLAND_AREA_WAN_MU,
      unit,
    },
    {
      key: "basic-grassland-area",
      name: "基本草原",
      value: basicArea,
      unit,
    },
    {
      key: "general-grassland-area",
      name: "一般草原",
      value: generalArea,
      unit,
    },
  ]
}

function ensureCoreShape(items, topicKey) {
  const presets = {
    woodland: [
      { key: "woodland-area", name: "林地总面积", unit: "万亩" },
      { key: "woodland-public-area", name: "公益林面积", unit: "万亩" },
      { key: "woodland-public-rate", name: "公益林占比", unit: "%" },
    ],
    grassland: [
      { key: "grassland-area", name: "草地面积", unit: "万亩" },
      { key: "basic-grassland", name: "基本草原", unit: "万亩" },
      { key: "general-grassland", name: "一般草原", unit: "万亩" },
    ],
    wetland: [
      { key: "wetland-area", name: "湿地面积", unit: "万亩" },
      { key: "wetland-yield", name: "湿地生产力", unit: "万吨" },
      { key: "wetland-level-1-area", name: "1级湿地面积", unit: "万亩" },
    ],
  }
  const base = presets[topicKey] || []
  const merged = base.map((preset, index) => ({
    ...preset,
    ...(items[index] || {}),
    name: items[index]?.name || preset.name,
    unit: items[index]?.unit || preset.unit,
  }))
  if (topicKey === "wetland" && merged[0]) {
    merged[0] = {
      ...merged[0],
      key: merged[0].key || "wetland-area",
      name: "湿地面积",
      value: CXPT_WETLAND_AREA_WAN_MU,
      unit: merged[0].unit || "万亩",
    }
  }
  return merged.length ? merged : items
}

async function tryRequests(requests) {
  let lastError
  for (const request of requests) {
    try {
      return await request()
    } catch (error) {
      lastError = error
    }
  }
  throw lastError || new Error("No request configured")
}

function normalizeRankRows(rows = [], options = {}) {
  const {
    nameKeys = ["name", "townName", "typeName"],
    valueKeys = ["areaWanMu", "value", "totalAreaWanMu", "basicAreaWanMu"],
    unit = "万亩",
    max = Number.POSITIVE_INFINITY,
    extra,
  } = options
  const normalized = rows.map((row, index) => {
    const value = formatNumber(pickValue(row, valueKeys))
    const item = {
      key: pickValue(row, ["key", "code", "townCode"]) || `${pickValue(row, nameKeys) || index}-${index}`,
      name: pickValue(row, nameKeys) || `第${index + 1}项`,
      value,
      unit,
      percent: formatNumber(pickValue(row, ["percent", "areaPercent", "basicRatio", "generalRatio"])),
      source: row,
    }
    return extra ? { ...item, extra: extra(row) } : item
  }).sort((a, b) => (Number(b.value) || 0) - (Number(a.value) || 0))
  return Number.isFinite(max) ? normalized.slice(0, max) : normalized
}

function normalizeMetricRows(rows = [], options = {}) {
  const { nameKeys = ["name"], valueKeys = ["value"], unit, max = Number.POSITIVE_INFINITY, extra } = options
  return normalizeRankRows(rows, {
    nameKeys,
    valueKeys,
    unit,
    max,
    extra,
  })
}

function normalizeMuRows(rows = [], options = {}) {
  const { nameKeys = ["grassMinType", "name"], valueKeys = ["acreage"], unit = "万亩", max = Number.POSITIVE_INFINITY } = options
  const normalized = rows.map((row, index) => {
    const rawValue = pickValue(row, valueKeys)
    const value = formatNumber(unit === "万亩" ? toNumber(rawValue) / 10000 : rawValue)
    const name = pickValue(row, nameKeys) || `第${index + 1}项`
    return {
      key: pickValue(row, ["key", "code"]) || `${name}-${index}`,
      name,
      value,
      unit,
      source: row,
    }
  }).filter((row) => Number(row.value) > 0)
    .sort((a, b) => (Number(b.value) || 0) - (Number(a.value) || 0))
  return Number.isFinite(max) ? normalized.slice(0, max) : normalized
}

function buildPanel(key, title, rows, type = "rank", options = {}) {
  return {
    key,
    title,
    type,
    rows: rows || [],
    ...options,
  }
}

function normalizeYieldRows(yieldRows = [], muYieldRows = [], options = {}) {
  const { unit = "万吨", max = Number.POSITIVE_INFINITY, showMuYieldExtra = true } = options
  const muYieldByTown = new Map(muYieldRows.map((row) => [row.areaName, row]))
  return normalizeRankRows(yieldRows, {
    nameKeys: ["areaName", "name"],
    valueKeys: ["yield", "value"],
    unit,
    max,
    extra: (row) => {
      const muYield = muYieldByTown.get(row.areaName)
      const value = formatNumber(pickValue(muYield, ["yield", "value"]))
      const muUnit = pickValue(muYield, ["unit"]) || "斤"
      return showMuYieldExtra && value !== undefined ? `亩产 ${value} ${muUnit}` : ""
    },
  })
}

function normalizeTownName(name) {
  return String(name || "").replace(/\s+/g, "").trim()
}

function sortRowsByTownDisplayOrder(rows = []) {
  const orderMap = new Map(HONGYUAN_TOWN_DISPLAY_ORDER.map((name, index) => [name, index]))
  return [...rows].sort((a, b) => {
    const orderA = orderMap.get(normalizeTownName(a?.name))
    const orderB = orderMap.get(normalizeTownName(b?.name))
    if (orderA !== undefined && orderB !== undefined) return orderA - orderB
    if (orderA !== undefined) return -1
    if (orderB !== undefined) return 1
    return 0
  })
}

function normalizeGrasslandTypeName(name) {
  const value = String(name || "")
  const aliases = {
    用于畜牧业生产的人工草地: "人工草地",
    "对调节气候、涵养水源、保持水土、防风固沙具有特殊作用的草原": "生态调节草原",
    国家重点保护野生动植物生存环境的草原: "野生动植物栖息草原",
    "草原科研、教学实验基地": "科研教学草原",
  }
  return aliases[value] || value
}

function normalizeGrasslandTypeSignal(name) {
  return normalizeGrasslandTypeName(name).replace(/\s+/g, "").replace(/类$/, "")
}

function normalizeLevelSignal(value) {
  const text = String(value || "")
  const keyMatch = text.match(/level-([1-8])/)
  if (keyMatch) return keyMatch[1]
  const levelMatch = text.match(/([1-8])\s*级/)
  if (levelMatch) return levelMatch[1]
  if (/^[1-8]$/.test(text.trim())) return text.trim()
  const chineseDigits = {
    一: "1",
    二: "2",
    三: "3",
    四: "4",
    五: "5",
    六: "6",
    七: "7",
    八: "8",
  }
  const chineseMatch = Object.entries(chineseDigits).find(([label]) => text.includes(`${label}级`))
  return chineseMatch?.[1] || ""
}

function getLegendLevelSignal(legend) {
  return normalizeLevelSignal(legend?.key) || normalizeLevelSignal(legend?.name)
}

function normalizeTownRankingRows(rows = [], options = {}) {
  const {
    nameKeys = ["name", "townName", "areaName"],
    valueKeys = ["areaWanMu", "value", "totalAreaWanMu", "yield"],
    unit = "万亩",
  } = options
  return rows
    .map((row, index) => {
      const name = normalizeTownName(pickValue(row, nameKeys))
      const value = formatNumber(pickValue(row, valueKeys))
      if (!name || value === undefined) return null
      return {
        key: pickValue(row, ["key", "code", "townCode"]) || `${name}-${index}`,
        name,
        value,
        unit: pickValue(row, ["unit"]) || unit,
        source: row,
      }
    })
    .filter(Boolean)
    .sort((a, b) => (Number(b.value) || 0) - (Number(a.value) || 0))
}

function aggregateTownRankingRows(rows = [], options = {}) {
  const {
    nameKeys = ["townName", "name", "areaName"],
    valueKeys = ["areaWanMu", "value", "totalAreaWanMu", "yield"],
    unit = "万亩",
  } = options
  const grouped = new Map()
  rows.forEach((row) => {
    const name = normalizeTownName(pickValue(row, nameKeys))
    const value = toNumber(pickValue(row, valueKeys))
    if (!name || value === undefined) return
    const current = grouped.get(name) || {
      key: pickValue(row, ["townCode", "code"]) || name,
      name,
      value: 0,
      unit: pickValue(row, ["unit"]) || unit,
      source: [],
    }
    current.value += value
    current.source.push(row)
    grouped.set(name, current)
  })
  return Array.from(grouped.values())
    .map((row) => ({
      ...row,
      value: formatNumber(row.value),
    }))
    .sort((a, b) => (Number(b.value) || 0) - (Number(a.value) || 0))
}

function buildTownRanking({ topicKey, layerKey, title, unit = "万亩", rows = [], note = "", metricLabel = "" }) {
  const rankedRows = rows
    .filter((row) => row?.name && row.value !== undefined)
    .sort((a, b) => (Number(b.value) || 0) - (Number(a.value) || 0))
    .map((row, index) => ({
      ...row,
      unit: row.unit || unit,
      rank: index + 1,
    }))
  return {
    status: rankedRows.length ? "success" : "empty",
    topicKey,
    layerKey,
    title,
    unit,
    metricLabel,
    note,
    rows: rankedRows,
  }
}

async function getWfsTownAreaRanking({ topicKey, layerKey, layerName, title, cqlFilter = "", unit = "万亩" }) {
  const data = await getWfsFeatureProperties(layerName, {
    propertyName: ["xiang", "acreage"],
    cqlFilter,
    maxFeatures: 200000,
  })
  const grouped = new Map()
  ;(data?.features || []).forEach((feature) => {
    const properties = feature.properties || {}
    const townCode = String(properties.xiang || "")
    const name = getHongyuanTownshipNameByCode(townCode)
    const acreage = toNumber(properties.acreage)
    if (!name || acreage === undefined) return
    const current = grouped.get(name) || {
      key: townCode,
      name,
      value: 0,
      unit,
    }
    current.value += acreage / 10000
    grouped.set(name, current)
  })
  return buildTownRanking({
    topicKey,
    layerKey,
    title,
    unit,
    rows: Array.from(grouped.values()).map((row) => ({
      ...row,
      value: formatNumber(row.value),
    })),
    note: "按 GeoServer 图斑属性汇总到乡镇",
  })
}

async function getWoodlandAreaRanking(topicKey, layerKey, title = "林地面积排行") {
  const data = normalizeResponseData(await post("/woodland/distribution"))
  return buildTownRanking({
    topicKey,
    layerKey,
    title,
    unit: "万亩",
    rows: normalizeTownRankingRows(data?.areaDistribution || [], {
      nameKeys: ["name"],
      valueKeys: ["areaWanMu", "value"],
      unit: "万亩",
    }),
  })
}

async function getGrasslandAreaRanking(topicKey, layerKey, valueKey, title) {
  const data = normalizeResponseData(await get("/basic_grassland/overview"))
  return buildTownRanking({
    topicKey,
    layerKey,
    title,
    unit: "万亩",
    rows: normalizeTownRankingRows(data?.townStats || [], {
      nameKeys: ["name"],
      valueKeys: [valueKey],
      unit: "万亩",
    }),
  })
}

function resolveTownName(properties = {}, townCodeKeys = [], townNameKeys = []) {
  const townName = pickValue(properties, townNameKeys)
  if (townName) return normalizeTownName(townName)
  const townCode = townCodeKeys
    .map((key) => pickValue(properties, [key]))
    .find((value) => value !== undefined)
  const normalizedCode = String(townCode || "").slice(0, 9)
  return getHongyuanTownshipNameByCode(normalizedCode)
}

async function getLegendWfsAreaRanking(topicKey, layerKey, layer, legend) {
  const townCodeKeys = legend?.rankingTownCodeKeys || layer?.rankingTownCodeKeys || ["area_code", "xiang", "town_code"]
  const townNameKeys = legend?.rankingTownNameKeys || layer?.rankingTownNameKeys || ["town_name", "area_name", "xiang_name"]
  const areaKeys = legend?.rankingAreaKeys || layer?.rankingAreaKeys || ["acreage", "area_mu", "area"]
  const propertyName = legend?.rankingPropertyName || [...townCodeKeys, ...townNameKeys, ...areaKeys]
  const data = await getWfsFeatureProperties(layer.layerName, {
    propertyName,
    cqlFilter: legend.cqlFilter,
    maxFeatures: 200000,
    timeout: 25000,
  })
  const grouped = new Map()
  ;(data?.features || []).forEach((feature) => {
    const properties = feature.properties || {}
    const name = resolveTownName(properties, townCodeKeys, townNameKeys)
    const acreage = toNumber(pickValue(properties, areaKeys))
    if (!name || acreage === undefined) return
    const current = grouped.get(name) || {
      key: name,
      name,
      value: 0,
      unit: "万亩",
    }
    current.value += acreage / 10000
    grouped.set(name, current)
  })
  return buildTownRanking({
    topicKey,
    layerKey,
    title: `${legend.name}面积排行`,
    unit: "万亩",
    metricLabel: legend.name,
    rows: Array.from(grouped.values()).map((row) => ({
      ...row,
      value: formatNumber(row.value),
      metricLabel: legend.name,
    })),
    note: "按选中图例过滤 GeoServer 图斑并汇总到乡镇",
  })
}

async function getBasicGrasslandLegendRanking(topicKey, layerKey, legend) {
  const data = normalizeResponseData(await get("/basic_grassland/overview"))
  return buildTownRanking({
    topicKey,
    layerKey,
    title: `${legend.name}面积排行`,
    unit: "万亩",
    metricLabel: legend.name,
    rows: normalizeTownRankingRows(data?.townStats || [], {
      nameKeys: ["name"],
      valueKeys: [legend.rankingValueKey],
      unit: "万亩",
    }).map((row) => ({
      ...row,
      metricLabel: legend.name,
    })),
  })
}

function buildLegendAreaRanking(topicKey, layerKey, legend, rows, options = {}) {
  const rankingRows = aggregateAreaWanMuRows(rows || [], options).map((row) => ({
    ...row,
    metricLabel: legend.name,
  }))
  return buildTownRanking({
    topicKey,
    layerKey,
    title: `${legend.name}面积排行`,
    unit: "万亩",
    metricLabel: legend.name,
    rows: rankingRows,
  })
}

async function getGrasslandLevelLegendRanking(topicKey, layerKey, legend) {
  const levelSignal = getLegendLevelSignal(legend)
  if (!levelSignal) return null
  const data = normalizeResponseData(await get("/grassland_grassland_level/distribution"))
  return buildLegendAreaRanking(topicKey, layerKey, legend, data, {
    nameKeys: ["areaName", "area_name", "name"],
    valueKeys: ["acreage", "areaWanMu", "value"],
    filter: (row) => normalizeLevelSignal(pickValue(row, ["level", "name"])) === levelSignal,
  })
}

async function getGrasslandTypeLegendRanking(topicKey, layerKey, legend) {
  const legendSignal = normalizeGrasslandTypeSignal(legend.name)
  if (!legendSignal) return null
  const [typeRows, minTypeRows] = await Promise.all([
    getOptionalData(async () => normalizeResponseData(await get("/grassland_grass_type/distribution"))),
    getOptionalData(async () => normalizeResponseData(await get("/grassland_grass_type/minTypeAreaDistribution"))),
  ])
  return buildLegendAreaRanking(topicKey, layerKey, legend, [...(typeRows || []), ...(minTypeRows || [])], {
    nameKeys: ["areaName", "area_name", "name"],
    valueKeys: ["acreage", "areaWanMu", "value"],
    filter: (row) => {
      const rowName = pickValue(row, ["grassMinType", "grass_min_type", "grassType", "grass_type", "name"])
      return normalizeGrasslandTypeSignal(rowName) === legendSignal
    },
  })
}

async function getWetlandLevelLegendRanking(topicKey, layerKey, legend) {
  const levelSignal = getLegendLevelSignal(legend)
  if (!levelSignal) return null
  const data = normalizeResponseData(await get("/wetland_grassland_level/distribution"))
  return buildLegendAreaRanking(topicKey, layerKey, legend, data, {
    nameKeys: ["areaName", "area_name", "name"],
    valueKeys: ["acreage", "areaWanMu", "value"],
    filter: (row) => normalizeLevelSignal(pickValue(row, ["level", "name"])) === levelSignal,
  })
}

async function getWetlandTypeLegendRanking(topicKey, layerKey, legend) {
  const legendSignal = normalizeGrasslandTypeSignal(legend.name)
  if (!legendSignal) return null
  const [typeRows, minTypeRows] = await Promise.all([
    getOptionalData(async () => normalizeResponseData(await get("/wetland_grass_type_copy/distribution"))),
    getOptionalData(async () => normalizeResponseData(await get("/wetland_grass_type_copy/minTypeAreaDistribution"))),
  ])
  return buildLegendAreaRanking(topicKey, layerKey, legend, [...(typeRows || []), ...(minTypeRows || [])], {
    nameKeys: ["areaName", "area_name", "name"],
    valueKeys: ["acreage", "areaWanMu", "value"],
    filter: (row) => {
      const rowName = pickValue(row, ["grassMinType", "grass_min_type", "grassType", "grass_type", "name"])
      return normalizeGrasslandTypeSignal(rowName) === legendSignal
    },
  })
}

async function getLegendTownRanking(topicKey, layerKey, legend) {
  if (!legend?.key) return null
  const layer = getLayerByKeyForRanking(topicKey, layerKey)
  if (!layer) return null
  if (topicKey === "grassland" && layerKey === "basic-grassland" && legend.rankingValueKey) {
    return getBasicGrasslandLegendRanking(topicKey, layerKey, legend)
  }
  if (topicKey === "grassland" && layerKey === "grassland-level") {
    return getGrasslandLevelLegendRanking(topicKey, layerKey, legend)
  }
  if (topicKey === "grassland" && layerKey === "grassland-type") {
    return getGrasslandTypeLegendRanking(topicKey, layerKey, legend)
  }
  if (topicKey === "wetland" && layerKey === "wetland-level") {
    return getWetlandLevelLegendRanking(topicKey, layerKey, legend)
  }
  if (topicKey === "wetland" && layerKey === "wetland-type") {
    return getWetlandTypeLegendRanking(topicKey, layerKey, legend)
  }
  if (legend.cqlFilter && layer.layerName) {
    return getLegendWfsAreaRanking(topicKey, layerKey, layer, legend)
  }
  return null
}

async function getYieldRanking(topicKey, layerKey, path, title, fallbackUnit = "万吨") {
  const rows = normalizeResponseData(await get(path))
  const unit = pickValue(rows?.[0], ["unit"]) || fallbackUnit
  return buildTownRanking({
    topicKey,
    layerKey,
    title,
    unit,
    rows: normalizeTownRankingRows(rows || [], {
      nameKeys: ["areaName", "name"],
      valueKeys: ["yield", "value"],
      unit,
    }),
  })
}

function rowsFromCore(items = []) {
  return items.map((item, index) => ({
    key: item.key || `${item.name}-${index}`,
    name: item.name,
    value: item.value,
    unit: item.unit,
  }))
}

function topRows(rows = [], count = 5) {
  return rows.slice(0, count)
}

function aggregateTailRows(rows = [], options = {}) {
  const { limit = 5, minPercent = 1, otherName = "其他类型" } = options
  const validRows = rows
    .filter((row) => row?.name && Number(row.value) > 0)
    .sort((a, b) => (Number(b.value) || 0) - (Number(a.value) || 0))
  const total = validRows.reduce((sum, row) => sum + (Number(row.value) || 0), 0)
  if (!total || validRows.length <= limit) return validRows
  const mainRows = []
  const tailRows = []
  validRows.forEach((row, index) => {
    const percent = percentOf(row.value, total)
    if (index < limit - 1 && (percent === undefined || percent >= minPercent)) {
      mainRows.push(row)
    } else {
      tailRows.push(row)
    }
  })
  if (!tailRows.length) return mainRows
  const tailValue = tailRows.reduce((sum, row) => sum + (Number(row.value) || 0), 0)
  return [
    ...mainRows,
    {
      key: `${otherName}-${tailRows.length}`,
      name: otherName,
      value: formatNumber(tailValue),
      unit: tailRows[0]?.unit || validRows[0]?.unit || "万亩",
      extra: `${formatNumber(percentOf(tailValue, total))}%`,
    },
  ]
}

function sumRowValues(rows = []) {
  return rows.reduce((sum, row) => sum + (Number(row.value) || 0), 0)
}

function withPercentExtra(rows = [], total = sumRowValues(rows), label = "") {
  return rows.map((row) => {
    const percent = formatNumber(percentOf(row.value, total))
    return {
      ...row,
      extra: percent === undefined ? row.extra : `${label}${percent}%`,
    }
  })
}

function colorRowsByPalette(rows = [], palette = []) {
  if (!palette.length) return rows
  return rows.map((row, index) => ({
    ...row,
    color: row?.color || row?.fillColor || palette[index % palette.length],
  }))
}

function hasPanelRows(panel) {
  return Array.isArray(panel?.rows) && panel.rows.length > 0
}

function fillPanelSlots(primaryPanels = [], fallbackPanels = [], count = 4) {
  const result = []
  const seen = new Set()
  const addPanel = (panel) => {
    if (!panel || seen.has(panel.key)) return
    seen.add(panel.key)
    result.push(panel)
  }
  const candidates = [...primaryPanels, ...fallbackPanels]
  candidates.filter(hasPanelRows).forEach(addPanel)
  candidates.filter((panel) => panel && !hasPanelRows(panel)).forEach(addPanel)
  return result.slice(0, count)
}

function clonePanelAs(panel, type, options = {}) {
  if (!panel) return panel
  return {
    ...panel,
    type,
    ...options,
  }
}

function diversifyPanelColumn(panels = []) {
  const preferredTypes = ["bar", "line", "donut", "column", "structure", "heat", "peak", "split"]
  const nextTypeMap = {
    bar: ["heat", "peak", "column", "structure"],
    line: ["bar", "column", "heat"],
    donut: ["structure", "split", "bar"],
    column: ["peak", "heat", "bar", "line"],
    structure: ["split", "donut", "bar"],
    heat: ["bar", "column", "structure"],
    peak: ["column", "bar", "line"],
    split: ["structure", "donut", "bar"],
  }
  const used = new Set()
  return panels.map((panel) => {
    if (!panel?.type || ["projectTable", "iconMetric", "metric", "spotlight", "rank", "table", "stackColumn"].includes(panel.type)) {
      return panel
    }
    const visualType = panel.type === "donut" && panel.variant === "ring" ? "donut-ring" : panel.type
    if (panel.fixedType) {
      used.add(visualType)
      return panel
    }
    if (!used.has(visualType)) {
      used.add(visualType)
      return panel
    }
    const nextType = (nextTypeMap[panel.type] || preferredTypes).find((type) => !used.has(type)) || panel.type
    used.add(nextType)
    return clonePanelAs(panel, nextType, { variant: nextType === panel.type ? panel.variant : undefined })
  })
}

function buildHeadTailRows(rows = [], options = {}) {
  const {
    headCount = 4,
    headName = "重点区域",
    tailName = "其他区域",
  } = options
  const validRows = rows.filter((row) => row?.name && Number(row.value) > 0)
  if (!validRows.length) return []
  const headRows = validRows.slice(0, headCount)
  const tailRows = validRows.slice(headCount)
  const buildGroupRow = (name, groupRows) => ({
    key: name,
    name,
    value: formatNumber(groupRows.reduce((sum, row) => sum + (Number(row.value) || 0), 0)),
    unit: groupRows[0]?.unit || validRows[0]?.unit || "万亩",
    extra: `${groupRows.length}项`,
  })
  return [
    buildGroupRow(headName, headRows),
    tailRows.length ? buildGroupRow(tailName, tailRows) : null,
  ].filter((row) => row && Number(row.value) > 0)
}

function createSummaryMetricRows(rows = [], options = {}) {
  const {
    labels = ["最大值", "平均值", "合计"],
    unit = rows[0]?.unit || "",
    precision = 2,
  } = options
  const values = rows.map((row) => Number(row.value)).filter((value) => !Number.isNaN(value))
  if (!values.length) return []
  const total = values.reduce((sum, value) => sum + value, 0)
  const maxRow = rows.reduce((max, row) => (Number(row.value) > Number(max?.value || 0) ? row : max), rows[0])
  const avg = total / values.length
  return [
    {
      key: "max",
      name: labels[0],
      value: formatNumber(maxRow?.value),
      unit: maxRow?.unit || unit,
      extra: maxRow?.name || "",
    },
    {
      key: "avg",
      name: labels[1],
      value: Number(avg.toFixed(precision)),
      unit,
      extra: `${rows.length}个乡镇`,
    },
    {
      key: "total",
      name: labels[2],
      value: Number(total.toFixed(precision)),
      unit,
      extra: "业务汇总",
    },
    {
      key: "count",
      name: labels[3] || "覆盖乡镇",
      value: rows.length,
      unit: "个",
      extra: "统计单元",
    },
  ]
}

function applyLayerPanelSelection(result, topicKey, layerKey) {
  if (!layerKey) return result
  const fallbackLayerKey = {
    grassland: "grassland-distribution",
    wetland: "wetland-distribution",
    woodland: "woodland-distribution",
  }[topicKey]
  const layerPanels = result?.layerPanels?.[layerKey] || result?.layerPanels?.[fallbackLayerKey]
  if (!layerPanels) return result
  const leftPanels = layerPanels.leftPanels?.length ? layerPanels.leftPanels : result.leftPanels
  const rightPanels = layerPanels.rightPanels?.length ? layerPanels.rightPanels : result.rightPanels
  return {
    ...result,
    activeLayerKey: layerKey || fallbackLayerKey,
    leftPanels,
    rightPanels,
    left: leftPanels?.[0] || result.left,
    right: rightPanels?.[0] || result.right,
  }
}

function normalizeAreaValueToWanMu(row, valueKeys = ["areaWanMu", "value", "acreage", "areaMu"]) {
  for (const key of valueKeys) {
    const value = pickValue(row, [key])
    const number = toNumber(value)
    if (number === undefined) continue
    const normalizedKey = String(key).toLowerCase()
    const unit = String(pickValue(row, ["unit", "areaUnit", "area_unit"]) || "")
    if (normalizedKey.includes("wanmu") || unit === "万亩") return number
    if (normalizedKey.includes("mu") || unit === "亩") return number / 10000
    return number
  }
  return undefined
}

function aggregateAreaWanMuRows(rows = [], options = {}) {
  const {
    nameKeys = ["name", "areaName", "townName"],
    valueKeys = ["areaWanMu", "value", "acreage", "areaMu"],
    nameTransform = (name) => name,
    filter,
    extra,
  } = options
  const grouped = new Map()
  rows.forEach((row) => {
    if (filter && !filter(row)) return
    const rawName = pickValue(row, nameKeys)
    const name = nameTransform(rawName, row)
    const value = normalizeAreaValueToWanMu(row, valueKeys)
    if (!name || value === undefined) return
    const current = grouped.get(name) || {
      key: pickValue(row, ["key", "code", "townCode"]) || name,
      name,
      value: 0,
      unit: "万亩",
      source: [],
    }
    current.value += value
    current.source.push(row)
    grouped.set(name, current)
  })
  return Array.from(grouped.values())
    .map((row) => {
      const normalized = {
        ...row,
        value: formatNumber(row.value),
      }
      return extra ? { ...normalized, extra: extra(normalized) } : normalized
    })
    .filter((row) => Number(row.value) > 0)
    .sort((a, b) => (Number(b.value) || 0) - (Number(a.value) || 0))
}

function normalizeWetlandLevelName(name) {
  return String(name || "").replace(/草原/g, "湿地")
}

function buildWetlandYieldCapacityRows(yieldSummary = {}, yieldRows = []) {
  const unit = yieldSummary?.unit || pickValue(yieldRows?.[0], ["unit"]) || "万吨"
  const total = toNumber(yieldSummary?.xc) ?? sumRowValues(yieldRows)
  const edible = toNumber(yieldSummary?.edibleXc)
  const unavailable = total !== undefined && edible !== undefined ? Math.max(total - edible, 0) : undefined
  return [
    {
      key: "wetland-yield-edible",
      name: "可食鲜草",
      value: formatNumber(edible),
      unit,
      extra: `${formatNumber(percentOf(edible, total))}%`,
    },
    {
      key: "wetland-yield-unavailable",
      name: "不可食鲜草",
      value: formatNumber(unavailable),
      unit,
      extra: `${formatNumber(percentOf(unavailable, total))}%`,
    },
  ].filter((row) => row.value !== undefined)
}

function buildWetlandDefaultPanels({
  yieldSummary,
  townAreaRows,
  typeRows,
  levelRows,
  yieldRows,
  minTypeRows,
  muYieldRows,
  edibleYieldRows,
  edibleMuRows,
  typeTownRows,
  levelTownRows,
  minTownRows,
}) {
  const townAreaPanel = buildPanel("wetland-town-area", "湿地面积分布", colorRowsByPalette(sortRowsByTownDisplayOrder(townAreaRows), WETLAND_CHART_PALETTE), "column", { span: 1, variant: "plain" })
  const typePanel = buildPanel("wetland-type", "湿地类型结构", colorRowsByPalette(typeRows, WETLAND_CHART_PALETTE), "donut", { span: 1 })
  const levelStructurePanel = buildPanel("wetland-level-proportion", "湿地级占比", colorRowsByPalette(withPercentExtra(levelRows), WETLAND_CHART_PALETTE), "donut", { span: 1, variant: "ring" })
  const minTypePanel = buildPanel("wetland-min-type", "湿地优势小类", colorRowsByPalette(topRows(minTypeRows, 6), WETLAND_CHART_PALETTE), "bar", { span: 1, variant: "raceBarNoWrap" })
  const yieldCapacityPanel = buildPanel("wetland-yield-capacity", "湿地产能结构", buildWetlandYieldCapacityRows(yieldSummary, yieldRows), "structure", { span: 1 })
  const yieldPanel = buildPanel("wetland-yield", "湿地生产力分布", sortRowsByTownDisplayOrder(yieldRows), "line", { span: 1, fixedType: true })
  const edibleYieldPanel = buildPanel("wetland-edible-yield", "可食鲜草产量", topRows(edibleYieldRows, hongyuanTownshipDisplayOrder.length), "column", { span: 1, variant: "slim" })
  const muYieldPanel = buildPanel("wetland-mu-yield", "湿地亩产效率", topRows(muYieldRows, hongyuanTownshipDisplayOrder.length), "heat", { span: 1, limit: hongyuanTownshipDisplayOrder.length })
  const levelPanel = buildPanel("wetland-level", "湿地级别面积", levelRows, "column", { span: 1 })
  const levelTownPanel = buildPanel("wetland-level-town", "1级湿地分布", topRows(levelTownRows, 6), "bar", { span: 1, variant: "distribution" })
  const typeTownPanel = buildPanel("wetland-type-town", "湿地类型乡镇分布", topRows(typeTownRows, 6), "bar", { span: 1, variant: "distribution" })
  const edibleMuPanel = buildPanel("wetland-edible-mu", "可食鲜草亩产", topRows(edibleMuRows, hongyuanTownshipDisplayOrder.length), "bar", { span: 1 })
  const minTownPanel = buildPanel("wetland-min-town", "优势小类乡镇分布", topRows(minTownRows, 6), "bar", { span: 1, variant: "distribution" })
  const leftPanels = diversifyPanelColumn([
    townAreaPanel,
    typePanel,
    levelStructurePanel,
    minTypePanel,
  ])
  const rightPanels = diversifyPanelColumn([
    edibleYieldPanel,
    yieldPanel,
    muYieldPanel,
    yieldCapacityPanel,
  ])
  return {
    leftPanels,
    rightPanels,
    left: leftPanels[0],
    right: rightPanels[0],
    layerPanels: buildWetlandLayerPanels({
      townAreaPanel,
      typePanel,
      yieldCapacityPanel,
      yieldPanel,
      levelPanel,
      levelTownPanel,
      muYieldPanel,
      levelStructurePanel,
      typeTownPanel,
      minTypePanel,
      edibleYieldPanel,
      edibleMuPanel,
      minTownPanel,
    }),
  }
}

function buildWetlandLayerPanels(panels = {}) {
  const {
    townAreaPanel,
    typePanel,
    yieldCapacityPanel,
    yieldPanel,
    levelPanel,
    levelTownPanel,
    muYieldPanel,
    levelStructurePanel,
    typeTownPanel,
    minTypePanel,
    edibleYieldPanel,
    edibleMuPanel,
    minTownPanel,
  } = panels
  return {
    "wetland-distribution": {
      leftPanels: diversifyPanelColumn([townAreaPanel, typePanel, levelStructurePanel, minTypePanel].filter(Boolean)),
      rightPanels: diversifyPanelColumn([edibleYieldPanel, yieldPanel, muYieldPanel, yieldCapacityPanel].filter(Boolean)),
    },
    "wetland-level": {
      leftPanels: diversifyPanelColumn([levelStructurePanel, levelPanel, levelTownPanel, typePanel].filter(Boolean)),
      rightPanels: diversifyPanelColumn([edibleYieldPanel, yieldPanel, muYieldPanel, yieldCapacityPanel].filter(Boolean)),
    },
    "wetland-type": {
      leftPanels: diversifyPanelColumn([typePanel, typeTownPanel, minTypePanel, minTownPanel].filter(Boolean)),
      rightPanels: diversifyPanelColumn([edibleYieldPanel, yieldPanel, edibleMuPanel, yieldCapacityPanel].filter(Boolean)),
    },
    "wetland-yield": {
      leftPanels: diversifyPanelColumn([townAreaPanel, typePanel, levelStructurePanel, minTypePanel].filter(Boolean)),
      rightPanels: diversifyPanelColumn([edibleYieldPanel, yieldPanel, muYieldPanel, yieldCapacityPanel].filter(Boolean)),
    },
  }
}

function buildGrasslandLayerPanels(panels = {}) {
  const {
    leftPanels = [],
    rightPanels = [],
  } = panels
  const stablePanels = {
    leftPanels: diversifyPanelColumn(leftPanels.filter(Boolean)),
    rightPanels: diversifyPanelColumn(rightPanels.filter(Boolean)),
  }
  return {
    "grassland-distribution": stablePanels,
    "basic-grassland": stablePanels,
    "grassland-level": stablePanels,
    "grassland-type": stablePanels,
    "grassland-yield": stablePanels,
    "grassland-health": stablePanels,
  }
}

function buildWoodlandDefaultPanels({
  townRows = [],
  typeRows = [],
  scaleRows = [],
  protectionRows = [],
  ownershipRows = [],
  qualityRows = [],
  originRows = [],
  ageRows = [],
  canopyRows = [],
  forestTypeRows = [],
  manageLevelRows = [],
  regionRows = [],
  ownerRows = [],
  typeTownRows = [],
  qualityLevelRows = [],
  townConcentrationRows = buildHeadTailRows(townRows, { headCount: 4, headName: "前四乡镇", tailName: "其他乡镇" }),
  typeConcentrationRows = buildHeadTailRows(typeRows, { headCount: 2, headName: "主要类型", tailName: "其他类型" }),
}) {
  const townPanel = buildPanel("woodland-town", "林地面积分布", colorRowsByPalette(sortRowsByTownDisplayOrder(townRows), WOODLAND_CHART_PALETTE), "column", { span: 1, variant: "plain" })
  const typePanel = buildPanel("woodland-type", "林地类型结构", colorRowsByPalette(typeRows, WOODLAND_CHART_PALETTE), "donut", { span: 1, variant: "ring" })
  const protectionPanel = buildPanel("woodland-protection", "公益林保护等级", colorRowsByPalette(withPercentExtra(protectionRows), WOODLAND_CHART_PALETTE), "bar", { span: 1, variant: "raceBarRelaxed" })
  const ownershipPanel = buildPanel("woodland-ownership", "林地权属结构", colorRowsByPalette(withPercentExtra(ownershipRows), WOODLAND_CHART_PALETTE), "structure", { span: 1 })
  const qualityPanel = buildPanel("woodland-quality", "优势树种面积", topRows(qualityRows, 6), "bar", { span: 1 })
  const originPanel = buildPanel("woodland-origin", "林地起源结构", withPercentExtra(originRows), "structure", { span: 1 })
  const agePanel = buildPanel("woodland-age", "林龄组结构", topRows(ageRows, 6), "column", { span: 1 })
  const canopyPanel = buildPanel("woodland-canopy", "郁闭度结构", colorRowsByPalette(topRows(canopyRows, 6), WOODLAND_CHART_PALETTE), "donut", { span: 1, fixedType: true })
  const scalePanel = buildPanel("woodland-area-scale", "林地图斑规模", scaleRows, "column", { span: 1 })
  const forestTypePanel = buildPanel("woodland-forest-type", "森林类别结构", topRows(forestTypeRows, 6), "bar", { span: 1 })
  const manageLevelPanel = buildPanel("woodland-manage-level", "管护等级分布", topRows(manageLevelRows, 6), "bar", { span: 1 })
  const regionPanel = buildPanel("woodland-public-rank", "公益林面积排行", topRows(regionRows, 6), "bar", { span: 1, variant: "distribution" })
  const ownerPanel = buildPanel("woodland-owner-rank", "权属单位排行", topRows(ownerRows, 6), "bar", { span: 1 })
  const typeTownPanel = buildPanel("woodland-type-town", "乡镇类型构成", topRows(typeTownRows, 6), "bar", { span: 1, variant: "distribution" })
  const qualityLevelPanel = buildPanel("woodland-quality-level", "林地质量等级", withPercentExtra(qualityLevelRows), "donut", { span: 1 })
  const townConcentrationPanel = buildPanel("woodland-town-concentration", "林地集中度", colorRowsByPalette(withPercentExtra(townConcentrationRows), WOODLAND_CHART_PALETTE), "structure", { span: 1 })
  const typeConcentrationPanel = buildPanel("woodland-type-concentration", "类型集中度", colorRowsByPalette(withPercentExtra(typeConcentrationRows), WOODLAND_CHART_PALETTE), "rose", { span: 1 })
  const leftPanels = diversifyPanelColumn(fillPanelSlots(
    [townPanel, typePanel, protectionPanel, ownershipPanel],
    [scalePanel, ownerPanel, forestTypePanel, qualityPanel]
  ))
  const rightPanels = diversifyPanelColumn(fillPanelSlots(
    [qualityPanel, originPanel, agePanel, canopyPanel],
    [scalePanel, ownerPanel, forestTypePanel, regionPanel, townConcentrationPanel, typeConcentrationPanel]
  ))
  return {
    leftPanels,
    rightPanels,
    left: leftPanels[0],
    right: rightPanels[0],
    layerPanels: buildWoodlandLayerPanels({
      townPanel,
      typePanel,
      scalePanel,
      protectionPanel,
      ownershipPanel,
      qualityPanel,
      originPanel,
      agePanel,
      canopyPanel,
      forestTypePanel,
      manageLevelPanel,
      regionPanel,
      ownerPanel,
      typeTownPanel,
      qualityLevelPanel,
      townConcentrationPanel,
      typeConcentrationPanel,
    }),
  }
}

function buildWoodlandLayerPanels(panels = {}) {
  const {
    townPanel,
    typePanel,
    scalePanel,
    protectionPanel,
    ownershipPanel,
    qualityPanel,
    originPanel,
    agePanel,
    canopyPanel,
    forestTypePanel,
    manageLevelPanel,
    regionPanel,
    ownerPanel,
    typeTownPanel,
    qualityLevelPanel,
    townConcentrationPanel,
    typeConcentrationPanel,
  } = panels
  return {
    "woodland-distribution": {
      leftPanels: diversifyPanelColumn(fillPanelSlots([townPanel, typePanel, protectionPanel, ownershipPanel], [scalePanel, forestTypePanel, ownerPanel])),
      rightPanels: diversifyPanelColumn(fillPanelSlots([qualityPanel, originPanel, agePanel, canopyPanel], [scalePanel, ownerPanel, regionPanel, townConcentrationPanel, typeConcentrationPanel, qualityLevelPanel])),
    },
    "woodland-protection": {
      leftPanels: diversifyPanelColumn(fillPanelSlots([protectionPanel, forestTypePanel, manageLevelPanel, townPanel], [typePanel, ownershipPanel, scalePanel])),
      rightPanels: diversifyPanelColumn(fillPanelSlots([regionPanel, qualityPanel, originPanel, ownershipPanel], [ownerPanel, typePanel, scalePanel])),
    },
    "woodland-type": {
      leftPanels: diversifyPanelColumn(fillPanelSlots([typePanel, townPanel, typeTownPanel, scalePanel], [protectionPanel, ownershipPanel, forestTypePanel])),
      rightPanels: diversifyPanelColumn(fillPanelSlots([qualityPanel, originPanel, protectionPanel, ownershipPanel], [agePanel, canopyPanel, ownerPanel, typeConcentrationPanel])),
    },
    "woodland-quality": {
      leftPanels: diversifyPanelColumn(fillPanelSlots([qualityPanel, originPanel, agePanel, canopyPanel], [qualityLevelPanel, scalePanel, typePanel])),
      rightPanels: diversifyPanelColumn(fillPanelSlots([townPanel, typePanel, protectionPanel, ownershipPanel], [forestTypePanel, ownerPanel, scalePanel])),
    },
    "woodland-ownership": {
      leftPanels: diversifyPanelColumn(fillPanelSlots([ownershipPanel, ownerPanel, townPanel, typePanel], [scalePanel, protectionPanel, qualityPanel])),
      rightPanels: diversifyPanelColumn(fillPanelSlots([protectionPanel, qualityPanel, originPanel, scalePanel], [forestTypePanel, agePanel, canopyPanel])),
    },
  }
}

function normalizeGrasslandDegradationName(name) {
  const value = String(name || "").trim()
  if (value.includes("未") && value.includes("退")) return "未退化"
  if (value.includes("轻")) return "轻度退化"
  if (value.includes("中")) return "中度退化"
  if (value.includes("重")) return "重度退化"
  return value || "未分级"
}

async function getGrasslandDegradationRows() {
  return (await getGrasslandDegradationStats()).levelRows
}

async function getGrasslandDegradationStats() {
  const data = await getWfsFeatureProperties("ne:t_grassland_result_caodi", {
    propertyName: ["area_code", "degradation_level", "acreage"],
    maxFeatures: 200000,
    timeout: 25000,
  })
  const levelGrouped = new Map()
  const townGrouped = new Map()
  ;(data?.features || []).forEach((feature) => {
    const properties = feature.properties || {}
    const name = normalizeGrasslandDegradationName(properties.degradation_level)
    const acreage = toNumber(properties.acreage)
    if (!name || acreage === undefined) return
    const areaWanMu = acreage / 10000
    levelGrouped.set(name, (levelGrouped.get(name) || 0) + areaWanMu)
    if (name === "未退化") return
    const townCode = String(properties.area_code || "").slice(0, 9)
    const townName = getHongyuanTownshipNameByCode(townCode)
    if (!townName) return
    townGrouped.set(townName, (townGrouped.get(townName) || 0) + areaWanMu)
  })
  const levelOrder = ["未退化", "轻度退化", "中度退化", "重度退化", "未分级"]
  const levelRows = Array.from(levelGrouped.entries())
    .map(([name, value]) => ({
      key: name,
      name,
      value: formatNumber(value),
      unit: "万亩",
    }))
    .filter((row) => Number(row.value) > 0)
    .sort((a, b) => {
      const orderA = levelOrder.indexOf(a.name)
      const orderB = levelOrder.indexOf(b.name)
      if (orderA !== -1 || orderB !== -1) {
        return (orderA === -1 ? 99 : orderA) - (orderB === -1 ? 99 : orderB)
      }
      return (Number(b.value) || 0) - (Number(a.value) || 0)
    })
  const townRows = Array.from(townGrouped.entries())
    .map(([name, value]) => ({
      key: name,
      name,
      value: formatNumber(value),
      unit: "万亩",
    }))
    .filter((row) => Number(row.value) > 0)
    .sort((a, b) => (Number(b.value) || 0) - (Number(a.value) || 0))
  return {
    levelRows: withPercentExtra(levelRows),
    townRows,
  }
}

function findGrasslandCoreRow(rows = [], keywords = []) {
  return rows.find((row) => {
    const signal = `${row?.key || ""}${row?.name || ""}`
    return keywords.some((keyword) => signal.includes(keyword))
  })
}

function buildGrasslandResourceRows(core = []) {
  const totalRow = findGrasslandCoreRow(core, ["grassland-total", "grassland-area", "草地总面积", "草地面积"])
  const basicRow = findGrasslandCoreRow(core, ["basic-grassland", "基本草原"])
  const generalRow = findGrasslandCoreRow(core, ["general-grassland", "一般草原"])
  const total = toNumber(totalRow?.value)
  const basic = toNumber(basicRow?.value)
  return [
    {
      ...(totalRow || {}),
      key: "resource-total",
      name: "草地总量",
      icon: "area",
    },
    {
      ...(basicRow || {}),
      key: "resource-basic",
      name: "基本草原",
      icon: "leaf",
    },
    {
      ...(generalRow || {}),
      key: "resource-general",
      name: "一般草原",
      icon: "stack",
    },
    {
      key: "resource-basic-rate",
      name: "基本占比",
      value: formatNumber(percentOf(basic, total)),
      unit: "%",
      icon: "rate",
    },
  ].filter((row) => row.value !== undefined)
}

function buildGrasslandResourceStructureRows(core = []) {
  const basicRow = findGrasslandCoreRow(core, ["basic-grassland", "基本草原"])
  const generalRow = findGrasslandCoreRow(core, ["general-grassland", "一般草原"])
  return withPercentExtra([
    {
      ...(basicRow || {}),
      key: "resource-basic",
      name: "基本草原",
    },
    {
      ...(generalRow || {}),
      key: "resource-general",
      name: "一般草原",
    },
  ].filter((row) => row.value !== undefined))
}

function buildGrasslandTopRows(core = [], yieldSummary = {}, yieldRows = []) {
  const totalYield = toNumber(yieldSummary?.xc) ?? sumRowValues(yieldRows)
  return [
    core[0],
    core[1],
    core[2],
    {
      key: "grassland-yield-total",
      name: "鲜草产量",
      value: formatNumber(totalYield),
      unit: yieldSummary?.unit || "万吨",
    },
  ].filter((row) => row?.value !== undefined)
}

function buildGrasslandDegradationDistributionRows(rows = []) {
  const total = sumRowValues(rows)
  return rows
    .filter((row) => row.name && row.name !== "未退化" && Number(row.value) > 0)
    .map((row) => ({
      ...row,
      color: getGrasslandDegradationColor(row.name),
      extra: formatNumber(percentOf(row.value, total)) ? `${formatNumber(percentOf(row.value, total))}%` : "",
    }))
    .sort((a, b) => Number(b.value) - Number(a.value))
}

function getGrasslandDegradationColor(name = "") {
  const text = String(name)
  if (text.includes("重度")) return "#FFE06B"
  if (text.includes("中度")) return "#32DCFF"
  return "#24F6C4"
}

function buildGrasslandForageStructureRows(yieldSummary = {}, yieldRows = []) {
  const unit = yieldSummary?.unit || pickValue(yieldRows?.[0], ["unit"]) || "万吨"
  const total = toNumber(yieldSummary?.xc) ?? sumRowValues(yieldRows)
  const edible = toNumber(yieldSummary?.edibleXc)
  const unavailable = total !== undefined && edible !== undefined ? Math.max(total - edible, 0) : undefined
  const rows = [
    {
      key: "forage-edible",
      name: "可食鲜草",
      value: formatNumber(edible),
      unit,
    },
    {
      key: "forage-unavailable",
      name: "不可食鲜草",
      value: formatNumber(unavailable),
      unit,
    },
  ].filter((row) => row.value !== undefined)
  return rows.map((row) => ({
    ...row,
    extra: `${formatNumber(percentOf(row.value, total)) || 0}%`,
  }))
}

function buildGrasslandForageCapacityRows(yieldSummary = {}, yieldRows = []) {
  const unit = yieldSummary?.unit || pickValue(yieldRows?.[0], ["unit"]) || "万吨"
  const total = toNumber(yieldSummary?.xc) ?? sumRowValues(yieldRows)
  const edible = toNumber(yieldSummary?.edibleXc)
  const unavailable = total !== undefined && edible !== undefined ? Math.max(total - edible, 0) : undefined
  const topTownYield = yieldRows.find((row) => Number(row.value) > 0)
  return [
    {
      key: "forage-total",
      name: "鲜草总产",
      value: formatNumber(total),
      unit,
      scaleValue: 100,
    },
    {
      key: "forage-edible",
      name: "可食鲜草",
      value: formatNumber(edible),
      unit,
      scaleValue: formatNumber(percentOf(edible, total)),
    },
    {
      key: "forage-unavailable",
      name: "不可食鲜草",
      value: formatNumber(unavailable),
      unit,
      scaleValue: formatNumber(percentOf(unavailable, total)),
    },
    {
      key: "forage-top-town",
      name: topTownYield?.name ? `最高乡镇：${topTownYield.name}` : "最高乡镇产量",
      value: topTownYield?.value,
      unit: topTownYield?.unit || unit,
      scaleValue: formatNumber(percentOf(topTownYield?.value, total)),
    },
  ].filter((row) => row.value !== undefined)
}

function fallbackGrasslandDegradationRows() {
  return fallbackGrasslandDegradationStats().levelRows
}

function fallbackGrasslandDegradationStats() {
  const levelRows = withPercentExtra([
    { key: "none", name: "未退化", value: 642.42, unit: "万亩" },
    { key: "light", name: "轻度退化", value: 83.95, unit: "万亩" },
    { key: "middle", name: "中度退化", value: 17.49, unit: "万亩" },
    { key: "heavy", name: "重度退化", value: 13.09, unit: "万亩" },
  ])
  const townRows = [
    { key: "qiongxi", name: "邛溪镇", value: 14.72, unit: "万亩" },
    { key: "sedi", name: "色地镇", value: 13.86, unit: "万亩" },
    { key: "anqu", name: "安曲镇", value: 12.38, unit: "万亩" },
    { key: "wache", name: "瓦切镇", value: 10.64, unit: "万亩" },
    { key: "chaerma", name: "查尔玛乡", value: 9.53, unit: "万亩" },
    { key: "amu", name: "阿木乡", value: 8.71, unit: "万亩" },
  ]
  return { levelRows, townRows }
}

function buildGrasslandDegradationFocusRows(rows = []) {
  const total = sumRowValues(rows)
  const degradedRows = rows.filter((row) => row.name && row.name !== "未退化")
  const degradedTotal = sumRowValues(degradedRows)
  const mediumHeavyTotal = degradedRows
    .filter((row) => row.name.includes("中") || row.name.includes("重"))
    .reduce((sum, row) => sum + (Number(row.value) || 0), 0)
  const heavyRow = degradedRows.find((row) => row.name.includes("重"))
  return [
    {
      key: "degraded-total",
      name: "退化面积",
      value: formatNumber(degradedTotal),
      unit: "万亩",
      icon: "area",
    },
    {
      key: "medium-heavy-area",
      name: "中重度",
      value: formatNumber(mediumHeavyTotal),
      unit: "万亩",
      icon: "risk",
    },
    {
      key: "heavy-area",
      name: "重度",
      value: heavyRow?.value,
      unit: heavyRow?.unit || "万亩",
      icon: "risk",
    },
  ].filter((row) => row.value !== undefined)
}

function buildFallbackTopicStats(topicKey, layerKey) {
  if (topicKey === "grassland") {
    const [fallbackBasicGrasslandArea, fallbackGeneralGrasslandArea] = normalizeAreaPartsToTotal(CXPT_GRASSLAND_AREA_WAN_MU, 637.13, 119.31)
    const core = ensureCoreShape([
      { key: "grassland-area", name: "草地面积", value: CXPT_GRASSLAND_AREA_WAN_MU, unit: "万亩" },
      { key: "basic-grassland", name: "基本草原", value: fallbackBasicGrasslandArea, unit: "万亩" },
      { key: "general-grassland", name: "一般草原", value: fallbackGeneralGrasslandArea, unit: "万亩" },
    ], topicKey)
    const townRows = normalizeRankRows([
      { name: "色地镇", value: 99.09, basicAreaWanMu: 66.58 },
      { name: "邛溪镇", value: 93.01, basicAreaWanMu: 70.6 },
      { name: "安曲镇", value: 90.08, basicAreaWanMu: 73.49 },
      { name: "阿木乡", value: 86.3, basicAreaWanMu: 77.31 },
      { name: "查尔玛乡", value: 80.8, basicAreaWanMu: 79.04 },
      { name: "瓦切镇", value: 74.74, basicAreaWanMu: 70.73 },
      { name: "刷经寺镇", value: 74.3, basicAreaWanMu: 56.66 },
      { name: "龙日镇", value: 62.64, basicAreaWanMu: 49.66 },
      { name: "江茸乡", value: 49.67, basicAreaWanMu: 48.78 },
      { name: "麦洼乡", value: 45.82, basicAreaWanMu: 44.28 },
    ], {
      nameKeys: ["name"],
      valueKeys: ["value"],
    })
    const yieldRows = normalizeRankRows([
      { areaName: "邛溪镇", yield: 38.88 },
      { areaName: "色地镇", yield: 37.78 },
      { areaName: "安曲镇", yield: 36.77 },
      { areaName: "查尔玛乡", yield: 33.21 },
      { areaName: "瓦切镇", yield: 32.62 },
      { areaName: "阿木乡", yield: 32.17 },
      { areaName: "龙日镇", yield: 24.43 },
      { areaName: "刷经寺镇", yield: 22.51 },
      { areaName: "麦洼乡", yield: 19.5 },
      { areaName: "江茸乡", yield: 19.43 },
    ], { nameKeys: ["areaName"], valueKeys: ["yield"], unit: "万吨" })
    const typeRows = aggregateTailRows([
      { key: "grazing", name: "重要放牧场", value: 516.41, unit: "万亩" },
      { key: "general", name: "一般草原", value: fallbackGeneralGrasslandArea, unit: "万亩" },
      { key: "ecology", name: "生态调节草原", value: 97.23, unit: "万亩" },
      { key: "mowing", name: "割草地", value: 15.95, unit: "万亩" },
      { key: "improved", name: "改良草地", value: 4.33, unit: "万亩" },
    ], { limit: 4, minPercent: 3, otherName: "其他草原类型" })
    const muYieldRows = normalizeRankRows([
      { areaName: "瓦切镇", yield: 798.39 },
      { areaName: "查尔玛乡", yield: 794.32 },
      { areaName: "麦洼乡", yield: 784.16 },
      { areaName: "邛溪镇", yield: 772.43 },
      { areaName: "安曲镇", yield: 770.9 },
    ], { nameKeys: ["areaName"], valueKeys: ["yield"], unit: "斤" })
    const degradationStats = fallbackGrasslandDegradationStats()
    const degradationRows = degradationStats.levelRows
    const levelRows = withPercentExtra([
      { key: "level-3", name: "3级草原", value: 200.9, unit: "万亩" },
      { key: "level-4", name: "4级草原", value: 205.47, unit: "万亩" },
      { key: "level-5", name: "5级草原", value: 385.42, unit: "万亩" },
      { key: "level-6", name: "6级草原", value: 139.06, unit: "万亩" },
      { key: "level-7", name: "7级草原", value: 3.68, unit: "万亩" },
      { key: "level-8", name: "8级草原", value: 3.61, unit: "万亩" },
    ])
    const healthRows = withPercentExtra([
      { key: "good", name: "较健康", value: 231.32, unit: "万亩" },
      { key: "healthy", name: "健康", value: 481.87, unit: "万亩" },
      { key: "subhealthy", name: "亚健康", value: 23.69, unit: "万亩" },
      { key: "unhealthy", name: "不健康", value: 20.27, unit: "万亩" },
    ])
    const forageRows = buildGrasslandForageCapacityRows({
        xc: 297.29,
        edibleXc: 192.26,
        unit: "万吨",
      }, yieldRows)
    const edibleYieldRows = normalizeRankRows([
      { areaName: "邛溪镇", yield: 24.71 },
      { areaName: "色地镇", yield: 24.18 },
      { areaName: "安曲镇", yield: 23.48 },
      { areaName: "查尔玛乡", yield: 21.26 },
      { areaName: "瓦切镇", yield: 20.88 },
      { areaName: "阿木乡", yield: 20.59 },
      { areaName: "龙日镇", yield: 15.63 },
      { areaName: "刷经寺镇", yield: 14.41 },
      { areaName: "麦洼乡", yield: 12.48 },
      { areaName: "江茸乡", yield: 12.44 },
    ], { nameKeys: ["areaName"], valueKeys: ["yield"], unit: "万吨" })
    const grasslandPanels = buildGrasslandDefaultPanels({
      core,
      townRows,
      grassTypeRows: typeRows,
      grassLevelRows: levelRows,
      healthRows,
      productivityRows: muYieldRows,
      edibleYieldRows,
      forageRows,
      degradationRows,
    })
    const result = {
      status: "fallback",
      ...grasslandPanels,
      top: buildGrasslandTopRows(core, { xc: 297.29, unit: "万吨" }, yieldRows),
    }
    return applyLayerPanelSelection(result, topicKey, layerKey)
  }

  if (topicKey === "wetland") {
    const core = ensureCoreShape([
      { key: "wetland-area", name: "湿地面积", value: CXPT_WETLAND_AREA_WAN_MU, unit: "万亩" },
      { key: "wetland-yield", name: "湿地生产力(鲜草)", value: 108.84, unit: "万吨" },
      { key: "wetland-level-1-area", name: "1级湿地面积", value: 213.22, unit: "万亩" },
    ], topicKey)
    const typeRows = aggregateTailRows([
      { name: "高寒草甸类", value: 190.32, unit: "万亩" },
      { name: "山地草甸类", value: 49.48, unit: "万亩" },
      { name: "低地草甸类", value: 3.21, unit: "万亩" },
    ], { limit: 4, minPercent: 1, otherName: "其他湿地类型" })
    const levelRows = [
      { name: "1级湿地", value: 213.22, unit: "万亩" },
      { name: "2级湿地", value: 22.99, unit: "万亩" },
      { name: "3级湿地", value: 6.42, unit: "万亩" },
      { name: "4级湿地", value: 0.36, unit: "万亩" },
      { name: "5级湿地", value: 0.02, unit: "万亩" },
    ]
    const yieldRows = normalizeRankRows([
      { areaName: "色地镇", yield: 21.32 },
      { areaName: "瓦切镇", yield: 17.49 },
      { areaName: "安曲镇", yield: 15.19 },
      { areaName: "邛溪镇", yield: 13.41 },
      { areaName: "阿木乡", yield: 10.37 },
      { areaName: "龙日镇", yield: 10.11 },
      { areaName: "麦洼乡", yield: 9.67 },
      { areaName: "江茸乡", yield: 5.78 },
      { areaName: "刷经寺镇", yield: 3.43 },
      { areaName: "查尔玛乡", yield: 2.08 },
    ], { nameKeys: ["areaName"], valueKeys: ["yield"], unit: "万吨" })
    const muYieldRows = [
      { name: "瓦切镇", value: 944.22, unit: "斤" },
      { name: "安曲镇", value: 913.28, unit: "斤" },
      { name: "麦洼乡", value: 911.14, unit: "斤" },
      { name: "查尔玛乡", value: 873.31, unit: "斤" },
      { name: "阿木乡", value: 872, unit: "斤" },
      { name: "邛溪镇", value: 870.48, unit: "斤" },
      { name: "色地镇", value: 865.92, unit: "斤" },
      { name: "刷经寺镇", value: 863.48, unit: "斤" },
      { name: "江茸乡", value: 827.92, unit: "斤" },
      { name: "龙日镇", value: 825.59, unit: "斤" },
    ]
    const townAreaRows = [
      { name: "瓦切镇", value: 36.38, unit: "万亩" },
      { name: "邛溪镇", value: 29.29, unit: "万亩" },
      { name: "阿木乡", value: 25.26, unit: "万亩" },
      { name: "龙日镇", value: 24.59, unit: "万亩" },
      { name: "色地镇", value: 24.62, unit: "万亩" },
    ].sort((a, b) => b.value - a.value)
    const minTypeRows = [
      { name: "矮生嵩草、杂类草型", value: 108.35, unit: "万亩" },
      { name: "高山嵩草、矮生嵩草型", value: 34.36, unit: "万亩" },
      { name: "西藏嵩草、杂类草型", value: 32.37, unit: "万亩" },
      { name: "早熟禾、杂类草型", value: 20.99, unit: "万亩" },
      { name: "苔草、杂类草型", value: 14.63, unit: "万亩" },
    ]
    const edibleYieldRows = normalizeRankRows([
      { areaName: "色地镇", yield: 2.82 },
      { areaName: "邛溪镇", yield: 2.71 },
      { areaName: "瓦切镇", yield: 2.64 },
      { areaName: "麦洼乡", yield: 1.76 },
      { areaName: "安曲镇", yield: 1.66 },
    ], { nameKeys: ["areaName"], valueKeys: ["yield"], unit: "万吨" })
    const edibleMuRows = normalizeRankRows([
      { areaName: "阿木乡", yield: 509.83 },
      { areaName: "瓦切镇", yield: 509.52 },
      { areaName: "邛溪镇", yield: 356.74 },
      { areaName: "色地镇", yield: 287.23 },
      { areaName: "麦洼乡", yield: 281.27 },
    ], { nameKeys: ["areaName"], valueKeys: ["yield"], unit: "斤" })
    const wetlandPanels = buildWetlandDefaultPanels({
      core,
      yieldSummary: { xc: 108.84, edibleXc: 1.65, unit: "万吨" },
      townAreaRows,
      typeRows,
    levelRows,
    yieldRows,
    minTypeRows,
    muYieldRows,
      edibleYieldRows,
    edibleMuRows,
    typeTownRows: townAreaRows,
    levelTownRows: townAreaRows,
    minTownRows: townAreaRows,
  })
    const result = {
      status: "fallback",
      core,
      top: [core[0], core[1], core[2]],
      ...wetlandPanels,
    }
    return applyLayerPanelSelection(result, topicKey, layerKey)
  }

  if (topicKey === "woodland") {
    const core = ensureCoreShape([
      { key: "woodland-area", name: "林地总面积", value: 177.92, unit: "万亩" },
      { key: "woodland-public-area", name: "公益林面积", value: 159.33, unit: "万亩" },
      { key: "woodland-public-rate", name: "公益林占比", value: 89.55, unit: "%" },
    ], topicKey)
    const townRows = normalizeRankRows([
      { name: "刷经寺镇", value: 59.4, percent: 33.39 },
      { name: "色地镇", value: 27.97, percent: 15.72 },
      { name: "查尔玛乡", value: 22.6, percent: 12.7 },
      { name: "阿木乡", value: 19.37, percent: 10.89 },
      { name: "江茸乡", value: 11.61, percent: 6.53 },
      { name: "邛溪镇", value: 8.29, percent: 4.66 },
      { name: "瓦切镇", value: 7.98, percent: 4.49 },
      { name: "安曲镇", value: 7.47, percent: 4.2 },
      { name: "龙日镇", value: 7.08, percent: 3.98 },
      { name: "麦洼乡", value: 6.14, percent: 3.45 },
    ], {
      nameKeys: ["name"],
      valueKeys: ["value"],
      extra: (row) => `占比 ${formatNumber(row.percent)}%`,
    })
    const typeRows = aggregateTailRows([
      { name: "灌木林地", value: 114.78, unit: "万亩" },
      { name: "乔木林地", value: 49.56, unit: "万亩" },
      { name: "灌丛沼泽", value: 8.79, unit: "万亩" },
      { name: "其他林地", value: 4.79, unit: "万亩" },
    ], { limit: 4, minPercent: 1, otherName: "其他林地" })
    const scaleRows = [
      { name: "15-150亩", value: 96.91, unit: "万亩" },
      { name: "<15亩", value: 39.99, unit: "万亩" },
      { name: "150-1500亩", value: 30.81, unit: "万亩" },
      { name: "≥1500亩", value: 10.21, unit: "万亩" },
    ]
    const protectionRows = [
      { name: "国家二级公益林", value: 158.33, unit: "万亩", extra: "88.99%" },
      { name: "未划定", value: 18.72, unit: "万亩", extra: "10.52%" },
      { name: "国家一级公益林", value: 0.88, unit: "万亩", extra: "0.49%" },
    ]
    const ownerRows = [
      { name: "壤口村", value: 42.74, unit: "万亩", extra: "占比 24.02%" },
      { name: "查龙村", value: 16.34, unit: "万亩", extra: "占比 9.18%" },
      { name: "茸塔玛村", value: 14.96, unit: "万亩", extra: "占比 8.41%" },
      { name: "峨扎村", value: 9.96, unit: "万亩", extra: "占比 5.6%" },
      { name: "三家寨村", value: 9.57, unit: "万亩", extra: "占比 5.38%" },
    ]
    const ownershipRows = [
      { name: "集体林地", value: 172.19, unit: "万亩", extra: "96.78%" },
      { name: "国有或其他", value: 5.73, unit: "万亩", extra: "3.22%" },
    ]
    const woodlandPanels = buildWoodlandDefaultPanels({
      townRows,
      typeRows,
      scaleRows,
      protectionRows,
      ownershipRows,
      ownerRows,
    })
    const result = {
      status: "fallback",
      core,
      top: [core[0], core[1], core[2]],
      ...woodlandPanels,
    }
    return applyLayerPanelSelection(result, topicKey, layerKey)
  }

  return {
    status: "empty",
    core: ensureCoreShape([], topicKey),
    leftPanels: [],
    rightPanels: [],
    left: { title: "业务统计", rows: [] },
    right: { title: "业务统计", rows: [] },
  }
}

function uniqueBusinessRows(rows = [], nameKeys = ["name"]) {
  const seen = new Map()
  rows.forEach((row) => {
    const name = pickValue(row, nameKeys)
    if (!name || seen.has(name)) return
    seen.set(name, row)
  })
  return Array.from(seen.values())
}

function getOptionalData(request, fallback = []) {
  return request().catch(() => fallback)
}

function normalizeProportionRows(rows = [], options = {}) {
  const {
    nameKeys = ["name", "health", "level"],
    valueKeys = ["value", "acreage", "areaWanMu"],
    unit = "万亩",
    nameTransform = (name) => name,
    max = Number.POSITIVE_INFINITY,
  } = options
  const normalizedRows = normalizeRankRows(rows || [], {
    nameKeys,
    valueKeys,
    unit,
  }).map((row) => ({
    ...row,
    name: nameTransform(row.name),
  }))
  return withPercentExtra(normalizedRows)
    .filter((row) => Number(row.value) > 0)
    .slice(0, max)
}

function normalizeGrasslandLevelName(name) {
  const value = String(name || "")
  if (/^\d+$/.test(value)) return `${value}级草原`
  if (value.includes("级")) return value.replace(/草地/g, "草原")
  return value
}

function normalizeHealthName(name) {
  const value = String(name || "")
  const aliases = {
    healthy: "健康",
    subhealthy: "亚健康",
    unhealthy: "不健康",
  }
  return aliases[value] || value
}

function buildGrasslandDefaultPanels({
  core,
  townRows,
  grassTypeRows,
  grassLevelRows,
  healthRows,
  productivityRows,
  edibleYieldRows,
  forageRows,
  degradationRows,
}) {
  const areaPanel = buildPanel("grassland-town", "草地面积分布", sortRowsByTownDisplayOrder(townRows), "column", { span: 1, variant: "plain" })
  const productivityPanel = buildPanel("grassland-productivity-town", "草地生产力分布", sortRowsByTownDisplayOrder(productivityRows), "line", { span: 1, fixedType: true })
  const typePanel = buildPanel("grassland-type-proportion", "草原类占比", grassTypeRows, "donut", { span: 1 })
  const edibleYieldPanel = buildPanel("grassland-edible-yield", "可食鲜草产量分布", topRows(edibleYieldRows, 10), "column", { span: 1, variant: "slim" })
  const degradationPanel = buildPanel("grassland-degradation", "草地退化统计", buildGrasslandDegradationDistributionRows(degradationRows), "bar", { span: 1, variant: "degradation" })
  const healthPanel = buildPanel("grassland-health-proportion", "草地健康占比", healthRows, "rose", { span: 1 })
  const levelPanel = buildPanel("grassland-level-proportion", "草原级占比", grassLevelRows, "donut", { span: 1, variant: "ring" })
  const foragePanel = buildPanel("grassland-forage-capacity", "饲草供给", forageRows, "bar", { span: 1, variant: "capacity" })
  const leftPanels = diversifyPanelColumn([
    areaPanel,
    typePanel,
    degradationPanel,
    levelPanel,
  ])
  const rightPanels = diversifyPanelColumn([
    edibleYieldPanel,
    productivityPanel,
    healthPanel,
    foragePanel,
  ])
  return {
    core,
    leftPanels,
    rightPanels,
    left: leftPanels[0],
    right: rightPanels[0],
    layerPanels: buildGrasslandLayerPanels({
      leftPanels,
      rightPanels,
    }),
  }
}

function normalizeWetlandBusiness(items, stats = {}) {
  const normalized = normalizeDataItems(items)
  const typeRows = uniqueBusinessRows(stats.typeRows || [], ["name"])
  const yieldRows = stats.yieldRows || []
  const levelRows = stats.levelRows || []
  const minTypeRows = stats.minTypeRows || []
  const edibleRows = stats.edibleRows || []
  const edibleMuRows = stats.edibleMuRows || []
  const typeDistributionRows = stats.typeDistributionRows || []
  const levelDistributionRows = stats.levelDistributionRows || []
  const minTypeDistributionRows = stats.minTypeDistributionRows || []
  const yieldSummary = stats.yieldSummary || {}
  const wetlandTypeRows = aggregateTailRows(normalizeMetricRows(typeRows, {
    nameKeys: ["name"],
    valueKeys: ["value"],
    unit: "万亩",
  }), { limit: 4, minPercent: 1, otherName: "其他湿地类型" })
  const wetlandYieldRows = normalizeYieldRows(yieldRows, stats.muYieldRows || [], { showMuYieldExtra: false })
  const wetlandMuYieldRows = normalizeMetricRows(stats.muYieldRows || [], {
    nameKeys: ["areaName", "name"],
    valueKeys: ["yield", "value"],
    unit: "斤",
    max: hongyuanTownshipDisplayOrder.length,
  })
  const wetlandLevelRows = normalizeMetricRows(levelRows, {
    nameKeys: ["name"],
    valueKeys: ["value"],
    unit: "万亩",
  }).map((row) => ({ ...row, name: normalizeWetlandLevelName(row.name) }))
  const wetlandMinTypeRows = normalizeMuRows(minTypeRows)
  const wetlandEdibleRows = normalizeYieldRows(edibleRows, edibleMuRows, { showMuYieldExtra: false })
  const wetlandEdibleMuRows = normalizeMetricRows(edibleMuRows, {
    nameKeys: ["areaName", "name"],
    valueKeys: ["yield", "value"],
    unit: pickValue(edibleMuRows?.[0], ["unit"]) || "斤",
    max: hongyuanTownshipDisplayOrder.length,
  })
  const wetlandTownAreaRows = aggregateAreaWanMuRows(typeDistributionRows, {
    nameKeys: ["areaName", "name"],
    valueKeys: ["acreage", "areaWanMu", "value"],
  })
  const wetlandTypeTownRows = aggregateAreaWanMuRows(typeDistributionRows, {
    nameKeys: ["areaName", "name"],
    valueKeys: ["acreage", "areaWanMu", "value"],
    extra: (row) => `${row.source?.length || 0}类`,
  })
  const wetlandLevelTownRows = aggregateAreaWanMuRows(levelDistributionRows, {
    nameKeys: ["areaName", "name"],
    valueKeys: ["acreage", "areaWanMu", "value"],
  })
  const wetlandLevelOneTownRows = aggregateAreaWanMuRows(levelDistributionRows, {
    nameKeys: ["areaName", "name"],
    valueKeys: ["acreage", "areaWanMu", "value"],
    filter: (row) => normalizeWetlandLevelName(pickValue(row, ["level", "name"])).startsWith("1级"),
  })
  const wetlandMinTypeTownRows = aggregateAreaWanMuRows(minTypeDistributionRows, {
    nameKeys: ["areaName", "name"],
    valueKeys: ["acreage", "areaWanMu", "value"],
    extra: (row) => `${row.source?.filter((item) => normalizeAreaValueToWanMu(item, ["acreage", "areaWanMu", "value"]) > 0).length || 0}型`,
  })
  const wetlandCore = ensureCoreShape(normalized, "wetland")
  const levelOneArea = wetlandLevelRows.find((row) => /^1级/.test(row.name)) || wetlandLevelRows[0]
  const wetlandPanels = buildWetlandDefaultPanels({
    yieldSummary,
    townAreaRows: wetlandTownAreaRows,
    typeRows: wetlandTypeRows,
    levelRows: wetlandLevelRows,
    yieldRows: wetlandYieldRows,
    minTypeRows: wetlandMinTypeRows,
    muYieldRows: wetlandMuYieldRows,
    edibleYieldRows: wetlandEdibleRows,
    edibleMuRows: wetlandEdibleMuRows,
    typeTownRows: wetlandTypeTownRows,
    levelTownRows: wetlandLevelOneTownRows.length ? wetlandLevelOneTownRows : wetlandLevelTownRows,
    minTownRows: wetlandMinTypeTownRows,
  })
  return {
    core: wetlandCore,
    top: [
      wetlandCore[0],
      wetlandCore[1],
      {
        key: "wetland-level-1-area",
        name: "1级湿地面积",
        value: levelOneArea?.value,
        unit: levelOneArea?.unit || "万亩",
      },
    ].filter(Boolean),
    ...wetlandPanels,
  }
}

export async function getTopicBusinessStats(topicKey, layerKey) {
  try {
    if (topicKey === "woodland") {
      const [data, typeData, protectionData, qualityData, ownershipData] = await Promise.all([
        post("/woodland/distribution").then(normalizeResponseData),
        getOptionalData(async () => normalizeResponseData(await post("/woodland/types")), {}),
        getOptionalData(async () => normalizeResponseData(await post("/woodland/protection")), {}),
        getOptionalData(async () => normalizeResponseData(await post("/woodland/quality")), {}),
        getOptionalData(async () => normalizeResponseData(await post("/woodland/ownership")), {}),
      ])
      const core = ensureCoreShape(normalizeWoodlandDistribution(data), topicKey)
      const woodlandTotalArea = pickValue(data?.core || data?.summary || {}, ["totalAreaWanMu", "total_area_wan_mu", "areaWanMu", "area_wan_mu"])
      const publicArea = pickValue(protectionData?.summary || {}, ["publicAreaWanMu", "public_area_wan_mu"])
      const top = [
        core[0],
        {
          key: "woodland-public-area",
          name: "公益林面积",
          value: formatNumber(publicArea),
          unit: "万亩",
        },
        {
          key: "woodland-public-rate",
          name: "公益林占比",
          value: formatNumber(
            pickValue(protectionData?.summary || {}, ["publicAreaPercent", "public_area_percent"]) ??
              percentOf(publicArea, woodlandTotalArea)
          ),
          unit: "%",
        },
      ].filter(Boolean)
      const townRows = normalizeRankRows(data?.areaDistribution || [], {
        nameKeys: ["name"],
        valueKeys: ["areaWanMu", "value"],
        extra: (row) => formatPercentExtra(row, woodlandTotalArea),
      })
      const typeRows = aggregateTailRows(normalizeRankRows(typeData?.typeStats || data?.typeDistribution || [], {
        nameKeys: ["name"],
        valueKeys: ["areaWanMu", "value"],
        extra: formatRowPercentExtra,
      }), { limit: 4, minPercent: 1, otherName: "其他林地" })
      const scaleRows = normalizeRankRows(data?.patchScale || [], {
        nameKeys: ["name"],
        valueKeys: ["areaWanMu", "value"],
        extra: (row) => formatPercentExtra(row, woodlandTotalArea),
      })
      const protectionRows = normalizeRankRows(protectionData?.protectionLevels || [], {
        nameKeys: ["name"],
        valueKeys: ["areaWanMu", "value"],
        extra: formatRowPercentExtra,
      })
      const qualityRows = normalizeRankRows(qualityData?.speciesRanks || [], {
        nameKeys: ["name"],
        valueKeys: ["areaWanMu", "value"],
        max: 6,
        extra: formatRowPercentExtra,
      })
      const ownerRows = normalizeRankRows(ownershipData?.ownerRanks || [], {
        nameKeys: ["name"],
        valueKeys: ["areaWanMu", "value"],
        max: 6,
        extra: (row) => formatPercentExtra(row, woodlandTotalArea),
      })
      const ownershipRows = normalizeRankRows(ownershipData?.landOwnerships || [], {
        nameKeys: ["name"],
        valueKeys: ["areaWanMu", "value"],
        extra: formatRowPercentExtra,
      })
      const forestTypeRows = normalizeRankRows(protectionData?.forestTypes || [], {
        nameKeys: ["name"],
        valueKeys: ["areaWanMu", "value"],
        max: 6,
        extra: formatRowPercentExtra,
      })
      const manageLevelRows = normalizeRankRows(protectionData?.manageLevels || [], {
        nameKeys: ["name"],
        valueKeys: ["areaWanMu", "value"],
        max: 6,
        extra: formatRowPercentExtra,
      })
      const regionRows = normalizeRankRows(protectionData?.regionRanks || [], {
        nameKeys: ["regionName", "name", "townName"],
        valueKeys: ["areaWanMu", "value"],
        max: 6,
        extra: (row) => formatPercentExtra(row, publicArea),
      })
      const originRows = normalizeRankRows(qualityData?.origins || [], {
        nameKeys: ["name"],
        valueKeys: ["areaWanMu", "value"],
        extra: formatRowPercentExtra,
      })
      const ageRows = normalizeRankRows(qualityData?.ageGroups || [], {
        nameKeys: ["name"],
        valueKeys: ["areaWanMu", "value"],
        extra: formatRowPercentExtra,
      })
      const canopyRows = normalizeRankRows(qualityData?.canopyLevels || [], {
        nameKeys: ["name"],
        valueKeys: ["areaWanMu", "value"],
        extra: (row) => {
          const avgCanopy = formatNumber(pickValue(row, ["avgCanopy", "avg_canopy"]))
          return avgCanopy !== undefined ? `均值 ${avgCanopy}` : formatRowPercentExtra(row)
        },
      })
      const qualityLevelRows = normalizeRankRows(qualityData?.qualityLevels || [], {
        nameKeys: ["name"],
        valueKeys: ["areaWanMu", "value"],
        extra: formatRowPercentExtra,
      })
      const typeTownRows = aggregateTownRankingRows(typeData?.townComposition || [], {
        nameKeys: ["townName", "name"],
        valueKeys: ["areaWanMu", "value"],
      }).slice(0, 6)
      const woodlandPanels = buildWoodlandDefaultPanels({
        townRows,
        typeRows,
        scaleRows,
        protectionRows,
        ownershipRows,
        qualityRows,
        originRows,
        ageRows,
        canopyRows,
        forestTypeRows,
        manageLevelRows,
        regionRows,
        ownerRows,
        typeTownRows,
        qualityLevelRows,
      })
      const result = {
        status: "success",
        core,
        top,
        ...woodlandPanels,
      }
      return applyLayerPanelSelection(result, topicKey, layerKey)
    }

    if (topicKey === "grassland") {
      const [
        data,
        yieldSummary,
        yieldRows,
        muYieldRows,
        degradationStats,
        typeRows,
        levelRows,
        healthRows,
        edibleRows,
      ] = await Promise.all([
        get("/basic_grassland/overview").then(normalizeResponseData),
        getOptionalData(async () => normalizeResponseData(await get("/grassland_yield/yieldProportion")), {}),
        getOptionalData(async () => normalizeResponseData(await get("/grassland_yield/distribution"))),
        getOptionalData(async () => normalizeResponseData(await get("/grassland_yield/muYieldDistribution"))),
        getOptionalData(async () => getGrasslandDegradationStats(), fallbackGrasslandDegradationStats()),
        getOptionalData(async () => normalizeResponseData(await get("/grassland_grass_type/areaProportion"))),
        getOptionalData(async () => normalizeResponseData(await get("/grassland_grassland_level/areaProportion"))),
        getOptionalData(async () => normalizeResponseData(await get("/grassland_health/proportion"))),
        getOptionalData(async () => normalizeResponseData(await get("/grassland_yield/edibleXcDistribution"))),
      ])
      const degradationRows = degradationStats.levelRows || []
      const core = ensureCoreShape(normalizeBasicGrassland(data), topicKey)
      const grassYieldRows = normalizeYieldRows(yieldRows || [], muYieldRows || [], { showMuYieldExtra: false })
      const muYieldRankRows = normalizeRankRows(muYieldRows || [], {
        nameKeys: ["areaName", "name"],
        valueKeys: ["yield", "value"],
        unit: pickValue(muYieldRows?.[0], ["unit"]) || "斤",
      })
      const townRows = normalizeRankRows(data?.townStats || [], {
        nameKeys: ["name"],
        valueKeys: ["totalAreaWanMu"],
      })
      const grassTypeRows = normalizeProportionRows(uniqueBusinessRows(typeRows || [], ["name"]), {
        nameKeys: ["name"],
        valueKeys: ["value", "areaWanMu", "acreage"],
        unit: "万亩",
        nameTransform: normalizeGrasslandTypeName,
      })
      const grassLevelRows = normalizeProportionRows(levelRows || [], {
        nameKeys: ["name", "level"],
        valueKeys: ["value", "areaWanMu", "acreage"],
        unit: "万亩",
        nameTransform: normalizeGrasslandLevelName,
      })
      const normalizedHealthRows = normalizeProportionRows(healthRows || [], {
        nameKeys: ["health", "name"],
        valueKeys: ["acreage", "value", "areaWanMu"],
        unit: "万亩",
        nameTransform: normalizeHealthName,
      })
      const edibleYieldRows = normalizeYieldRows(edibleRows || [], [], { showMuYieldExtra: false })
      const grasslandPanels = buildGrasslandDefaultPanels({
        core,
        townRows,
        grassTypeRows,
        grassLevelRows,
        healthRows: normalizedHealthRows,
        productivityRows: muYieldRankRows,
        edibleYieldRows,
        forageRows: buildGrasslandForageCapacityRows(yieldSummary, grassYieldRows),
        degradationRows,
      })
      const result = {
        status: "success",
        ...grasslandPanels,
        top: buildGrasslandTopRows(core, yieldSummary, grassYieldRows),
      }
      return applyLayerPanelSelection(result, topicKey, layerKey)
    }

    if (topicKey === "wetland") {
      const [
        data,
        typeRows,
        yieldRows,
        muYieldRows,
        levelRows,
        minTypeRows,
        edibleRows,
        edibleMuRows,
        typeDistributionRows,
        levelDistributionRows,
        minTypeDistributionRows,
        yieldSummary,
      ] = await Promise.all([
        tryRequests([
          async () => normalizeResponseData(await get("/index/dataItem", { group: "wetland" })),
          async () => normalizeResponseData(await get("/index/dataItem", { group: "wetland_grassland_level" })),
        ]),
        getOptionalData(async () => normalizeResponseData(await get("/wetland_grass_type_copy/areaProportion"))),
        getOptionalData(async () => normalizeResponseData(await get("/wetland_yield/distribution"))),
        getOptionalData(async () => normalizeResponseData(await get("/wetland_yield/muYieldDistribution"))),
        getOptionalData(async () => normalizeResponseData(await get("/wetland_grassland_level/areaProportion"))),
        getOptionalData(async () => normalizeResponseData(await get("/wetland_grass_type_copy/minTypeAreaProportion"))),
        getOptionalData(async () => normalizeResponseData(await get("/wetland_yield/edibleXcDistribution"))),
        getOptionalData(async () => normalizeResponseData(await get("/wetland_yield/edibleXcMuDistribution"))),
        getOptionalData(async () => normalizeResponseData(await get("/wetland_grass_type_copy/distribution"))),
        getOptionalData(async () => normalizeResponseData(await get("/wetland_grassland_level/distribution"))),
        getOptionalData(async () => normalizeResponseData(await get("/wetland_grass_type_copy/minTypeAreaDistribution"))),
        getOptionalData(async () => normalizeResponseData(await get("/wetland_yield/yieldProportion")), {}),
      ])
      const normalized = normalizeWetlandBusiness(data, {
        typeRows,
        yieldRows,
        muYieldRows,
        levelRows,
        minTypeRows,
        edibleRows,
        edibleMuRows,
        typeDistributionRows,
        levelDistributionRows,
        minTypeDistributionRows,
        yieldSummary,
      })
      const result = {
        status: "success",
        ...normalized,
        left: normalized.leftPanels[0],
        right: normalized.rightPanels[0],
      }
      return applyLayerPanelSelection(result, topicKey, layerKey)
    }

    return buildFallbackTopicStats(topicKey, layerKey)
  } catch (error) {
    return {
      ...buildFallbackTopicStats(topicKey, layerKey),
      status: "error",
      error,
    }
  }
}

export async function getTopicCoreStats(topicKey) {
  try {
    if (topicKey === "woodland") {
      const data = normalizeResponseData(await post("/woodland/distribution"))
      return {
        status: "success",
        items: ensureCoreShape(normalizeWoodlandDistribution(data), topicKey),
      }
    }

    if (topicKey === "grassland") {
      const data = await tryRequests([
        async () => normalizeResponseData(await get("/basic_grassland/overview")),
        async () => normalizeResponseData(await get("/index/dataItem", { group: "grassLand" })),
        async () => normalizeResponseData(await get("/index/dataItem", { group: "grassland" })),
      ])
      const items = Array.isArray(data) ? normalizeDataItems(data) : normalizeBasicGrassland(data)
      return {
        status: "success",
        items: ensureCoreShape(items, topicKey),
      }
    }

    if (topicKey === "wetland") {
      const data = await tryRequests([
        async () => normalizeResponseData(await get("/index/dataItem", { group: "wetland" })),
        async () => normalizeResponseData(await get("/index/dataItem", { group: "wetland_grassland_level" })),
      ])
      return {
        status: "success",
        items: ensureCoreShape(normalizeDataItems(data), topicKey),
      }
    }

    return { status: "empty", items: [] }
  } catch (error) {
    return {
      status: "error",
      error,
      items: ensureCoreShape([], topicKey),
    }
  }
}

export async function getLayerTownRanking(topicKey, layerKey, legend = null) {
  try {
    const legendRanking = await getLegendTownRanking(topicKey, layerKey, legend)
    if (legendRanking) return legendRanking

    if (topicKey === "woodland") {
      if (layerKey === "woodland-protection") {
        return await getWfsTownAreaRanking({
          topicKey,
          layerKey,
          layerName: "ne:t_woodland_2023",
          title: "公益林面积排行",
          cqlFilter: "gjgyl_bhdj IN ('1','2')",
        }).catch(async () => {
          const data = normalizeResponseData(await post("/woodland/protection"))
          const rows = aggregateTownRankingRows(data?.regionRanks || [], {
            nameKeys: ["townName"],
            valueKeys: ["areaWanMu"],
            unit: "万亩",
          })
          return buildTownRanking({
            topicKey,
            layerKey,
            title: "公益林面积排行",
            unit: "万亩",
            rows,
            note: "按公益林村级榜单汇总到乡镇",
          })
        })
      }

      if (layerKey === "woodland-type") {
        return await getWfsTownAreaRanking({
          topicKey,
          layerKey,
          layerName: "ne:t_woodland_2023",
          title: "林地类型面积排行",
        }).catch(async () => {
          const data = normalizeResponseData(await post("/woodland/types"))
          const rows = aggregateTownRankingRows(data?.townComposition || [], {
            nameKeys: ["townName"],
            valueKeys: ["areaWanMu"],
            unit: "万亩",
          })
          return buildTownRanking({
            topicKey,
            layerKey,
            title: "林地类型面积排行",
            unit: "万亩",
            rows,
            note: "按林地类型组成汇总到乡镇",
          })
        })
      }

      if (layerKey === "woodland-quality") {
        return await getWfsTownAreaRanking({
          topicKey,
          layerKey,
          layerName: "ne:t_woodland_2023",
          title: "林地质量面积排行",
          cqlFilter: "zl_dj IS NOT NULL",
        })
      }

      if (layerKey === "woodland-ownership") {
        return await getWfsTownAreaRanking({
          topicKey,
          layerKey,
          layerName: "ne:t_woodland_2023",
          title: "林地权属面积排行",
          cqlFilter: "ld_qs IS NOT NULL",
        })
      }

      return await getWoodlandAreaRanking(topicKey, layerKey, "林地面积排行")
    }

    if (topicKey === "grassland") {
      if (layerKey === "basic-grassland") {
        return await getGrasslandAreaRanking(topicKey, layerKey, "basicAreaWanMu", "基本草原面积排行")
      }

      if (layerKey === "grassland-level") {
        return await getYieldRanking(topicKey, layerKey, "/grassland_yield/muYieldDistribution", "草地亩产排行", "斤")
      }

      return await getGrasslandAreaRanking(topicKey, layerKey, "totalAreaWanMu", "草地面积排行")
    }

    if (topicKey === "wetland") {
      if (layerKey === "wetland-level") {
        return await getYieldRanking(topicKey, layerKey, "/wetland_yield/muYieldDistribution", "湿地亩产排行", "斤")
      }

      if (layerKey === "wetland-type") {
        return await getYieldRanking(topicKey, layerKey, "/wetland_yield/edibleXcDistribution", "可食鲜草产量排行", "万吨")
      }

      return await getYieldRanking(topicKey, layerKey, "/wetland_yield/distribution", "湿地生产力排行", "万吨")
    }

    return buildTownRanking({
      topicKey,
      layerKey,
      title: "乡镇统计排行",
      rows: [],
    })
  } catch (error) {
    return {
      status: "error",
      topicKey,
      layerKey,
      title: "乡镇统计排行",
      unit: "",
      rows: [],
      error,
    }
  }
}
