import hongyuanTownshipsRaw from "/public/datas/geojsons/hongyuan-townships.geojson?raw"
import { HONGYUAN_TOWNSHIP_GEOJSON_PATH } from "@/config/mapResources"

export const hongyuanTownshipGeoJsonPath = HONGYUAN_TOWNSHIP_GEOJSON_PATH

const townshipEnNames = {
  邛溪镇: "qiongxi",
  刷经寺镇: "shuajingsi",
  安曲镇: "anqu",
  龙日镇: "longri",
  江茸乡: "jiangrong",
  查尔玛乡: "chaerma",
  瓦切镇: "waqie",
  阿木乡: "amu",
  麦洼乡: "maiwa",
  色地镇: "sedi",
}

const townshipValues = {
  色地镇: 1199,
  瓦切镇: 991,
  刷经寺镇: 986,
  邛溪镇: 896,
  阿木乡: 892,
  安曲镇: 885,
  查尔玛乡: 729,
  龙日镇: 645,
  麦洼乡: 559,
  江茸乡: 514,
}

const townshipLabelCenterOverrides = {}

function parseGeoJson(raw) {
  try {
    return JSON.parse(raw)
  } catch (error) {
    return { type: "FeatureCollection", features: [] }
  }
}

function readPoint(feature = {}) {
  const properties = feature.properties || {}
  const point = properties.cp || properties.center || properties.centroid || properties.sourceCenter
  if (Array.isArray(point) && Number.isFinite(Number(point[0])) && Number.isFinite(Number(point[1]))) {
    return [Number(point[0]), Number(point[1])]
  }
  return [0, 0]
}

function getFeaturePolygons(geometry = {}) {
  if (!geometry?.coordinates) return []
  if (geometry.type === "Polygon") return [geometry.coordinates]
  if (geometry.type === "MultiPolygon") return geometry.coordinates
  return []
}

function getRingArea(ring = []) {
  return ring.reduce((sum, point, index) => {
    const previous = ring[index === 0 ? ring.length - 1 : index - 1]
    return sum + (Number(previous?.[0]) * Number(point?.[1]) - Number(point?.[0]) * Number(previous?.[1]))
  }, 0) / 2
}

function getRingCentroid(ring = []) {
  let areaFactor = 0
  let lngSum = 0
  let latSum = 0
  ring.forEach((point, index) => {
    const previous = ring[index === 0 ? ring.length - 1 : index - 1]
    const factor = Number(previous?.[0]) * Number(point?.[1]) - Number(point?.[0]) * Number(previous?.[1])
    areaFactor += factor
    lngSum += (Number(previous?.[0]) + Number(point?.[0])) * factor
    latSum += (Number(previous?.[1]) + Number(point?.[1])) * factor
  })
  if (Math.abs(areaFactor) < 1e-10) return null
  return [lngSum / (3 * areaFactor), latSum / (3 * areaFactor)]
}

function getRingBounds(ring = []) {
  const finitePoints = ring
    .map((point) => [Number(point?.[0]), Number(point?.[1])])
    .filter(([lng, lat]) => Number.isFinite(lng) && Number.isFinite(lat))
  if (!finitePoints.length) return null
  return finitePoints.reduce((bounds, [lng, lat]) => ({
    west: Math.min(bounds.west, lng),
    east: Math.max(bounds.east, lng),
    south: Math.min(bounds.south, lat),
    north: Math.max(bounds.north, lat),
  }), { west: Infinity, east: -Infinity, south: Infinity, north: -Infinity })
}

function isPointInRing(point = [], ring = []) {
  const lng = Number(point[0])
  const lat = Number(point[1])
  if (!Number.isFinite(lng) || !Number.isFinite(lat)) return false
  let inside = false
  for (let index = 0, previousIndex = ring.length - 1; index < ring.length; previousIndex = index, index += 1) {
    const current = ring[index] || []
    const previous = ring[previousIndex] || []
    const currentLng = Number(current[0])
    const currentLat = Number(current[1])
    const previousLng = Number(previous[0])
    const previousLat = Number(previous[1])
    if (!Number.isFinite(currentLng) || !Number.isFinite(currentLat) || !Number.isFinite(previousLng) || !Number.isFinite(previousLat)) continue
    const intersects = (currentLat > lat) !== (previousLat > lat)
      && lng < ((previousLng - currentLng) * (lat - currentLat)) / (previousLat - currentLat || 1e-12) + currentLng
    if (intersects) inside = !inside
  }
  return inside
}

function isPointInPolygon(point = [], polygon = []) {
  if (!polygon.length || !isPointInRing(point, polygon[0])) return false
  return !polygon.slice(1).some((ring) => isPointInRing(point, ring))
}

function isPointInGeometry(point = [], geometry = {}) {
  return getFeaturePolygons(geometry).some((polygon) => isPointInPolygon(point, polygon))
}

function getLargestPolygon(feature = {}) {
  return getFeaturePolygons(feature.geometry)
    .map((polygon) => ({
      polygon,
      area: Math.abs(getRingArea(polygon?.[0] || [])),
    }))
    .filter((item) => item.area > 0)
    .sort((a, b) => b.area - a.area)[0]?.polygon || null
}

function roundPoint(point = []) {
  return point.map((value) => Number(Number(value).toFixed(6)))
}

function getFeatureVisualCenter(feature = {}) {
  const fallback = readPoint(feature)
  if (isPointInGeometry(fallback, feature.geometry)) return roundPoint(fallback)

  const largestPolygon = getLargestPolygon(feature)
  const outerRing = largestPolygon?.[0] || []
  const centroid = getRingCentroid(outerRing)
  if (centroid && isPointInPolygon(centroid, largestPolygon)) return roundPoint(centroid)

  const bounds = getRingBounds(outerRing)
  const boundsCenter = bounds ? [(bounds.west + bounds.east) / 2, (bounds.south + bounds.north) / 2] : null
  if (boundsCenter && isPointInPolygon(boundsCenter, largestPolygon)) return roundPoint(boundsCenter)
  return roundPoint(centroid || boundsCenter || fallback)
}

export const hongyuanTownshipsGeoJsonRaw = hongyuanTownshipsRaw
export const hongyuanTownshipsGeoJson = parseGeoJson(hongyuanTownshipsRaw)
export const hongyuanTownshipFeatures = hongyuanTownshipsGeoJson.features || []

const townshipsByCode = hongyuanTownshipFeatures.reduce((result, feature) => {
  const properties = feature.properties || {}
  const name = normalizeHongyuanTownName(properties.name)
  ;[properties.code, properties.fullCode].forEach((code) => {
    const normalizedCode = String(code || "").replace(/\D/g, "")
    if (normalizedCode && name) result[normalizedCode] = name
  })
  return result
}, {})

export const hongyuanTownshipCodeByName = hongyuanTownshipFeatures.reduce((result, feature) => {
  const properties = feature.properties || {}
  const name = normalizeHongyuanTownName(properties.name)
  const code = String(properties.code || "").replace(/\D/g, "")
  if (name && code) result[name] = code
  return result
}, {})

export const hongyuanTownshipLabelPoints = hongyuanTownshipFeatures.map((feature) => {
  const properties = feature.properties || {}
  const name = normalizeHongyuanTownName(properties.name)
  const center = townshipLabelCenterOverrides[name] || getFeatureVisualCenter(feature)
  return {
    name,
    code: properties.code,
    fullCode: properties.fullCode,
    center,
    centroid: center,
    acreageMu: Number(properties.acreageMu) || 0,
  }
})

export const hongyuanTownshipRankingPoints = hongyuanTownshipLabelPoints
  .map((item) => ({
    ...item,
    enName: townshipEnNames[item.name] || "",
    value: townshipValues[item.name] || 0,
  }))
  .sort((a, b) => b.value - a.value)

export const hongyuanTownshipDisplayOrder = hongyuanTownshipLabelPoints.map((item) => item.name)

export function normalizeHongyuanTownName(value) {
  const text = String(value || "").trim()
  if (!text || text === "--") return ""
  return text
}

export function getHongyuanTownshipNameByCode(value) {
  const normalizedCode = String(value || "").replace(/\D/g, "")
  if (!normalizedCode) return ""
  return townshipsByCode[normalizedCode] || townshipsByCode[normalizedCode.slice(0, 12)] || townshipsByCode[normalizedCode.slice(0, 9)] || ""
}

export function getHongyuanTownshipCodeByName(value) {
  const name = normalizeHongyuanTownName(value)
  if (!name) return ""
  return hongyuanTownshipCodeByName[name] || ""
}

export function isHongyuanTownshipName(value) {
  const name = normalizeHongyuanTownName(value)
  return Boolean(name && hongyuanTownshipLabelPoints.some((item) => item.name === name))
}
