#!/usr/bin/env python3
"""
garmin_import
─────────────
Plug in Garmin GPSMAP 67, run this tool.
Finds unimported GPX files by checking track_metadata.source_file
and imports them via ogr2ogr.

Install: sudo cp garmin_import.py /usr/local/bin/garmin_import && sudo chmod +x /usr/local/bin/garmin_import
"""

from __future__ import annotations

import argparse
import logging
import os
import subprocess
import sys
from pathlib import Path

import psycopg2

# ── Logging ───────────────────────────────────────────────────────────────────

logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s  %(levelname)-8s  %(message)s",
    datefmt="%H:%M:%S",
)
log = logging.getLogger(__name__)

# ── Config ────────────────────────────────────────────────────────────────────

_DB_HOST = "db.courtman.me"
_DB_NAME = "family"
_DB_USER = "nicholas"

_GARMIN_SERIAL = "Garmin_G_0000d0042970"
_GARMIN_GPX_SUBDIRS = [
    Path("Internal Storage/GARMIN/GPX/Archive"),
    Path("Internal Storage/GARMIN/GPX"),
]


# ── Garmin mount detection ────────────────────────────────────────────────────

def _find_garmin_gpx_dir() -> Path | None:
    gvfs_root = Path(f"/run/user/{os.getuid()}/gvfs")
    mount = gvfs_root / f"mtp:host={_GARMIN_SERIAL}"
    if not mount.exists():
        log.error("Garmin not mounted at %s. Is it plugged in?", mount)
        return None
    for subdir in _GARMIN_GPX_SUBDIRS:
        full = mount / subdir
        if full.exists():
            log.info("Found GPX directory: %s", full)
            return full
    log.error("Garmin mounted at %s but no GPX directory found.", mount)
    return None


# ── DB helpers ────────────────────────────────────────────────────────────────

def _db_connect() -> psycopg2.extensions.connection:
    return psycopg2.connect(host=_DB_HOST, dbname=_DB_NAME, user=_DB_USER)


def _pg_dsn() -> str:
    return f"host={_DB_HOST} dbname={_DB_NAME} user={_DB_USER}"


def _already_imported(cur, filename: str) -> bool:
    cur.execute(
        "SELECT 1 FROM geospatial_tracking.track_metadata WHERE source_file = %s",
        (filename,),
    )
    return cur.fetchone() is not None


def _find_new_track_fid(cur) -> int:
    cur.execute("""
        SELECT ogc_fid
        FROM geospatial_tracking.tracks
        WHERE ogc_fid NOT IN (
            SELECT track_reference FROM geospatial_tracking.track_metadata
        )
        ORDER BY ogc_fid DESC
        LIMIT 1
    """)
    row = cur.fetchone()
    if row is None:
        raise RuntimeError("Could not determine the imported track's ogc_fid.")
    return row[0]


# ── Import logic ──────────────────────────────────────────────────────────────

def _import_gpx(gpx: Path, dry_run: bool) -> None:
    cmd = [
        "ogr2ogr",
        "-update", "-append",
        "-f", "PostgreSQL",
        f"PG:{_pg_dsn()} active_schema=geospatial_tracking",
        str(gpx),
    ]
    if dry_run:
        log.info("[dry-run] would run: %s", " ".join(cmd))
        return
    result = subprocess.run(cmd, capture_output=True, text=True)
    if result.returncode != 0:
        raise RuntimeError(result.stderr.strip())


# ── Main ──────────────────────────────────────────────────────────────────────

def main() -> None:
    parser = argparse.ArgumentParser(
        description="Import unregistered GPX files from a Garmin GPSMAP 67."
    )
    parser.add_argument(
        "--path", type=Path, default=None,
        help="Override GPX directory (default: auto-detect Garmin mount)",
    )
    parser.add_argument("--dry-run", action="store_true")
    parser.add_argument("--verbose", "-v", action="store_true")
    args = parser.parse_args()

    if args.verbose:
        logging.getLogger().setLevel(logging.DEBUG)

    gpx_dir: Path | None = args.path or _find_garmin_gpx_dir()
    if gpx_dir is None:
        sys.exit(1)

    gpx_files = sorted(gpx_dir.glob("*.gpx"))
    if not gpx_files:
        log.info("No GPX files found in %s.", gpx_dir)
        return

    log.info("Found %d GPX file(s).", len(gpx_files))

    imported = skipped = failed = 0

    conn = _db_connect()
    try:
        with conn.cursor() as cur:
            for gpx in gpx_files:
                if _already_imported(cur, gpx.name):
                    log.debug("Already imported: %s", gpx.name)
                    skipped += 1
                    continue

                log.info("Importing: %s", gpx.name)
                try:
                    _import_gpx(gpx, dry_run=args.dry_run)
                except RuntimeError as exc:
                    log.error("ogr2ogr failed for %s: %s", gpx.name, exc)
                    failed += 1
                    continue

                if not args.dry_run:
                    track_fid = _find_new_track_fid(cur)
                    cur.execute("""
                        INSERT INTO geospatial_tracking.track_metadata
                            (track_reference, source_file)
                        VALUES (%s, %s)
                        ON CONFLICT DO NOTHING
                    """, (track_fid, gpx.name))
                    conn.commit()
                    log.info("Registered: %s → ogc_fid %d", gpx.name, track_fid)

                imported += 1

    finally:
        conn.close()

    log.info("Done. imported=%d  skipped=%d  failed=%d", imported, skipped, failed)
    if failed:
        sys.exit(1)


if __name__ == "__main__":
    main()
