#!/usr/bin/env python3 from __future__ import annotations import argparse import json import sys from pathlib import Path from typing import Any sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src")) from garmin_coach_clone.coach import ( best_workout_for_date, find_date_matches, find_workout_like_objects, ) from garmin_coach_clone.dates import parse_date from garmin_coach_clone.io import dump_redacted_json, print_json from garmin_coach_clone.workouts import ( clone_workout_payload, summarize_workout, validate_workout_payload, ) def main() -> int: parser = argparse.ArgumentParser(description="Analyze saved Garmin JSON without logging in.") parser.add_argument("json_file", type=Path, help="Path to a saved JSON dump.") parser.add_argument("--date", default="today", help="today, tomorrow, or YYYY-MM-DD") parser.add_argument( "--clone-dry-run", action="store_true", help="Build a local clone payload from the matched workout.", ) parser.add_argument("--prefix", default="GCClone", help="Clone workout name prefix.") parser.add_argument( "--dump-json", action="store_true", help="Write analysis JSON under debug/." ) args = parser.parse_args() target_date = parse_date(args.date) data = _load_json(args.json_file) date_matches = find_date_matches(data, target_date) workout_like = find_workout_like_objects(data) matched = best_workout_for_date(data, target_date) analysis: dict[str, Any] = { "source": str(args.json_file), "target_date": target_date.isoformat(), "date_match_count": len(date_matches), "workout_like_count": len(workout_like), "matched_workout": matched is not None, } print(f"Source: {args.json_file}") print(f"Target date: {target_date.isoformat()}") print(f"Date-containing objects: {len(date_matches)}") print(f"Workout-like objects with workoutSegments/workoutSteps: {len(workout_like)}") if matched is None: print("No dated workout-like object was found.") if args.dump_json: out = _analysis_path(args.json_file) dump_redacted_json(out, analysis) print(f"Analysis JSON written to {out}") return 1 print("\nMatched workout summary:") print(summarize_workout(matched)) if args.clone_dry_run: payload = clone_workout_payload(matched, target_date, args.prefix) errors = validate_workout_payload(payload) analysis["clone_validation_errors"] = errors analysis["clone_payload"] = payload if errors: print("\nLocal clone payload failed validation:") for error in errors: print(f" - {error}") return_code = 1 else: print("\nLocal clone payload passed validation.") print_json(payload) return_code = 0 else: return_code = 0 if args.dump_json: out = _analysis_path(args.json_file) dump_redacted_json(out, analysis) print(f"Analysis JSON written to {out}") return return_code def _load_json(path: Path) -> Any: try: return json.loads(path.read_text(encoding="utf-8")) except FileNotFoundError: raise SystemExit(f"File not found: {path}") from None except json.JSONDecodeError as exc: raise SystemExit(f"Invalid JSON in {path}: {exc}") from None def _analysis_path(source: Path) -> Path: stem = source.stem.replace(".", "_") return Path("debug") / f"analysis_{stem}.json" if __name__ == "__main__": raise SystemExit(main())