#!/usr/bin/env python3
"""
AirGradient ONE sync - polls local device JSON API and stores to chl_air_quality.

Runs every 5 min via launchd (com.chl.airgradient-sync).
Config: .claude/context/airgradient-config.json

Usage:
    python sync-airgradient.py          # One poll, write to Supabase
    python sync-airgradient.py --test   # One poll, print only (no DB write)
"""

import argparse
import json
import sys
import urllib.error
import urllib.request
from datetime import datetime, timedelta, timezone
from pathlib import Path

sys.path.insert(0, str(Path(__file__).parent / '.claude' / 'skills' / 'supabase-connector'))

CONFIG_PATH = Path(__file__).parent / '.claude' / 'context' / 'airgradient-config.json'
BRISBANE_TZ = timezone(timedelta(hours=10))


def log(msg):
    ts = datetime.now(BRISBANE_TZ).strftime("%Y-%m-%d %H:%M:%S")
    print(f"[{ts}] {msg}")


def load_config():
    with open(CONFIG_PATH) as f:
        return json.load(f)


def fetch_measures(device_ip, timeout):
    url = f"http://{device_ip}/measures/current"
    req = urllib.request.Request(url, headers={"Accept": "application/json"})
    with urllib.request.urlopen(req, timeout=timeout) as resp:
        return json.loads(resp.read().decode("utf-8"))


def _as_int(v):
    return int(round(v)) if isinstance(v, (int, float)) else None


def build_row(measures, device_serial):
    """Map AirGradient field names to our schema."""
    now = datetime.now(BRISBANE_TZ).isoformat()
    return {
        "measured_at": now,
        "pm01": measures.get("pm01"),
        "pm25": measures.get("pm02"),
        "pm10": measures.get("pm10"),
        "co2_ppm": _as_int(measures.get("rco2")),
        "tvoc_index": _as_int(measures.get("tvocIndex")),
        "nox_index": _as_int(measures.get("noxIndex")),
        "temp_c": measures.get("atmp"),
        "humidity_pct": measures.get("rhum"),
        "device_serial": device_serial,
        "raw": measures,
    }


def main():
    parser = argparse.ArgumentParser(description="Poll AirGradient ONE and write to Supabase")
    parser.add_argument("--test", action="store_true", help="Print row, don't write to DB")
    args = parser.parse_args()

    try:
        config = load_config()
    except Exception as e:
        log(f"ERROR loading config: {e}")
        return 1

    if not config.get("enabled", True):
        log("AirGradient sync disabled in config")
        return 0

    device_ip = config.get("device_ip", "")
    if not device_ip or device_ip.startswith("REPLACE_ME"):
        log("ERROR: device_ip not set in airgradient-config.json")
        return 1

    device_serial = config.get("device_serial", "unknown")
    timeout = config.get("poll_timeout_seconds", 5)

    log(f"Polling http://{device_ip}/measures/current")
    try:
        measures = fetch_measures(device_ip, timeout)
    except urllib.error.URLError as e:
        log(f"ERROR: device unreachable: {e}")
        return 1
    except Exception as e:
        log(f"ERROR fetching measures: {e}")
        return 1

    row = build_row(measures, device_serial)
    log(
        f"CO2={row['co2_ppm']} PM2.5={row['pm25']} VOC={row['tvoc_index']} "
        f"NOx={row['nox_index']} T={row['temp_c']}C RH={row['humidity_pct']}%"
    )

    if args.test:
        log("TEST MODE: not writing to DB")
        print(json.dumps(row, indent=2, default=str))
        return 0

    try:
        from client import get_supabase_client
        supabase = get_supabase_client()
    except Exception as e:
        log(f"ERROR connecting to Supabase: {e}")
        return 1

    try:
        supabase.table("chl_air_quality").upsert(
            row, on_conflict="device_serial,measured_at"
        ).execute()
        log("Wrote 1 row to chl_air_quality")
    except Exception as e:
        log(f"ERROR writing to Supabase: {e}")
        return 1

    return 0


if __name__ == "__main__":
    sys.exit(main())
