"""Refresh public offline GeoNames points; no employee locations are uploaded.
Run manually with Python 3: python scripts/build-place-data.py
Source data license: CC BY 4.0, https://www.geonames.org/
"""
from pathlib import Path
import datetime, hashlib, io, json, urllib.request, zipfile
ROOT = Path(__file__).resolve().parent.parent
BASE = "https://download.geonames.org/export/dump/"
SOURCES = ["cities15000.zip", "AE.zip", "admin1CodesASCII.txt", "countryInfo.txt"]

def download(name):
    request = urllib.request.Request(BASE + name, headers={"User-Agent": "ZentrikHRMS-offline-place-data/1.0"})
    with urllib.request.urlopen(request, timeout=90) as response:
        data = response.read(20_000_001)
    if len(data) > 20_000_000:
        raise RuntimeError("Unexpected source size: " + name)
    return data

def build():
    sources = {name: download(name) for name in SOURCES}
    countries = {}
    for line in sources["countryInfo.txt"].decode("utf-8").splitlines():
        if line and not line.startswith("#"):
            fields = line.split("\t")
            if len(fields) >= 5:
                countries[fields[0]] = fields[4]
    regions = {}
    for line in sources["admin1CodesASCII.txt"].decode("utf-8").splitlines():
        fields = line.split("\t")
        if len(fields) >= 3:
            regions[fields[0]] = fields[2] or fields[1]
    points = {}
    for archive, entry in [("cities15000.zip", "cities15000.txt"), ("AE.zip", "AE.txt")]:
        with zipfile.ZipFile(io.BytesIO(sources[archive])) as source:
            if source.getinfo(entry).file_size > 40_000_000:
                raise RuntimeError("Unexpected expanded size")
            lines = source.read(entry).decode("utf-8").splitlines()
        for line in lines:
            fields = line.split("\t")
            if len(fields) != 19:
                continue
            if fields[6] != "P" or fields[7] in {"PPLH", "PPLQ", "PPLW"}:
                continue
            lat, lng = float(fields[4]), float(fields[5])
            if not (-90 <= lat <= 90 and -180 <= lng <= 180):
                raise RuntimeError("Invalid public data coordinate")
            name = fields[2] or fields[1]
            region = regions.get(fields[8] + "." + fields[10], "")
            country = countries.get(fields[8], fields[8])
            points[int(fields[0])] = [lat, lng, name, region, country, int(fields[0])]
    tiles = {}
    import math
    for point in sorted(points.values(), key=lambda p:p[5]):
        key = str(math.floor(point[0])) + ":" + str(math.floor(point[1]))
        tiles.setdefault(key, []).append(point)
    result = {"version":1,"updated_at":datetime.datetime.now(datetime.timezone.utc).date().isoformat(),"attribution":"GeoNames, CC BY 4.0","source":"https://www.geonames.org/","coverage":"Worldwide cities over 15,000 people and administrative seats; additional UAE populated places and neighbourhoods. Nearest points, not street address boundaries.","source_sha256":{name:hashlib.sha256(data).hexdigest() for name,data in sources.items()},"point_count":len(points),"tiles":tiles}
    target = ROOT / "resources" / "data" / "places.json"
    target.parent.mkdir(parents=True, exist_ok=True)
    target.write_text(json.dumps(result, ensure_ascii=False, separators=(",", ":")) + "\n", encoding="utf-8", newline="\n")
    print(json.dumps({"points":len(points),"bytes":target.stat().st_size}))

if __name__ == "__main__":
    build()
