#!/usr/bin/env python3
"""
Download the most recent N recording docs for a user and write them as JSON
fixtures the Kotlin ingest test can load. Defaults to ericmigi@gmail.com /
20 recordings; pass `--email erohead@gmail.com --limit 20` for the user the
prompt called out.

Usage:
    ./dump_user_recordings.py --email erohead@gmail.com --limit 20
    ./dump_user_recordings.py --uid <firebase-uid> --out path/to/dir

Each fixture is written as `<docId>.json` in the output directory. The JSON
uses gitlive's serialization shape (epochSeconds/nanosecondsOfSecond, etc.)
so the Kotlin side can decode it via the same `@Serializable` data classes
used at runtime — no porting of the schema required.

Run after `gcloud auth application-default login` (uses ADC).
"""

import argparse
import json
import sys
from datetime import datetime, timezone
from pathlib import Path

import firebase_admin
import google.auth
from firebase_admin import auth, credentials, firestore

DEFAULT_EMAIL = "ericmigi@gmail.com"
DEFAULT_LIMIT = 20
ROOT = Path(__file__).resolve().parent
GOOGLE_SERVICES_JSON = ROOT / "google-services.json"
DEFAULT_OUT = ROOT / "tools" / "ingest_fixtures"


def project_id_from_google_services() -> str:
    if not GOOGLE_SERVICES_JSON.exists():
        sys.exit(f"google-services.json not found at {GOOGLE_SERVICES_JSON}")
    return json.loads(GOOGLE_SERVICES_JSON.read_text())["project_info"]["project_id"]


def init_app(project_id: str):
    if firebase_admin._apps:
        return firebase_admin.get_app()
    raw, _ = google.auth.default()
    if hasattr(raw, "with_quota_project"):
        raw = raw.with_quota_project(project_id)
    cred = credentials.ApplicationDefault()
    cred._g_credential = raw
    return firebase_admin.initialize_app(cred, {"projectId": project_id})


def resolve_uid(email: str | None, uid: str | None) -> str:
    if uid:
        return uid
    try:
        return auth.get_user_by_email(email).uid
    except auth.UserNotFoundError:
        sys.exit(f"No Firebase user found for {email}")


def normalize(value):
    """Convert Firestore client types to JSON-friendly Python objects so
    kotlinx.serialization can decode them on the other side."""
    if value is None:
        return None
    if isinstance(value, dict):
        return {k: normalize(v) for k, v in value.items()}
    if isinstance(value, list):
        return [normalize(v) for v in value]
    if isinstance(value, (str, int, float, bool)):
        return value
    if hasattr(value, "isoformat"):
        # google.cloud.firestore_v1.types.Timestamp / DatetimeWithNanoseconds
        # → {epochSeconds, nanosecondsOfSecond} so the Kotlin side decodes it
        # the same way kotlin.time.Instant.Serializer expects.
        if not value.tzinfo:
            value = value.replace(tzinfo=timezone.utc)
        secs = int(value.timestamp())
        nanos = getattr(value, "nanosecond", 0)
        return {"epochSeconds": secs, "nanosecondsOfSecond": nanos}
    if hasattr(value, "path"):  # DocumentReference
        return value.path
    if hasattr(value, "latitude"):  # GeoPoint
        return {"lat": value.latitude, "lng": value.longitude}
    return str(value)


def main() -> int:
    p = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
    p.add_argument("--email", help=f"User email (default: {DEFAULT_EMAIL})")
    p.add_argument("--uid", help="Firebase UID (overrides --email)")
    p.add_argument("--limit", type=int, default=DEFAULT_LIMIT, help=f"Number of recordings to fetch (default: {DEFAULT_LIMIT})")
    p.add_argument("--out", type=Path, default=DEFAULT_OUT, help=f"Output directory (default: {DEFAULT_OUT})")
    args = p.parse_args()

    email = args.email if (args.email or args.uid) else DEFAULT_EMAIL
    project = project_id_from_google_services()
    init_app(project)
    uid = resolve_uid(email, args.uid)
    db = firestore.client()

    args.out.mkdir(parents=True, exist_ok=True)

    docs = (
        db.collection("recordings")
        .document(uid)
        .collection("recordings")
        .order_by("timestamp", direction=firestore.Query.DESCENDING)
        .limit(args.limit)
        .stream()
    )

    written = 0
    for d in docs:
        data = d.to_dict() or {}
        data["_id"] = d.id
        normalized = normalize(data)
        path = args.out / f"{d.id}.json"
        path.write_text(json.dumps(normalized, indent=2, ensure_ascii=False))
        written += 1
        n_msgs = len(((data.get("assistant_session") or {}).get("messages") or []))
        n_entries = len(data.get("entries") or [])
        print(f"  → {d.id}  msgs={n_msgs} entries={n_entries}")

    print(f"\nWrote {written} fixtures to {args.out}")
    return 0


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