import fs from "node:fs"
import path from "node:path"
import process from "node:process"

const projectRoot = path.resolve(path.dirname(new URL(import.meta.url).pathname), "..")
const sourcePath = process.argv[2]
const targetPath = path.join(projectRoot, "public/datas/yak-industry-chain/artificial_grassland_plots.geojson")
const summaryPath = path.join(projectRoot, "src/views/yakIndustryChain/artificialGrasslandSummary.json")
const townshipPath = path.join(projectRoot, "public/datas/geojsons/hongyuan-townships.geojson")

if (!sourcePath) {
  console.error("Usage: node scripts/prepare-artificial-grassland-data.mjs <source.geojson>")
  process.exit(1)
}

const source = readJson(sourcePath)
const townships = readJson(townshipPath)
const sourceLabel = "21.95万亩种草矢量数据"
const displayTownOrder = (townships.features || []).map((feature) => feature.properties?.name).filter(Boolean)

const seenTopology = new Set()
const features = []

for (const sourceFeature of source.features || []) {
  const candidate = toPlotCandidate(sourceFeature)
  if (!candidate) continue
  const topologyKey = canonicalRing(candidate.ring)
  if (!topologyKey || seenTopology.has(topologyKey)) continue
  seenTopology.add(topologyKey)

  const name = cleanName(sourceFeature.properties?.name)
  const category = getPlotCategory(name)
  const center = getRingCenter(candidate.ring)
  const town = getTownByPoint(center, townships.features || [])
  const id = `AG-${String(features.length + 1).padStart(3, "0")}`

  features.push({
    type: "Feature",
    properties: {
      id,
      plot_code: id,
      name,
      plot_name: name,
      stageKey: "artificial-grassland",
      stage_name: "人工种草",
      town,
      town_name: town,
      plot_category: category.name,
      plot_category_key: category.key,
      data_status: "待核定",
      source_type: candidate.sourceType,
      data_source: sourceLabel,
      geometry_note: candidate.note,
    },
    geometry: {
      type: "Polygon",
      coordinates: [closeRing(candidate.ring)],
    },
  })
}

const summary = buildSummary(features, displayTownOrder)
writeJson(targetPath, {
  type: "FeatureCollection",
  name: "artificial_grassland_plots",
  generatedAt: new Date().toISOString(),
  description: "人工种草空间资料。图斑为待核定资料，不作为正式面积统计口径。",
  features,
})
writeJson(summaryPath, summary)

console.log(`Generated ${features.length} artificial grassland plots.`)
console.log(`GeoJSON: ${targetPath}`)
console.log(`Summary: ${summaryPath}`)

function readJson(filePath) {
  return JSON.parse(fs.readFileSync(filePath, "utf8"))
}

function writeJson(filePath, value) {
  fs.mkdirSync(path.dirname(filePath), { recursive: true })
  fs.writeFileSync(filePath, `${JSON.stringify(value, null, 2)}\n`, "utf8")
}

function toPlotCandidate(feature = {}) {
  const geometry = feature.geometry || {}
  if (geometry.type === "Polygon") {
    const ring = cleanRing(geometry.coordinates?.[0])
    if (ring.length < 3) return null
    return {
      ring,
      sourceType: "面图斑",
      note: "原始面图斑已闭合后展示",
    }
  }
  if (geometry.type !== "LineString") return null
  const originalRing = Array.isArray(geometry.coordinates) ? geometry.coordinates : []
  if (originalRing.length < 4 || !samePoint(originalRing[0], originalRing.at(-1))) return null
  const ring = cleanRing(originalRing)
  if (ring.length < 3) return null
  return {
    ring,
    sourceType: "边界图斑",
    note: "原始闭合边界转换为图斑展示",
  }
}

function cleanRing(coordinates = []) {
  const ring = []
  coordinates.forEach((coordinate) => {
    if (!Array.isArray(coordinate) || coordinate.length < 2) return
    const next = [roundCoordinate(coordinate[0]), roundCoordinate(coordinate[1])]
    if (!ring.length || !samePoint(ring.at(-1), next)) ring.push(next)
  })
  if (ring.length > 1 && samePoint(ring[0], ring.at(-1))) ring.pop()
  return ring
}

function closeRing(ring = []) {
  return [...ring, [...ring[0]]]
}

function canonicalRing(ring = []) {
  if (ring.length < 3) return ""
  const variants = [ring, [...ring].reverse()]
  let result = ""
  variants.forEach((variant) => {
    variant.forEach((_, index) => {
      const rotated = [...variant.slice(index), ...variant.slice(0, index)]
      const signature = rotated.map((point) => `${point[0]},${point[1]}`).join("|")
      if (!result || signature < result) result = signature
    })
  })
  return result
}

function getRingCenter(ring = []) {
  if (!ring.length) return [0, 0]
  const total = ring.reduce(
    (result, point) => [result[0] + Number(point[0] || 0), result[1] + Number(point[1] || 0)],
    [0, 0],
  )
  return [total[0] / ring.length, total[1] / ring.length]
}

function getTownByPoint(point, townshipFeatures) {
  for (const feature of townshipFeatures) {
    const geometry = feature.geometry || {}
    const polygons = geometry.type === "MultiPolygon" ? geometry.coordinates : geometry.type === "Polygon" ? [geometry.coordinates] : []
    if (polygons.some((polygon) => isPointInRing(point, polygon?.[0] || []))) {
      return feature.properties?.name || "未归属"
    }
  }
  return "未归属"
}

function isPointInRing(point, ring = []) {
  if (!Array.isArray(point) || ring.length < 3) return false
  let inside = false
  for (let index = 0, previous = ring.length - 1; index < ring.length; previous = index++) {
    const [currentX, currentY] = ring[index]
    const [previousX, previousY] = ring[previous]
    const crosses = (currentY > point[1]) !== (previousY > point[1])
      && point[0] < ((previousX - currentX) * (point[1] - currentY)) / (previousY - currentY) + currentX
    if (crosses) inside = !inside
  }
  return inside
}

function getPlotCategory(name) {
  if (name.startsWith("撒播")) return { key: "broadcast", name: "撒播图斑" }
  if (name.startsWith("总范围")) return { key: "high-yield", name: "高产稳产范围" }
  if (name.startsWith("调拨")) return { key: "allocation", name: "调拨地块" }
  if (name.includes("地块")) return { key: "project-plot", name: "项目地块" }
  return { key: "unclassified", name: "待分类图斑" }
}

function buildSummary(plotFeatures, townOrder) {
  const rows = plotFeatures.map((feature) => feature.properties || {})
  const townRows = townOrder.map((name) => {
    const value = rows.filter((item) => item.town === name).length
    return {
      key: name,
      name,
      value,
      unit: "个",
      extra: value ? "待核定图斑" : "暂无图斑",
      zero: value === 0,
    }
  })
  const categoryRows = groupRows(rows, "plot_category").map((item) => ({
    ...item,
    unit: "个",
  }))
  const sourceRows = groupRows(rows, "source_type").map((item) => ({
    ...item,
    unit: "个",
  }))
  const plotRows = rows
    .map((item) => ({
      key: item.id,
      id: item.id,
      name: item.name,
      fullName: item.name,
      town: item.town,
      category: item.plot_category,
      status: item.data_status,
      stageKey: "artificial-grassland",
      stageName: "人工种草",
      canLocate: true,
      locateText: "定位",
      searchText: [item.name, item.town, item.plot_category, item.data_status].filter(Boolean).join(" "),
    }))
    .sort((left, right) => Number(right.category === "项目地块") - Number(left.category === "项目地块") || left.name.localeCompare(right.name, "zh-CN"))

  return {
    generatedAt: new Date().toISOString(),
    sourceLabel,
    statusLabel: "待核定",
    totalPlots: rows.length,
    coveredTowns: townRows.filter((item) => item.value > 0).length,
    projectPlots: rows.filter((item) => item.plot_category === "项目地块").length,
    pendingPlots: rows.length,
    townRows,
    categoryRows,
    sourceRows,
    plotRows,
  }
}

function groupRows(rows, key) {
  const grouped = new Map()
  rows.forEach((item) => {
    const name = String(item[key] || "未分类")
    grouped.set(name, (grouped.get(name) || 0) + 1)
  })
  return [...grouped.entries()]
    .map(([name, value]) => ({ key: name, name, value }))
    .sort((left, right) => right.value - left.value || left.name.localeCompare(right.name, "zh-CN"))
}

function cleanName(value) {
  const text = String(value || "").trim()
  return text || "未命名图斑"
}

function roundCoordinate(value) {
  return Number(Number(value).toFixed(8))
}

function samePoint(left = [], right = []) {
  return Math.abs(Number(left[0]) - Number(right[0])) < 1e-8 && Math.abs(Number(left[1]) - Number(right[1])) < 1e-8
}
