#!/usr/bin/env python3
"""
BPF 2026 — Build-time Airtable fetcher.

Reads PAT from .env (gitignored), fetches all 5 Airtable tables,
writes data.json. The BPFmap.html app reads this JSON at runtime
instead of calling Airtable directly — so the PAT never ships to
the client.

Run:  python3 build.py
Output: data.json in the same directory.

Workflow:
  1. Team edits in Airtable as usual
  2. You run `python3 build.py` to refresh local data.json
  3. Deploy (drag-drop folder to Cloudflare Pages, or push to git)
"""
import json
import os
import subprocess
import sys
import time
import urllib.parse
from pathlib import Path

ROOT = Path(__file__).resolve().parent
ENV_FILE = ROOT / ".env"
OUTPUT_FILE = ROOT / "data.json"

DEFAULT_BASE_ID = "appQ7B5TqP7RRK5Xp"

TABLES = [
    "BPF_Venues",
    "BPF_Events",
    "BPF_Categories",
    "BPF_App_Copy",
    "BPF_Settings",
]


def load_env(path: Path) -> dict:
    env = {}
    if not path.exists():
        return env
    for line in path.read_text().splitlines():
        line = line.strip()
        if not line or line.startswith("#") or "=" not in line:
            continue
        k, v = line.split("=", 1)
        env[k.strip()] = v.strip().strip("'\"")
    return env


def fetch_table(pat: str, base_id: str, table_name: str) -> list:
    """Uses macOS-bundled `curl` (system CA bundle, no Python cert issues)."""
    records = []
    offset = None
    while True:
        params = {"pageSize": "100"}
        if offset:
            params["offset"] = offset
        url = "https://api.airtable.com/v0/{}/{}?{}".format(
            base_id,
            urllib.parse.quote(table_name),
            urllib.parse.urlencode(params),
        )
        proc = subprocess.run(
            [
                "curl",
                "--silent",
                "--show-error",
                "--max-time", "30",
                "--fail-with-body",
                "--header", "Authorization: Bearer " + pat,
                url,
            ],
            capture_output=True,
            text=True,
        )
        if proc.returncode != 0:
            sys.exit(
                "  FAIL: {} — curl exit {}\n  {}".format(
                    table_name, proc.returncode, (proc.stderr or proc.stdout)[:400]
                )
            )
        try:
            payload = json.loads(proc.stdout)
        except json.JSONDecodeError as e:
            sys.exit("  FAIL: {} — invalid JSON: {}".format(table_name, e))
        records.extend(payload.get("records", []))
        offset = payload.get("offset")
        if not offset:
            return records


def main():
    env = load_env(ENV_FILE)
    pat = env.get("AIRTABLE_PAT") or os.environ.get("AIRTABLE_PAT")
    base_id = (
        env.get("AIRTABLE_BASE_ID")
        or os.environ.get("AIRTABLE_BASE_ID")
        or DEFAULT_BASE_ID
    )

    if not pat:
        sys.exit(
            "ERROR: AIRTABLE_PAT missing.\n"
            "  Create a .env file in this folder with:\n"
            "      AIRTABLE_PAT=pat...\n"
            "  See .env.example for template."
        )

    print("BPF build — fetching from Airtable base {}".format(base_id))
    t0 = time.time()
    tables_out = {}
    total_records = 0
    for name in TABLES:
        sys.stdout.write("  - {}... ".format(name))
        sys.stdout.flush()
        recs = fetch_table(pat, base_id, name)
        tables_out[name] = recs
        total_records += len(recs)
        print("{} records".format(len(recs)))

    output = {
        "_meta": {
            "generated_at": time.strftime("%Y-%m-%dT%H:%M:%S%z"),
            "base_id": base_id,
            "total_records": total_records,
            "build_seconds": round(time.time() - t0, 2),
        },
        "tables": tables_out,
    }

    OUTPUT_FILE.write_text(
        json.dumps(output, ensure_ascii=False, separators=(",", ":")),
        encoding="utf-8",
    )
    size_kb = OUTPUT_FILE.stat().st_size / 1024
    print(
        "\nOK: wrote {} ({:.1f} KB, {} records, {:.2f}s)".format(
            OUTPUT_FILE.name, size_kb, total_records, time.time() - t0
        )
    )


if __name__ == "__main__":
    main()
