// Free, keyless forward geocoding via OpenStreetMap Nominatim.
//
// Usage policy — https://operations.osmfoundation.org/policies/nominatim/ :
//   • max 1 request/second, no heavy bulk use
//   • an identifying User-Agent is REQUIRED (set GEOCODER_USER_AGENT to a
//     contact URL/email in production)
//   • results must be cached — we persist latitude/longitude on the property,
//     so each address is geocoded once on save, never on map render.
//
// Best-effort by design: every failure path returns null and the caller simply
// proceeds without coordinates (the property is omitted from the map).

const NOMINATIM_URL = "https://nominatim.openstreetmap.org/search"

const USER_AGENT =
  process.env.GEOCODER_USER_AGENT ||
  `PropertyManagementNetwork/1.0 (${process.env.NEXT_PUBLIC_APP_URL || "https://propertymanagement.network"})`

export type Coordinates = { latitude: number; longitude: number }

export type AddressParts = {
  address_line1?: string | null
  address_line2?: string | null
  city?: string | null
  state?: string | null
  postal_code?: string | null
  country?: string | null
}

/** True when there's enough of an address to bother geocoding. */
export function hasGeocodableAddress(a: AddressParts): boolean {
  return Boolean(a.address_line1 || a.city || a.postal_code)
}

export async function geocodeAddress(a: AddressParts): Promise<Coordinates | null> {
  if (!hasGeocodableAddress(a)) return null

  const street = [a.address_line1, a.address_line2].filter(Boolean).join(" ").trim()
  const params = new URLSearchParams({ format: "jsonv2", limit: "1", addressdetails: "0" })
  if (street) params.set("street", street)
  if (a.city) params.set("city", a.city)
  if (a.state) params.set("state", a.state)
  if (a.postal_code) params.set("postalcode", a.postal_code)
  params.set("country", a.country || "US")

  const controller = new AbortController()
  const timer = setTimeout(() => controller.abort(), 8000)
  try {
    const res = await fetch(`${NOMINATIM_URL}?${params.toString()}`, {
      headers: { "User-Agent": USER_AGENT, Accept: "application/json" },
      signal: controller.signal,
    })
    if (!res.ok) return null
    const json = (await res.json()) as Array<{ lat: string; lon: string }>
    const first = Array.isArray(json) ? json[0] : undefined
    if (!first) return null
    const latitude = Number(first.lat)
    const longitude = Number(first.lon)
    if (!Number.isFinite(latitude) || !Number.isFinite(longitude)) return null
    return { latitude, longitude }
  } catch {
    return null
  } finally {
    clearTimeout(timer)
  }
}
