// Backfill latitude/longitude for existing properties that predate geocoding.
//
//   node scripts/backfill-geocode.mjs          # dev   (uses DATABASE_URL)
//   node scripts/backfill-geocode.mjs --prod   # prod  (uses PROD_DATABASE_URL)
//
// Geocodes every property missing coordinates via OpenStreetMap Nominatim,
// throttled to 1 request/second per Nominatim's usage policy. Safe to re-run —
// it only touches rows where latitude or longitude is null.
import { readFileSync } from "node:fs"
import { config } from "dotenv"
import pg from "pg"

config({ path: ".env.local", quiet: true })

const useProd = process.argv.includes("--prod")
const url = useProd ? process.env.PROD_DATABASE_URL : process.env.DATABASE_URL
if (!url) {
  console.error(`[backfill-geocode] ${useProd ? "PROD_DATABASE_URL" : "DATABASE_URL"} is not set.`)
  process.exit(1)
}

function resolveSsl() {
  if (useProd) {
    try {
      return { rejectUnauthorized: true, ca: readFileSync("ca-certificate.crt", "utf8") }
    } catch {
      return { rejectUnauthorized: false }
    }
  }
  return process.env.DATABASE_SSL === "disable" ? false : { rejectUnauthorized: false }
}

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

const sleep = (ms) => new Promise((r) => setTimeout(r, ms))

async function geocode(a) {
  if (!a.address_line1 && !a.city && !a.postal_code) return null
  const street = [a.address_line1, a.address_line2].filter(Boolean).join(" ").trim()
  const params = new URLSearchParams({ format: "jsonv2", limit: "1" })
  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")
  try {
    const res = await fetch(`https://nominatim.openstreetmap.org/search?${params.toString()}`, {
      headers: { "User-Agent": USER_AGENT, Accept: "application/json" },
    })
    if (!res.ok) return null
    const json = await res.json()
    const first = Array.isArray(json) ? json[0] : null
    if (!first) return null
    const lat = Number(first.lat)
    const lon = Number(first.lon)
    return Number.isFinite(lat) && Number.isFinite(lon) ? { lat, lon } : null
  } catch {
    return null
  }
}

const pool = new pg.Pool({ connectionString: url, ssl: resolveSsl() })

const { rows } = await pool.query(
  `select id, name, address_line1, address_line2, city, state, postal_code, country
     from properties
    where latitude is null or longitude is null`
)

console.log(`[backfill-geocode] ${rows.length} propert${rows.length === 1 ? "y" : "ies"} to geocode (${useProd ? "PROD" : "dev"})`)

let ok = 0
for (const r of rows) {
  const g = await geocode(r)
  const label = r.name || r.address_line1 || r.city || r.id
  if (g) {
    await pool.query(`update properties set latitude = $1, longitude = $2 where id = $3`, [g.lat, g.lon, r.id])
    ok++
    console.log(`  ✓ ${label} → ${g.lat.toFixed(4)}, ${g.lon.toFixed(4)}`)
  } else {
    console.log(`  · ${label}: no match`)
  }
  await sleep(1100) // Nominatim: max 1 request/second
}

console.log(`[backfill-geocode] done — ${ok}/${rows.length} geocoded`)
await pool.end()
