import classifiedDataRaw from "./yakIndustryClassifiedData.json?raw"
import {
  estimatedStock,
  grasslandYakRows,
  homeCore,
  townRecognitionRows,
} from "@/views/gdMap/livestockData"
import { hongyuanTownshipLabelPoints } from "@/config/townshipBoundaries"
import { HONGYUAN_BOUNDS } from "@/config/layers"

export const industryStageDefs = [
  { key: "family-pasture", name: "家庭生态牧场", color: "#24f6c4", unit: "户", metricLabel: "牧场", width: 126 },
  { key: "artificial-grassland", name: "人工草地", color: "#7ee269", unit: "万亩", metricLabel: "草地", width: 112 },
  { key: "scale-breeding", name: "规模化养殖基地", subName: "牦牛选育场", color: "#32dcff", unit: "个", metricLabel: "基地", width: 132 },
  { key: "forage-storage", name: "防灾减灾", subName: "饲草储备库", color: "#ffe06b", unit: "吨", metricLabel: "库容", width: 126 },
  { key: "slaughter-processing", name: "屠宰与加工", color: "#ff9a62", unit: "万元", metricLabel: "产值", width: 112 },
  { key: "farm-equipment", name: "农机装备", color: "#30dcff", unit: "个", metricLabel: "装备", width: 112 },
  { key: "social-service", name: "社会化服务", subName: "金融/疫病/保险/培训", color: "#9ea7ff", unit: "个", metricLabel: "主体", width: 132 },
]

const townNames = grasslandYakRows.map((item) => item.zoneName)
const townCenterByName = new Map(hongyuanTownshipLabelPoints.map((item) => [item.name, item.center]))
const classifiedData = JSON.parse(classifiedDataRaw)
const categoryList = classifiedData.categories || []
const categoryMap = new Map(categoryList.map((item) => [item.categoryCode, item]))
const nonBusinessNames = new Set([
  "企业全称",
  "主体全称",
  "畜牧工作站",
  "规划建设股",
  "执法大队",
  "疫控中心",
  "科教股",
  "科技股",
  "乡村振兴股",
  "农产品检测站",
  "数据欠缺，请两个股室核定饲草基地数据。",
  "对接相关科研院校收集数据",
])
const nonBusinessCategoryCodes = new Set(["YC-GRASSLAND-RESOURCE", "YC-CXPT-OTHER-BASE"])
const nonBusinessNamePatterns = [/^林草局数据-\d+$/, /^(技术培训|金融服务网点|保险服务网点)-\d+$/]
const unrelatedYakChainNamePatterns = [/蔬菜/, /金针菇/, /植物园/, /污水/, /物联网/, /绵羊/]

const allClassifiedItems = categoryList.flatMap((category) =>
  (category.items || []).map((item) => ({
    ...item,
    categoryCode: category.categoryCode,
    categoryName: category.categoryName,
    stageKey: category.industryStage,
    stageName: getStageDef(category.industryStage)?.name || category.categoryName,
  })),
)
const businessItems = allClassifiedItems.filter(isBusinessItem)
const itemById = new Map(allClassifiedItems.map((item) => [String(item.id), item]))

const familyPastureItems = categoryItems("YC-FAMILY-PASTURE")
const breedingStockItems = categoryItems(["YC-BREEDING-STOCK", "YC-CXPT-BREEDING-STOCK-BASE"])
const forageBaseItems = categoryItems(["YC-FORAGE-BASE", "YC-CXPT-FORAGE-BASE", "YC-CXPT-GRASS-SEED-BASE"])
const forageStorageItems = categoryItems("YC-DISASTER-FORAGE-STORAGE")
const processingItems = categoryItems("YC-PROCESSING-PLANT")
const slaughterItems = categoryItems("YC-SLAUGHTERHOUSE")
const farmEquipmentItems = categoryItems("YC-FARM-EQUIPMENT")
const diseaseControlItems = categoryItems("YC-DISEASE-CONTROL")
const trainingItems = categoryItems("YC-TECH-TRAINING")
const financeItems = categoryItems("YC-SERVICE-FINANCE")
const insuranceItems = categoryItems("YC-SERVICE-INSURANCE")

const familyPastureTotal = countBusinessItems(familyPastureItems)
const forageBaseTotal = countBusinessItems(forageBaseItems)
const forageStorageTotal = countBusinessItems(forageStorageItems)
const breedingStockTotal = countBusinessItems(breedingStockItems)
const processingTotal = countBusinessItems(processingItems)
const slaughterTotal = countBusinessItems(slaughterItems)
const farmEquipmentTotal = countBusinessItems(farmEquipmentItems)
const diseaseControlTotal = countBusinessItems(diseaseControlItems)
const trainingTotal = countBusinessItems(trainingItems)
const financeTotal = countBusinessItems(financeItems)
const insuranceTotal = countBusinessItems(insuranceItems)
const businessCategoryTotal = categoryList.filter((category) => categoryItems(category.categoryCode).some(isBusinessItem)).length
const sourceItemTotal = businessItems.length
const coveredTownTotal = new Set(businessItems.map(normalizeTown).filter(Boolean)).size || townNames.length
const equipmentTotal = Math.max(farmEquipmentTotal, townRecognitionRows.reduce((sum, item) => sum + Number(item.devices || 0), 0))

const forageAreaMu = sumBy(forageBaseItems, (item) => metricValue(item, ["种植面积 (亩)", "acreage"]) || parseNumber(item.scale))
const storageCapacity = sumBy(forageStorageItems, (item) => metricValue(item, ["总库容 (吨)"]))
const breedingDesignStock = sumBy(categoryItems("YC-BREEDING-BASE"), (item) => metricValue(item, ["设计存栏量 (头)"]))
const breedingAnnualOutput = sumBy(categoryItems("YC-BREEDING-BASE"), (item) => metricValue(item, ["年出栏量 (头)"]))
const processingOutputValue = sumBy(processingItems, (item) => metricValue(item, ["年产值 (万元)"]))
const processingRawCapacity = sumBy(processingItems, (item) => metricValue(item, ["年加工鲜奶总量 (吨)", "年加工原料肉总量 (吨)"]))
const processingDrivenHouseholds = sumBy(processingItems, (item) => metricValue(item, ["带动本地农户数"]))
const slaughterOutputValue = sumBy(slaughterItems, (item) => metricValue(item, ["年总产值 (万元)"]))
const slaughterAnnualHeads = sumBy(slaughterItems, (item) => metricValue(item, ["年屠宰总量 (头)"]))
const slaughterColdCapacity = sumBy(slaughterItems, (item) => metricValue(item, ["冷冻库容量 (吨)"]))
const industryOutputValue = processingOutputValue + slaughterOutputValue
const financeMaxLoan = maxByValue(financeItems, (item) => metricValue(item, ["最高单户贷款额度 (万元)"]))
const financeMaxTownCoverage = maxByValue(financeItems, (item) => metricValue(item, ["服务覆盖乡镇数"]))
const insuranceMaxTownCoverage = maxByValue(insuranceItems, (item) => metricValue(item, ["服务覆盖乡镇数"]))
const trainingSessionCount = sumBy(trainingItems, (item) => metricValue(item, ["年培训场次"]))
const trainingPersonCount = sumBy(trainingItems, (item) => metricValue(item, ["年培训人次"]))
const breedingBaseItems = categoryItems("YC-BREEDING-BASE")
const forageGrassTypeRows = buildGrassTypeRows([...forageBaseItems, ...forageStorageItems])
const processingChainRows = buildProcessingChainRows()
const serviceTypeRows = buildServiceTypeRows()
const equipmentDeviceRows = townRecognitionRows
  .map((item) => ({
    key: item.name,
    name: item.name,
    value: Number(item.devices || 0),
    unit: "套",
    extra: `${formatNumber(item.count)}头识别样本`,
  }))
  .filter((item) => item.value > 0)
  .sort(sortByValue)
const equipmentRecognitionRows = townRecognitionRows
  .map((item) => ({
    key: item.name,
    name: item.name,
    value: Number(item.count || 0),
    unit: "头",
    extra: `${formatNumber(item.devices)}套设备`,
  }))
  .filter((item) => item.value > 0)
  .sort(sortByValue)
const farmEquipmentPointRows = buildFarmEquipmentPointRows()
const grasslandResourceWanMu = round(homeCore.grasslandArea / 10000, 2)

export const industryDatasetGeneratedAt = classifiedData.generatedAt || ""
export const supportPointRows = forageStorageItems.map(toLegacyPointRow)
export const processingPointRows = [...processingItems, ...slaughterItems].map(toLegacyPointRow)
export const industryPointRows = businessItems.map(toLegacyPointRow)
export const industryChainListRows = businessItems
  .map(toIndustryChainListRow)
  .sort((a, b) => Number(b.canLocate) - Number(a.canLocate) || a.stageOrder - b.stageOrder || String(a.name).localeCompare(String(b.name), "zh-CN"))
const industryMapPointTotal = industryStageDefs.reduce((sum, stage) => sum + stagePointCount(stage.key), 0)
const pointCoveredTownTotal = new Set(industryStageDefs.flatMap((stage) => getStagePointListRows(stage.key).map((row) => row.town)).filter(Boolean)).size || townNames.length

export const industryTopStats = [
  { zh: "产业点位", name: "产业点位", value: industryMapPointTotal, unit: "个" },
  { zh: "产业产值", name: "产业产值", value: round(industryOutputValue, 1), unit: "万元", decimals: 1 },
  { zh: "饲草库容", name: "饲草库容", value: storageCapacity, unit: "吨" },
  { zh: "覆盖乡镇", name: "覆盖乡镇", value: pointCoveredTownTotal, unit: "个" },
]

export function getStageTopStats(stageKey) {
  const fallbackRow = getStageRow(stageKey)
  const stageStats = {
    "family-pasture": [
      { zh: "家庭生态牧场", name: "家庭生态牧场", value: familyPastureTotal, unit: "户" },
      { zh: "估算存栏", name: "估算存栏", value: estimatedStock, unit: "头" },
      { zh: "覆盖乡镇", name: "覆盖乡镇", value: uniqueCount(familyPastureItems, normalizeTown), unit: "个" },
      { zh: "户均存栏", name: "户均存栏", value: round(estimatedStock / Math.max(familyPastureTotal, 1)), unit: "头/户" },
    ],
    "artificial-grassland": [
      { zh: "种草面积", name: "种草面积", value: round(forageAreaMu / 10000, 2), unit: "万亩", decimals: 2 },
      { zh: "饲草点位", name: "饲草点位", value: stagePointCount("artificial-grassland"), unit: "个" },
      { zh: "草种类型", name: "草种类型", value: forageGrassTypeRows.length, unit: "类" },
      { zh: "草地资源", name: "草地资源", value: grasslandResourceWanMu, unit: "万亩", decimals: 2 },
    ],
    "scale-breeding": [
      { zh: "养殖点位", name: "养殖点位", value: stagePointCount("scale-breeding"), unit: "个" },
      { zh: "设计存栏", name: "设计存栏", value: breedingDesignStock, unit: "头" },
      { zh: "年出栏", name: "年出栏", value: breedingAnnualOutput, unit: "头" },
      { zh: "育种场", name: "育种场", value: breedingStockTotal, unit: "个" },
    ],
    "forage-storage": [
      { zh: "储备库", name: "储备库", value: forageStorageTotal, unit: "个" },
      { zh: "总库容", name: "总库容", value: storageCapacity, unit: "吨" },
      { zh: "覆盖乡镇", name: "覆盖乡镇", value: uniqueCount(forageStorageItems, normalizeTown), unit: "个" },
      { zh: "草种类型", name: "草种类型", value: forageGrassTypeRows.length, unit: "类" },
    ],
    "slaughter-processing": [
      { zh: "加工屠宰点位", name: "加工屠宰点位", value: stagePointCount("slaughter-processing"), unit: "个" },
      { zh: "产业产值", name: "产业产值", value: round(industryOutputValue, 1), unit: "万元", decimals: 1 },
      { zh: "年屠宰量", name: "年屠宰量", value: slaughterAnnualHeads, unit: "头" },
      { zh: "带动农户", name: "带动农户", value: processingDrivenHouseholds, unit: "户" },
    ],
    "farm-equipment": [
      { zh: "监测点位", name: "监测点位", value: stagePointCount("farm-equipment"), unit: "个" },
      { zh: "识别设备", name: "识别设备", value: townRecognitionRows.reduce((sum, item) => sum + Number(item.devices || 0), 0), unit: "套" },
      { zh: "乡镇样本", name: "乡镇样本", value: townRecognitionRows.length, unit: "个" },
      { zh: "识别样本", name: "识别样本", value: townRecognitionRows.reduce((sum, item) => sum + Number(item.count || 0), 0), unit: "头" },
    ],
    "social-service": [
      { zh: "服务点位", name: "服务点位", value: stagePointCount("social-service"), unit: "个" },
      { zh: "最高授信", name: "最高授信", value: financeMaxLoan, unit: "万元" },
      { zh: "培训人次", name: "培训人次", value: trainingPersonCount, unit: "人次" },
      { zh: "服务类型", name: "服务类型", value: serviceTypeRows.length, unit: "类" },
    ],
  }

  return (stageStats[stageKey] || [
    { zh: fallbackRow.name, name: fallbackRow.name, value: fallbackRow.value, unit: fallbackRow.unit },
    { zh: fallbackRow.capacityUnit ? "能力规模" : "主体规模", name: fallbackRow.capacityUnit ? "能力规模" : "主体规模", value: fallbackRow.capacity, unit: fallbackRow.capacityUnit },
    ...(fallbackRow.fields || []).map((item) => ({
      zh: item.label,
      name: item.label,
      value: item.value,
      unit: item.unit,
    })),
  ]).filter((item) => item.value !== undefined && item.value !== null && item.value !== "").slice(0, 4)
}

export const industryOverviewRows = [
  { key: "chain-subject", name: "产业点位", value: industryMapPointTotal, unit: "个", icon: "town", extra: `${businessCategoryTotal}类主体` },
  { key: "chain-town", name: "镇域覆盖", value: pointCoveredTownTotal, unit: "个", icon: "town", extra: "全链覆盖" },
  { key: "chain-output", name: "产业产值", value: round(industryOutputValue, 1), unit: "万元", icon: "certificate", extra: "加工+屠宰" },
  { key: "chain-forage", name: "饲草库容", value: storageCapacity, unit: "吨", icon: "yield", extra: "防灾储备" },
]

export const stageCompositionRows = industryStageDefs.map((stage) => ({
  key: stage.key,
  name: stage.name,
  value: stagePointCount(stage.key),
  unit: stage.key === "family-pasture" ? "户" : "个",
  color: stage.color,
}))

export const industryStageRows = [
  {
    key: "family-pasture",
    name: "家庭生态牧场",
    value: familyPastureTotal,
    unit: "户",
    capacity: estimatedStock,
    capacityUnit: "头",
    note: "家庭生态牧场与牦牛养殖基础",
    fields: [
      { label: "家庭生态牧场", value: familyPastureTotal, unit: "户" },
      { label: "覆盖乡镇", value: uniqueCount(familyPastureItems, normalizeTown), unit: "个" },
      { label: "户均存栏", value: round(estimatedStock / Math.max(familyPastureTotal, 1)), unit: "头/户" },
    ],
  },
  {
    key: "artificial-grassland",
    name: "人工草地",
    value: round(forageAreaMu / 10000, 2),
    unit: "万亩",
    capacity: grasslandResourceWanMu,
    capacityUnit: "万亩",
    note: "种草饲草基地、草种基地与草地资源",
    fields: [
      { label: "种草面积", value: round(forageAreaMu / 10000, 2), unit: "万亩" },
      { label: "饲草点位", value: stagePointCount("artificial-grassland"), unit: "个" },
      { label: "草种类型", value: 3, unit: "类" },
    ],
  },
  {
    key: "scale-breeding",
    name: "规模化养殖基地",
    value: stagePointCount("scale-breeding"),
    unit: "个",
    capacity: breedingDesignStock,
    capacityUnit: "头",
    note: "标准化养殖、选育扩繁与种畜基地",
    fields: [
      { label: "设计存栏", value: breedingDesignStock, unit: "头" },
      { label: "年出栏", value: breedingAnnualOutput, unit: "头" },
      { label: "育种场", value: breedingStockTotal, unit: "个" },
    ],
  },
  {
    key: "forage-storage",
    name: "防灾减灾饲草储备库",
    value: forageStorageTotal,
    unit: "个",
    capacity: storageCapacity,
    capacityUnit: "吨",
    note: "饲草储备、防灾调拨和草种保障",
    fields: [
      { label: "储备库", value: forageStorageTotal, unit: "个" },
      { label: "总库容", value: storageCapacity, unit: "吨" },
      { label: "覆盖乡镇", value: uniqueCount(forageStorageItems, normalizeTown), unit: "个" },
    ],
  },
  {
    key: "slaughter-processing",
    name: "屠宰与加工",
    value: stagePointCount("slaughter-processing"),
    unit: "个",
    capacity: round(industryOutputValue, 1),
    capacityUnit: "万元",
    note: "乳品加工、肉制品加工与定点屠宰",
    fields: [
      { label: "加工产值", value: processingOutputValue, unit: "万元" },
      { label: "屠宰产值", value: round(slaughterOutputValue, 1), unit: "万元" },
      { label: "年屠宰量", value: slaughterAnnualHeads, unit: "头" },
    ],
  },
  {
    key: "farm-equipment",
    name: "农机装备",
    value: stagePointCount("farm-equipment"),
    unit: "个",
    capacity: equipmentTotal,
    capacityUnit: "套",
    note: "农机服务主体与生产监测设备",
    fields: [
      { label: "监测点位", value: stagePointCount("farm-equipment"), unit: "个" },
      { label: "识别设备", value: townRecognitionRows.reduce((sum, item) => sum + Number(item.devices || 0), 0), unit: "套" },
      { label: "乡镇样本", value: townRecognitionRows.length, unit: "个" },
    ],
  },
  {
    key: "social-service",
    name: "社会化服务",
    value: stagePointCount("social-service"),
    unit: "个",
    capacity: financeMaxLoan,
    capacityUnit: "万元",
    note: "金融、保险、防疫、培训和其他服务网点",
    fields: [
      { label: "金融网点", value: financeTotal, unit: "家" },
      { label: "最高授信", value: financeMaxLoan, unit: "万元" },
      { label: "培训人次", value: trainingPersonCount, unit: "人次" },
    ],
  },
]

export const breedingLevelRows = buildBreedingLevelRows()

export const forageSecurityRows = aggregateRows(forageStorageItems, normalizeTown, (item) => metricValue(item, ["总库容 (吨)"]))
  .map((item) => ({ ...item, unit: "吨", extra: `${item.count}个库点` }))

export const industryValueRows = [
  { key: "milk-processing", name: "乳品加工", value: sumBy(processingItems.filter(isMilkProcessing), (item) => metricValue(item, ["年产值 (万元)"])), unit: "万元", color: "#32dcff" },
  { key: "meat-processing", name: "肉品加工", value: sumBy(processingItems.filter(isMeatProcessing), (item) => metricValue(item, ["年产值 (万元)"])), unit: "万元", color: "#ff9a62" },
  { key: "slaughter-output", name: "定点屠宰", value: round(slaughterOutputValue, 1), unit: "万元", color: "#ffe06b" },
].filter((item) => item.value > 0)

export const processingAbilityRows = [
  { key: "raw-capacity", name: "年加工原料", value: processingRawCapacity, unit: "吨", extra: `${processingItems.filter(isBusinessItem).length}家加工主体` },
  { key: "slaughter-heads", name: "年屠宰总量", value: slaughterAnnualHeads, unit: "头", extra: `${slaughterItems.filter(isBusinessItem).length}家定点屠宰` },
  { key: "farmer-driven", name: "带动本地农户", value: processingDrivenHouseholds, unit: "户", extra: "加工企业申报" },
  { key: "cold-storage", name: "冷冻/冷藏能力", value: slaughterColdCapacity, unit: "吨", extra: "屠宰冷链" },
]

export const serviceCapabilityRows = [
  { key: "finance", name: "金融服务", value: scoreBy(financeMaxTownCoverage, 10), count: financeTotal, unit: "家", extra: `最高${formatNumber(financeMaxLoan)}万元` },
  { key: "insurance", name: "保险服务", value: scoreBy(insuranceMaxTownCoverage, 10), count: insuranceTotal, unit: "家", extra: `覆盖${formatNumber(insuranceMaxTownCoverage)}乡镇` },
  { key: "training", name: "技术培训", value: scoreBy(trainingPersonCount, 200), count: trainingTotal, unit: "家", extra: `${formatNumber(trainingPersonCount)}人次` },
  { key: "disease", name: "疫病防控", value: scoreBy(diseaseControlTotal, 4), count: diseaseControlTotal, unit: "个", extra: "防疫主体" },
  { key: "equipment", name: "农机装备", value: scoreBy(farmEquipmentTotal, 3), count: farmEquipmentTotal, unit: "个", extra: "服务主体" },
]

export function getStagePanelConfig(stageKey) {
  const stage = getStageDef(stageKey)
  const subjectRows = getStageSubjectRows(stageKey)
  const configs = {
    "family-pasture": {
      left: [
        chartPanel("family-town", "牧场镇域分布", "column", getStageCapacityRows(stageKey), { variant: "townCompact", scrollable: false }),
        chartPanel("family-town-stock", "镇域存栏支撑", "column", getTownYakStockRows(), { variant: "townCompact", scrollable: false }),
        chartPanel("family-grass-resource", "草地资源保障", "structure", getTownGrasslandResourceRows()),
      ],
      right: [
        industryChainListPanel(stageKey),
      ],
    },
    "artificial-grassland": {
      left: [
        chartPanel("grass-town", "种草面积分布", "column", getStageCapacityRows(stageKey), { variant: "townCompact", scrollable: false }),
        chartPanel("grass-base-town", "基地点位分布", "column", getTownCountRows(forageBaseItems, "基地点位"), { variant: "townCompact", scrollable: false }),
        chartPanel("grass-type", "草种保障结构", "donut", forageGrassTypeRows, { variant: "ring" }),
      ],
      right: [
        industryChainListPanel(stageKey),
      ],
    },
    "scale-breeding": {
      left: [
        chartPanel("breeding-stock", "设计存栏分布", "column", getStageCapacityRows(stageKey), { variant: "townCompact", scrollable: false }),
        chartPanel("breeding-output", "年出栏能力分布", "column", getTownMetricRows(breedingBaseItems, ["年出栏量 (头)"], { unit: "头", extra: "年出栏" }), { variant: "townCompact", scrollable: false }),
        chartPanel("breeding-level", "育种等级结构", "donut", breedingLevelRows, { variant: "ring" }),
      ],
      right: [
        industryChainListPanel(stageKey),
      ],
    },
    "forage-storage": {
      left: [
        chartPanel("storage-town", "库容镇域分布", "column", getStageCapacityRows(stageKey), { variant: "townCompact", scrollable: false }),
        chartPanel("storage-point", "库点数量分布", "column", getTownCountRows(forageStorageItems, "储备库点"), { variant: "townCompact", scrollable: false }),
        chartPanel("storage-grass", "储备草种结构", "structure", forageGrassTypeRows),
      ],
      right: [
        industryChainListPanel(stageKey),
      ],
    },
    "slaughter-processing": {
      left: [
        chartPanel("processing-value", "产值结构", "donut", industryValueRows, { variant: "ring" }),
        chartPanel("processing-chain", "产能与带动", "structure", processingChainRows),
        chartPanel("processing-heads", "屠宰能力分布", "column", getTownMetricRows(slaughterItems, ["年屠宰总量 (头)"], { unit: "头", extra: "年屠宰" }), { variant: "townCompact", scrollable: false }),
      ],
      right: [
        industryChainListPanel(stageKey),
      ],
    },
    "farm-equipment": {
      left: [
        chartPanel("equipment-device", "识别设备分布", "column", completeTownColumnRows(equipmentDeviceRows, { unit: "套", extra: "识别设备" }), { variant: "townCompact", scrollable: false }),
        chartPanel("equipment-recognition", "识别样本分布", "column", completeTownColumnRows(equipmentRecognitionRows, { unit: "头", extra: "识别样本" }), { variant: "townCompact", scrollable: false }),
      ],
      right: [
        industryChainListPanel(stageKey),
      ],
    },
    "social-service": {
      left: [
        chartPanel("service-type", "服务主体结构", "donut", serviceTypeRows, { variant: "ring" }),
        chartPanel("service-town", "服务镇域分布", "column", getTownCountRows([...diseaseControlItems, ...trainingItems, ...financeItems, ...insuranceItems], "服务主体"), { variant: "townCompact", scrollable: false }),
        chartPanel("service-training-town", "培训人次分布", "column", getTownMetricRows(trainingItems, ["年培训人次"], { unit: "人次", extra: "技术培训" }), { variant: "townCompact", scrollable: false }),
        chartPanel("service-training", "培训服务能力", "line", getTrainingRows()),
      ],
      right: [
        industryChainListPanel(stageKey),
      ],
    },
  }

  const fallback = {
    left: [
      chartPanel(`${stage.key}-rank`, `${stage.metricLabel}分布`, "column", getStageCapacityRows(stageKey), { variant: "townCompact", scrollable: false }),
      chartPanel(`${stage.key}-subject`, "主体结构", "structure", subjectRows),
      chartPanel(`${stage.key}-town`, "镇域覆盖分布", "column", completeTownColumnRows(getStageTownRows(stageKey), { unit: "个", extra: "镇域覆盖" }), { variant: "townCompact", scrollable: false }),
      chartPanel(`${stage.key}-capacity`, "能力规模分布", "split", getStageCapacityRows(stageKey).slice(0, 7)),
    ],
    right: [
      industryChainListPanel(stageKey),
    ],
  }

  return configs[stageKey] || fallback
}

export const industryFinancialRows = [
  { key: "support-capacity", name: "饲草储备能力", value: storageCapacity, unit: "吨", extra: `${forageStorageTotal}个库点` },
  { key: "processing-capacity", name: "加工原料规模", value: processingRawCapacity, unit: "吨", extra: `${processingItems.filter(isBusinessItem).length}家加工主体` },
  { key: "processing-output", name: "加工屠宰产值", value: round(industryOutputValue, 1), unit: "万元", extra: "加工+屠宰" },
  { key: "finance-credit", name: "最高单户授信", value: financeMaxLoan, unit: "万元", extra: "金融服务" },
]

export function getStageDef(key) {
  return industryStageDefs.find((item) => item.key === key) || industryStageDefs[0]
}

export function getStageRow(key) {
  return industryStageRows.find((item) => item.key === key) || industryStageRows[0]
}

export function getStageInsightRows(stageKey) {
  return getStageRow(stageKey).fields || []
}

export function getStageCapacityRows(stageKey) {
  if (stageKey === "family-pasture") {
    const rows = aggregateRows(familyPastureItems, normalizeTown, () => 1)
      .map((item) => ({ ...item, unit: "户", extra: "家庭生态牧场" }))
    return completeTownColumnRows(rows, { unit: "户", extra: "家庭生态牧场" })
  }
  if (stageKey === "artificial-grassland") {
    const rows = aggregateRows(forageBaseItems, normalizeTown, (item) => metricValue(item, ["种植面积 (亩)", "acreage"]) || parseNumber(item.scale))
      .map((item) => ({ ...item, value: round(item.value / 10000, 2), unit: "万亩", extra: `${item.count}个基地` }))
    return completeTownColumnRows(rows, { unit: "万亩", extra: "种草基地" })
  }
  if (stageKey === "scale-breeding") {
    const rows = aggregateRows(categoryItems("YC-BREEDING-BASE"), normalizeTown, (item) => metricValue(item, ["设计存栏量 (头)"]))
      .map((item) => ({ ...item, unit: "头", extra: `${item.count}个基地` }))
    return completeTownColumnRows(rows, { unit: "头", extra: "养殖基地" })
  }
  if (stageKey === "forage-storage") {
    return completeTownColumnRows(forageSecurityRows, { unit: "吨", extra: "饲草储备" })
  }
  if (stageKey === "slaughter-processing") {
    return [...processingItems, ...slaughterItems]
      .filter(isBusinessItem)
      .map((item) => ({
        key: item.id,
        name: compactName(item.name),
        value: metricValue(item, ["年产值 (万元)", "年总产值 (万元)"]),
        unit: "万元",
        extra: item.categoryName,
      }))
      .filter((item) => item.value > 0)
      .sort(sortByValue)
      .slice(0, 7)
  }
  if (stageKey === "farm-equipment") {
    return farmEquipmentItems.filter(isBusinessItem).map((item) => ({
      key: item.id,
      name: compactName(item.name),
      value: 1,
      unit: "个",
      extra: item.attributes?.简称 || "农机服务",
    }))
  }
  if (stageKey === "social-service") {
    return [
      { key: "finance", name: "金融服务网点", value: financeTotal, unit: "家", extra: `最高${formatNumber(financeMaxLoan)}万元` },
      { key: "insurance", name: "保险服务网点", value: insuranceTotal, unit: "家", extra: `覆盖${formatNumber(insuranceMaxTownCoverage)}乡镇` },
      { key: "training", name: "技术培训机构", value: trainingTotal, unit: "家", extra: `${formatNumber(trainingSessionCount)}场` },
      { key: "disease", name: "疫病防控主体", value: diseaseControlTotal, unit: "个", extra: "防疫服务" },
    ]
  }
  return []
}

export function getStageTownRows(stageKey) {
  return aggregateRows(stageItems(stageKey), normalizeTown, () => 1).map((item) => ({
    ...item,
    unit: "个",
    extra: `${item.count}条`,
  }))
}

export function getStageDetailRows(stageKey) {
  return stageItems(stageKey)
    .filter(isBusinessItem)
    .map(toDetailRow)
    .sort((a, b) => b.numericValue - a.numericValue || a.name.localeCompare(b.name, "zh-CN"))
}

export function getPointExtraRows(point = {}) {
  const item = findClassifiedItem(point)
  if (!item) return []
  const rows = []
  const metrics = item.metrics || {}
  const attrs = item.attributes || {}
  const add = (label, value, unit = "") => {
    if (isBlank(value)) return
    rows.push({ label, value: formatValueWithUnit(value, unit) })
  }
  add("运营单位", attrs["运营单位"])
  add("育种等级", attrs["育种等级"])
  add("育种方向", attrs["主要育种方向"])
  add("设计存栏", metrics["设计存栏量 (头)"], "头")
  add("年出栏量", metrics["年出栏量 (头)"], "头")
  add("种植面积", metrics["种植面积 (亩)"] || item.scale, item.scale ? "" : "亩")
  add("总库容", metrics["总库容 (吨)"], "吨")
  add("年产值", metrics["年产值 (万元)"] || metrics["年总产值 (万元)"], "万元")
  add("年加工量", metrics["年加工鲜奶总量 (吨)"] || metrics["年加工原料肉总量 (吨)"], "吨")
  add("年屠宰量", metrics["年屠宰总量 (头)"], "头")
  add("服务覆盖", metrics["服务覆盖乡镇数"], "个乡镇")
  add("最高授信", metrics["最高单户贷款额度 (万元)"], "万元")
  add("主要产品", attrs["主要产品"])
  add("主要草种", attrs["主要草种"] || attrs["储备草种"])
  return rows.slice(0, 8)
}

function categoryItems(codes) {
  const codeList = Array.isArray(codes) ? codes : [codes]
  return codeList.flatMap((code) => {
    const category = categoryMap.get(code)
    return (category?.items || []).map((item) => ({
      ...item,
      categoryCode: category.categoryCode,
      categoryName: category.categoryName,
      stageKey: category.industryStage,
      stageName: getStageDef(category.industryStage)?.name || category.categoryName,
    }))
  })
}

function stageItems(stageKey) {
  return businessItems.filter((item) => item.stageKey === stageKey)
}

function stageItemCount(stageKey) {
  return stageItems(stageKey).length
}

function getStagePointListRows(stageKey) {
  if (stageKey === "farm-equipment") return farmEquipmentPointRows
  return industryChainListRows.filter((row) => row.stageKey === stageKey && row.canLocate)
}

function stagePointCount(stageKey) {
  return getStagePointListRows(stageKey).length
}

function buildFarmEquipmentPointRows() {
  return townRecognitionRows
    .map((item, index) => {
      const center = townCenterByName.get(item.name)
      const longitude = Number(center?.[0])
      const latitude = Number(center?.[1])
      if (!isCoordinateInHongyuanBounds(longitude, latitude)) return null
      const key = `YC-FARM-EQUIPMENT-TOWN-${String(index + 1).padStart(3, "0")}`
      const name = `${item.name}农机装备监测点`
      const devices = Number(item.devices || 0)
      const count = Number(item.count || 0)
      return {
        key,
        id: key,
        name,
        fullName: name,
        stageKey: "farm-equipment",
        stageName: getStageDef("farm-equipment").name,
        stageOrder: industryStageDefs.findIndex((stage) => stage.key === "farm-equipment"),
        typeName: "农机装备监测点",
        categoryName: "农机装备监测点",
        town: item.name,
        address: `${item.name}乡镇中心`,
        status: "监测样本",
        value: devices,
        unit: "套",
        numericValue: devices,
        valueText: `${formatNumber(devices)}套`,
        extra: `${formatNumber(count)}头识别样本`,
        longitude,
        latitude,
        locateText: "定位",
        canLocate: true,
        searchText: [name, "农机装备", item.name, `${devices}套`, `${count}头识别样本`].join(" "),
      }
    })
    .filter(Boolean)
    .sort((a, b) => b.numericValue - a.numericValue || String(a.name).localeCompare(String(b.name), "zh-CN"))
}

function isBusinessItem(item = {}) {
  const name = cleanText(item.name)
  const sourceOwner = cleanText(item.attributes?.["序号"])
  if (!name || nonBusinessNames.has(name) || nonBusinessCategoryCodes.has(item.categoryCode)) return false
  if (unrelatedYakChainNamePatterns.some((pattern) => pattern.test(name))) return false
  if (item.categoryCode === "YC-FAMILY-PASTURE" && !getItemCoordinate(item)) return false
  if (sourceOwner && nonBusinessNames.has(sourceOwner) && !hasBusinessMetric(item)) return false
  if (nonBusinessNamePatterns.some((pattern) => pattern.test(name))) return false
  return true
}

function countBusinessItems(rows = []) {
  return rows.filter(isBusinessItem).length
}

function hasBusinessMetric(item = {}) {
  return Object.values(item.metrics || {}).some((value) => parseNumber(value) > 0)
}

function toLegacyPointRow(item = {}) {
  const value = primaryValue(item)
  return {
    key: String(item.id || item.name),
    name: item.name,
    stageKey: item.stageKey,
    typeName: item.categoryName,
    categoryName: item.categoryName,
    town: normalizeTown(item),
    address: item.address || item.village || item.areaFullName || "",
    status: item.status || "",
    products: item.attributes?.["主要产品"] || item.attributes?.["主要草种"] || item.attributes?.["储备草种"] || item.attributes?.["主要育种方向"] || "",
    capacity: value,
    capacityUnit: primaryUnit(item),
    outputValue: metricValue(item, ["年产值 (万元)", "年总产值 (万元)"]),
    longitude: item.longitude,
    latitude: item.latitude,
  }
}

function toDetailRow(item = {}) {
  const value = primaryValue(item)
  const unit = primaryUnit(item)
  const town = normalizeTown(item)
  return {
    key: String(item.id || item.name),
    name: compactName(item.name),
    fullName: item.name,
    stageKey: item.stageKey,
    typeName: item.categoryName,
    categoryName: item.categoryName,
    town: town || "全县",
    address: item.address || item.village || item.areaFullName || "",
    status: item.status || "待完善",
    value,
    unit,
    numericValue: Number(value) || 0,
    valueText: buildPrimaryValueText(item, value, unit),
    extra: buildDetailExtra(item),
    sourceSheet: item.sourceSheet,
  }
}

function toIndustryChainListRow(item = {}) {
  const row = toDetailRow(item)
  const coordinate = getItemCoordinate(item)
  const stage = getStageDef(item.stageKey)
  const fullName = cleanText(item.name)
  const categoryName = cleanText(item.categoryName).replace(/^cxpt/i, "")
  const address = cleanText(item.address || item.village || item.areaFullName || "")
  const attrs = item.attributes || {}
  const metrics = item.metrics || {}
  const searchText = [
    fullName,
    row.name,
    stage?.name,
    categoryName,
    row.town,
    address,
    attrs["简称"],
    attrs["运营单位"],
    attrs["主要产品"],
    attrs["主要草种"],
    attrs["储备草种"],
    attrs["主要育种方向"],
    metrics["主要贷款产品（可多选）"],
    row.valueText,
    row.extra,
    item.sourceSheet,
  ].filter(Boolean).join(" ")
  return {
    ...row,
    name: row.name,
    fullName,
    stageName: stage?.name || row.stageName || "",
    stageOrder: industryStageDefs.findIndex((stageItem) => stageItem.key === item.stageKey),
    categoryName,
    address,
    longitude: coordinate?.longitude ?? "",
    latitude: coordinate?.latitude ?? "",
    locateText: coordinate ? "定位" : "暂无",
    canLocate: Boolean(coordinate),
    searchText,
  }
}

function primaryValue(item = {}) {
  if (item.stageKey === "family-pasture") return 1
  if (item.categoryCode === "YC-BREEDING-STOCK") return item.attributes?.["育种等级"] || "待完善"
  if (item.categoryCode === "YC-CXPT-BREEDING-STOCK-BASE") return parseNumber(item.scale) || 1
  if (item.categoryCode === "YC-BREEDING-BASE") return metricValue(item, ["设计存栏量 (头)"])
  if (item.categoryCode === "YC-FORAGE-BASE") return metricValue(item, ["种植面积 (亩)"])
  if (item.categoryCode === "YC-DISASTER-FORAGE-STORAGE") return metricValue(item, ["总库容 (吨)"])
  if (item.categoryCode === "YC-PROCESSING-PLANT") return metricValue(item, ["年产值 (万元)"]) || metricValue(item, ["年加工鲜奶总量 (吨)", "年加工原料肉总量 (吨)"])
  if (item.categoryCode === "YC-SLAUGHTERHOUSE") return metricValue(item, ["年总产值 (万元)"]) || metricValue(item, ["年屠宰总量 (头)"])
  if (item.categoryCode === "YC-SERVICE-FINANCE") return metricValue(item, ["最高单户贷款额度 (万元)", "服务覆盖乡镇数"])
  if (item.categoryCode === "YC-SERVICE-INSURANCE") return metricValue(item, ["服务覆盖乡镇数"])
  if (item.categoryCode === "YC-TECH-TRAINING") return metricValue(item, ["年培训人次", "年培训场次"])
  if (item.categoryCode?.startsWith("YC-CXPT")) return parseNumber(item.scale) || metricValue(item, ["acreage"])
  return metricValue(item, Object.keys(item.metrics || {})) || 1
}

function primaryUnit(item = {}) {
  if (item.stageKey === "family-pasture") return "户"
  if (item.categoryCode === "YC-BREEDING-STOCK") return ""
  if (item.categoryCode === "YC-BREEDING-BASE") return "头"
  if (["YC-FORAGE-BASE", "YC-CXPT-FORAGE-BASE", "YC-CXPT-GRASS-SEED-BASE", "YC-CXPT-BREEDING-STOCK-BASE"].includes(item.categoryCode)) return "亩"
  if (item.categoryCode === "YC-DISASTER-FORAGE-STORAGE") return "吨"
  if (item.categoryCode === "YC-PROCESSING-PLANT") return "万元"
  if (item.categoryCode === "YC-SLAUGHTERHOUSE") return "万元"
  if (item.categoryCode === "YC-SERVICE-FINANCE") return "万元"
  if (item.categoryCode === "YC-SERVICE-INSURANCE") return "乡镇"
  if (item.categoryCode === "YC-TECH-TRAINING") return "人次"
  if (item.categoryCode?.startsWith("YC-CXPT")) return "亩"
  return ""
}

function buildPrimaryValueText(item, value, unit) {
  if (item.categoryCode === "YC-BREEDING-STOCK") return String(value || "待完善")
  if (!Number.isFinite(Number(value))) return String(value || "")
  return `${formatNumber(value)}${unit || ""}`
}

function buildDetailExtra(item = {}) {
  const attrs = item.attributes || {}
  const metrics = item.metrics || {}
  return attrs["主要产品"] || attrs["主要草种"] || attrs["储备草种"] || attrs["主要育种方向"] || metrics["主要贷款产品（可多选）"] || item.sourceSheet || ""
}

function buildBreedingLevelRows() {
  const rows = new Map()
  breedingStockItems.forEach((item) => {
    const name = cleanText(item.attributes?.["育种等级"]) || "待完善"
    const current = rows.get(name) || { key: name, name, value: 0, unit: "个" }
    current.value += 1
    rows.set(name, current)
  })
  return [...rows.values()].sort((a, b) => {
    const order = { "省级": 0, "县级": 1, "待完善": 2 }
    return (order[a.name] ?? 9) - (order[b.name] ?? 9)
  })
}

function getStageSubjectRows(stageKey) {
  return categoryList
    .filter((category) => category.industryStage === stageKey)
    .map((category) => {
      const value = countBusinessItems(categoryItems(category.categoryCode))
      return {
        key: category.categoryCode,
        name: category.categoryName.replace(/^cxpt/, ""),
        value,
        unit: "条",
        extra: getStageDef(stageKey).name,
      }
    })
    .filter((item) => item.value > 0)
    .sort(sortByValue)
}

function chartPanel(key, title, type, rows, extra = {}) {
  return {
    key,
    title,
    height: 227,
    renderer: "business",
    type,
    rows,
    ...extra,
  }
}

function getIndustryChainListRows(stageKey) {
  if (!stageKey) return industryStageDefs.flatMap((stage) => getStagePointListRows(stage.key))
  return getStagePointListRows(stageKey)
}

function industryChainListPanel(stageKey) {
  const stage = getStageDef(stageKey)
  const rows = getIndustryChainListRows(stageKey)
  return {
    key: "industry-chain-list",
    title: `${stage.name}点位清单`,
    height: 466,
    renderer: "business",
    type: "projectTable",
    rows,
    searchPlaceholder: `搜索${stage.name}点位 / 乡镇`,
    emptyText: "无匹配点位",
    columns: [
      { key: "name", label: "主体", field: "name", width: "38%", className: "business-project-col-name" },
      { key: "stage", label: "类型", field: "categoryName", width: "24%" },
      { key: "town", label: "乡镇", field: "town", width: "18%" },
      { key: "locate", label: "定位", field: "locateText", width: "20%", align: "center" },
    ],
    searchKeys: ["name", "fullName", "stageName", "categoryName", "town", "address", "valueText", "extra", "sourceSheet", "searchText"],
  }
}

function getTownYakStockRows() {
  const rows = grasslandYakRows
    .map((item) => ({
      key: item.zoneName,
      name: item.zoneName,
      value: Number(item.yakCount || 0),
      unit: "头",
      extra: "牦牛存栏",
    }))
    .filter((item) => item.value > 0)
  return completeTownColumnRows(rows, { unit: "头", extra: "牦牛存栏" })
}

function getTownGrasslandResourceRows() {
  return grasslandYakRows
    .map((item) => ({
      key: item.zoneName,
      name: item.zoneName,
      value: round(Number(item.grasslandArea || 0) / 10000, 2),
      unit: "万亩",
      extra: "草地资源",
    }))
    .filter((item) => item.value > 0)
    .sort(sortByValue)
}

function getTownMetricRows(items = [], metricNames = [], options = {}) {
  const rows = aggregateRows(items, normalizeTown, (item) => metricValue(item, metricNames))
    .map((item) => ({
      ...item,
      unit: options.unit || "",
      extra: options.extra || `${item.count}个点位`,
    }))
  return completeTownColumnRows(rows, options)
}

function getTownCountRows(items = [], extra = "点位") {
  const rows = aggregateRows(items, normalizeTown, () => 1)
    .map((item) => ({
      ...item,
      unit: "个",
      extra,
    }))
  return completeTownColumnRows(rows, { unit: "个", extra })
}

function getForageBaseAreaRows() {
  return forageBaseItems
    .filter(isBusinessItem)
    .map((item) => ({
      key: item.id,
      name: compactName(item.name),
      value: metricValue(item, ["种植面积 (亩)", "acreage"]) || parseNumber(item.scale),
      unit: "亩",
      extra: normalizeTown(item) || item.categoryName,
    }))
    .filter((item) => item.value > 0)
    .sort(sortByValue)
    .slice(0, 8)
}

function getBreedingOutputRows() {
  return breedingBaseItems
    .filter(isBusinessItem)
    .map((item) => ({
      key: item.id,
      name: compactName(item.name),
      value: metricValue(item, ["年出栏量 (头)"]),
      unit: "头",
      extra: `设计${formatNumber(metricValue(item, ["设计存栏量 (头)"]))}头`,
    }))
    .filter((item) => item.value > 0)
    .sort(sortByValue)
    .slice(0, 7)
}

function getStoragePointRows() {
  return forageStorageItems
    .filter(isBusinessItem)
    .map((item) => ({
      key: item.id,
      name: compactName(item.name),
      value: metricValue(item, ["总库容 (吨)"]),
      unit: "吨",
      extra: metricValue(item, ["发放次数"]) || item.attributes?.["储备草种"] || "储备库",
    }))
    .filter((item) => item.value > 0)
    .sort(sortByValue)
    .slice(0, 8)
}

function getSlaughterHeadRows() {
  return slaughterItems
    .filter(isBusinessItem)
    .map((item) => ({
      key: item.id,
      name: compactName(item.name),
      value: metricValue(item, ["年屠宰总量 (头)"]),
      unit: "头",
      extra: `${formatNumber(metricValue(item, ["冷冻库容量 (吨)"]))}吨冷链`,
    }))
    .filter((item) => item.value > 0)
    .sort(sortByValue)
    .slice(0, 7)
}

function getFinanceCreditRows() {
  return financeItems
    .filter(isBusinessItem)
    .map((item) => ({
      key: item.id,
      name: compactName(item.attributes?.简称 || item.name),
      value: metricValue(item, ["最高单户贷款额度 (万元)"]),
      unit: "万元",
      extra: `覆盖${formatNumber(metricValue(item, ["服务覆盖乡镇数"]))}乡镇`,
    }))
    .filter((item) => item.value > 0)
    .sort(sortByValue)
    .slice(0, 7)
}

function getServiceCoverageRows() {
  return [
    ...financeItems.filter(isBusinessItem).map((item) => ({
      key: item.id,
      name: compactName(item.attributes?.简称 || item.name),
      value: metricValue(item, ["服务覆盖乡镇数"]),
      unit: "乡镇",
      extra: "金融",
    })),
    ...insuranceItems.filter(isBusinessItem).map((item) => ({
      key: item.id,
      name: compactName(item.attributes?.简称 || item.name),
      value: metricValue(item, ["服务覆盖乡镇数"]),
      unit: "乡镇",
      extra: "保险",
    })),
  ].filter((item) => item.value > 0).sort(sortByValue).slice(0, 7)
}

function getTrainingRows() {
  const rows = trainingItems
    .filter(isBusinessItem)
    .map((item) => ({
      key: item.id,
      name: compactName(item.name),
      value: metricValue(item, ["年培训人次"]),
      unit: "人次",
      extra: `${formatNumber(metricValue(item, ["年培训场次"]))}场`,
    }))
    .filter((item) => item.value > 0)
    .sort(sortByValue)
    .slice(0, 7)
  return rows.length ? rows : [
    { key: "sessions", name: "年培训场次", value: trainingSessionCount, unit: "场" },
    { key: "persons", name: "年培训人次", value: trainingPersonCount, unit: "人次" },
  ]
}

function buildGrassTypeRows(rows) {
  const aliases = [
    { key: "oat", name: "燕麦草", pattern: /燕麦/ },
    { key: "elymus", name: "披碱草", pattern: /披碱草/ },
    { key: "roegneria", name: "老芒麦", pattern: /老芒麦/ },
    { key: "other", name: "其他草种", pattern: /./ },
  ]
  const map = new Map(aliases.map((item) => [item.key, { key: item.key, name: item.name, value: 0, unit: "处" }]))
  rows.filter(isBusinessItem).forEach((item) => {
    const text = [item.attributes?.["主要草种"], item.attributes?.["储备草种"]].filter(Boolean).join("、")
    const matched = aliases.filter((alias) => alias.key !== "other" && alias.pattern.test(text))
    const targets = matched.length ? matched : [aliases[aliases.length - 1]]
    targets.forEach((alias) => {
      map.get(alias.key).value += 1
    })
  })
  return [...map.values()].filter((item) => item.value > 0).sort(sortByValue)
}

function buildProcessingChainRows() {
  return [
    { key: "raw-capacity", name: "原料加工", value: processingRawCapacity, unit: "吨" },
    { key: "slaughter-heads", name: "屠宰总量", value: slaughterAnnualHeads, unit: "头" },
    { key: "farmer-driven", name: "带动农户", value: processingDrivenHouseholds, unit: "户" },
    { key: "cold-storage", name: "冷链能力", value: slaughterColdCapacity, unit: "吨" },
  ].filter((item) => item.value > 0)
}

function buildServiceTypeRows() {
  return [
    { key: "finance", name: "金融", value: financeItems.filter(isBusinessItem).length, unit: "家" },
    { key: "insurance", name: "保险", value: insuranceItems.filter(isBusinessItem).length, unit: "家" },
    { key: "training", name: "培训", value: trainingItems.filter(isBusinessItem).length, unit: "家" },
    { key: "disease", name: "防疫", value: diseaseControlItems.filter(isBusinessItem).length, unit: "个" },
  ].filter((item) => item.value > 0)
}

function aggregateRows(rows, nameGetter, valueGetter) {
  const map = new Map()
  rows.filter(isBusinessItem).forEach((item) => {
    const name = cleanText(typeof nameGetter === "function" ? nameGetter(item) : item[nameGetter]) || "未填写"
    const current = map.get(name) || { key: name, name, value: 0, count: 0, extra: "" }
    current.value += Number(valueGetter(item) || 0)
    current.count += 1
    map.set(name, current)
  })
  return [...map.values()].sort(sortByValue)
}

function completeTownColumnRows(rows = [], options = {}) {
  const byTown = new Map()
  rows.forEach((row) => {
    const name = cleanText(row?.name)
    const matchedTown = townNames.find((town) => town === name) || townNames.find((town) => {
      const stem = town.replace(/[镇乡]$/, "")
      return stem.length >= 2 && name.includes(stem)
    })
    if (!matchedTown) return
    byTown.set(matchedTown, row)
  })
  return townNames.map((town, index) => {
    const row = byTown.get(town)
    const rawValue = Number(row?.value || 0)
    const hasValue = Number.isFinite(rawValue) && rawValue > 0
    return {
      key: row?.key || town,
      name: town,
      value: hasValue ? rawValue : 0.001,
      displayValue: hasValue ? row.displayValue : "0",
      scaleValue: row?.scaleValue,
      unit: row?.unit || options.unit || "",
      extra: row?.extra || options.extra || "",
      color: row?.color,
      zero: !hasValue,
      sourceIndex: index,
    }
  })
}

function metricValue(item = {}, names = []) {
  const metrics = item.metrics || {}
  const nameList = Array.isArray(names) ? names : [names]
  for (const name of nameList) {
    if (Object.prototype.hasOwnProperty.call(metrics, name)) {
      const value = parseNumber(metrics[name])
      if (value || value === 0) return value
    }
  }
  return 0
}

function parseNumber(value) {
  if (typeof value === "number") return Number.isFinite(value) ? value : 0
  if (isBlank(value)) return 0
  const text = String(value).replace(/,/g, "").trim()
  if (!text || text === "无" || text === "待完善") return 0
  const match = text.match(/-?\d+(?:\.\d+)?/)
  if (!match) return 0
  let number = Number(match[0])
  if (text.includes("万亩") && !text.includes("万元")) number *= 10000
  return Number.isFinite(number) ? number : 0
}

function normalizeTown(item = {}) {
  const direct = cleanText(item.town || item.areaName)
  if (townNames.includes(direct)) return direct
  const text = [item.town, item.areaName, item.areaFullName, item.address, item.village, item.name].filter(Boolean).join(" ")
  const exact = townNames.find((name) => text.includes(name))
  if (exact) return exact
  return townNames.find((name) => {
    const stem = name.replace(/[镇乡]$/, "")
    return stem.length >= 2 && text.includes(stem)
  }) || direct
}

function getItemCoordinate(item = {}) {
  const longitude = parseCoordinateNumber(item.longitude)
  const latitude = parseCoordinateNumber(item.latitude)
  if (isCoordinateInHongyuanBounds(longitude, latitude)) return { longitude, latitude }
  const location = Object.values(item.locations || {}).find((value) => (
    isCoordinateInHongyuanBounds(parseCoordinateNumber(value?.longitude), parseCoordinateNumber(value?.latitude))
  ))
  if (!location) return null
  return {
    longitude: parseCoordinateNumber(location.longitude),
    latitude: parseCoordinateNumber(location.latitude),
  }
}

function isCoordinateInHongyuanBounds(longitude, latitude) {
  const lng = Number(longitude)
  const lat = Number(latitude)
  return Number.isFinite(lng)
    && Number.isFinite(lat)
    && lng >= HONGYUAN_BOUNDS.west
    && lng <= HONGYUAN_BOUNDS.east
    && lat >= HONGYUAN_BOUNDS.south
    && lat <= HONGYUAN_BOUNDS.north
}

function parseCoordinateNumber(value) {
  if (value === undefined || value === null || value === "") return NaN
  const number = Number(value)
  return Number.isFinite(number) ? number : NaN
}

function isMilkProcessing(item = {}) {
  const text = [item.name, item.attributes?.["主要产品"]].filter(Boolean).join("")
  return /奶|乳|酸奶|奶粉/.test(text)
}

function isMeatProcessing(item = {}) {
  const text = [item.name, item.attributes?.["主要产品"]].filter(Boolean).join("")
  return /肉|屠宰|牛肉/.test(text)
}

function findClassifiedItem(point = {}) {
  const id = String(point.id || "")
  if (id && itemById.has(id)) return itemById.get(id)
  return allClassifiedItems.find((item) => item.name === point.name && item.categoryCode === point.categoryCode)
}

function scoreBy(value, target) {
  return Math.max(12, Math.min(100, Math.round((Number(value || 0) / target) * 100)))
}

function sumBy(rows, getter) {
  return rows.filter(isBusinessItem).reduce((sum, item) => sum + Number(getter(item) || 0), 0)
}

function maxByValue(rows, getter) {
  return rows.filter(isBusinessItem).reduce((max, item) => Math.max(max, Number(getter(item) || 0)), 0)
}

function uniqueCount(rows, getter) {
  return new Set(rows.filter(isBusinessItem).map(getter).filter(Boolean)).size
}

function sortByValue(a, b) {
  return b.value - a.value || b.count - a.count || String(a.name).localeCompare(String(b.name), "zh-CN")
}

function compactName(value = "") {
  return String(value)
    .replace(/^四川红原/, "")
    .replace(/^红原县/, "")
    .replace(/有限责任公司$/, "")
    .replace(/农民专业合作社$/, "合作社")
    .replace(/股份有限公司红原县支行$/, "红原支行")
    .trim()
}

function cleanText(value) {
  return String(value ?? "").replace(/\s+/g, " ").trim()
}

function isBlank(value) {
  return value === undefined || value === null || String(value).trim() === "" || String(value).trim().toLowerCase() === "nan"
}

function formatValue(value) {
  if (typeof value === "number") return formatNumber(value)
  const numeric = parseNumber(value)
  if (numeric && String(value).match(/^\s*[约≈]?\d/)) return String(value)
  return String(value ?? "")
}

function formatValueWithUnit(value, unit = "") {
  const formatted = formatValue(value)
  if (!unit) return formatted
  if (typeof value === "string" && formatted.includes(unit.replace(/^个/, ""))) return formatted
  return `${formatted}${unit}`
}

function formatNumber(value) {
  const number = Number(value || 0)
  if (!Number.isFinite(number)) return "0"
  return number.toLocaleString("zh-CN", { maximumFractionDigits: Number.isInteger(number) ? 0 : 1 })
}

function round(value, digits = 0) {
  const factor = 10 ** digits
  return Math.round(Number(value || 0) * factor) / factor
}
