/**
 * Ray-casting point-in-polygon for GeoJSON Polygon geometry.
 * lng = x, lat = y (GeoJSON coordinate order).
 */
function rayInRing(lng: number, lat: number, ring: number[][]): boolean {
  let inside = false
  for (let i = 0, j = ring.length - 1; i < ring.length; j = i++) {
    const xi = ring[i][0], yi = ring[i][1]
    const xj = ring[j][0], yj = ring[j][1]
    const intersect =
      yi > lat !== yj > lat &&
      lng < ((xj - xi) * (lat - yi)) / (yj - yi) + xi
    if (intersect) inside = !inside
  }
  return inside
}

export function pointInPolygon(lat: number, lng: number, geometry: GeoJSON.Geometry): boolean {
  if (geometry.type === 'Polygon') {
    const [outer, ...holes] = geometry.coordinates as number[][][]
    if (!rayInRing(lng, lat, outer)) return false
    for (const hole of holes) {
      if (rayInRing(lng, lat, hole)) return false
    }
    return true
  }
  if (geometry.type === 'MultiPolygon') {
    return (geometry.coordinates as number[][][][]).some((poly) => {
      const [outer, ...holes] = poly
      if (!rayInRing(lng, lat, outer)) return false
      for (const hole of holes) {
        if (rayInRing(lng, lat, hole)) return false
      }
      return true
    })
  }
  return false
}
