#!/usr/bin/env python3
# HL REV:NEWFILE
"""
Automated probes for Trajectories tab diagnostics.

This script runs several simulated scenarios to diagnose the trajectories tab:
1. NORMAL: Uses real data from data/motions.db
2. EMPTY_POSITIONS: Simulates load_positions returning empty (realistic failure mode)
3. EMPTY_PARTY_MAP: Simulates load_party_map returning empty (realistic failure mode)
4. BOTH_EMPTY: Simulates both returning empty (severe failure mode)

Run: python scripts/diagnose_trajectories_cli.py
"""

import os
import importlib
import traceback
import sys
import json
from datetime import datetime

# Real DB path relative to project root
DB_PATH = os.path.abspath(
    os.path.join(os.path.dirname(__file__), "..", "data", "motions.db")
)


def run():
    os.environ.setdefault("EXPLORER_DEBUG_TRAJECTORIES", "1")
    # Ensure project root is on sys.path so 'import explorer' finds the module
    root = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
    if root not in sys.path:
        sys.path.insert(0, root)

    # Import explorer fresh so env var reads take effect
    import explorer

    # Results collection for all scenarios
    all_results = {
        "generated_at": datetime.now().isoformat(),
        "db_path": DB_PATH,
        "db_exists": os.path.exists(DB_PATH),
        "scenarios": {},
    }

    def run_scenario(
        name,
        load_positions_ret=None,
        load_party_map_ret=None,
        select_helper_behavior=None,
        use_real_data=False,
    ):
        print("\n" + "=" * 80)
        print("SCENARIO:", name)
        print("=" * 80)

        scenario_result = {
            "name": name,
            "use_real_data": use_real_data,
            "monkeypatched": {},
        }

        # Clear previous diagnostics
        explorer._last_trajectories_diagnostics.clear()

        # Backup originals
        orig_load_positions = getattr(explorer, "load_positions", None)
        orig_load_party_map = getattr(explorer, "load_party_map", None)
        orig_select_helper = getattr(explorer, "select_trajectory_plot_data", None)

        # If using real data, call the real functions once to get actual values
        if use_real_data and os.path.exists(DB_PATH):
            print(f"Loading real data from: {DB_PATH}")
            try:
                real_positions = explorer.load_positions(DB_PATH, "annual")
                real_party_map = explorer.load_party_map(DB_PATH)
                print(
                    f"  Real load_positions: {len(real_positions[0]) if real_positions[0] else 0} windows"
                )
                print(f"  Real party_map: {len(real_party_map)} entries")
                scenario_result["real_data"] = {
                    "positions_windows": len(real_positions[0])
                    if real_positions[0]
                    else 0,
                    "party_map_count": len(real_party_map),
                }
            except Exception as e:
                print(f"  ERROR loading real data: {e}")
                scenario_result["real_data_error"] = str(e)

        if load_positions_ret is not None:
            explorer.load_positions = lambda db, ws: load_positions_ret
            scenario_result["monkeypatched"]["load_positions"] = "ARTIFICIAL_EMPTY"
            print(
                "  Monkeypatched: load_positions -> ARTIFICIAL_EMPTY (for comparison)"
            )

        if load_party_map_ret is not None:
            explorer.load_party_map = lambda db: load_party_map_ret
            scenario_result["monkeypatched"]["load_party_map"] = "ARTIFICIAL_EMPTY"
            print(
                "  Monkeypatched: load_party_map -> ARTIFICIAL_EMPTY (for comparison)"
            )

        if select_helper_behavior == "raise":

            def raising(*args, **kwargs):
                raise ValueError("simulated crash from select_trajectory_plot_data")

            explorer.select_trajectory_plot_data = raising
            scenario_result["monkeypatched"]["select_helper"] = "RAISE_ERROR"
            print("  Monkeypatched: select_trajectory_plot_data -> RAISE_ERROR")

        elif select_helper_behavior == "zero_traces":

            class DummyFig:
                def __init__(self):
                    self.data = []

            def zero(*args, **kwargs):
                return DummyFig(), 0, None

            explorer.select_trajectory_plot_data = zero
            scenario_result["monkeypatched"]["select_helper"] = "ZERO_TRACES"
            print("  Monkeypatched: select_trajectory_plot_data -> ZERO_TRACES")

        try:
            # Call the UI function; it's import-safe and uses a dummy st when streamlit is absent
            explorer.build_trajectories_tab(db_path=DB_PATH, window_size="annual")
        except Exception as e:
            print("build_trajectories_tab RAISED:", type(e), e)
            print(traceback.format_exc())
            scenario_result["exception"] = str(e)
            scenario_result["traceback"] = traceback.format_exc()

        # Capture diagnostics
        diag = getattr(explorer, "_last_trajectories_diagnostics", None)
        scenario_result["diagnostics"] = dict(diag) if diag else {}
        print("module _last_trajectories_diagnostics:", diag)

        sh = None
        if hasattr(explorer, "select_trajectory_plot_data"):
            sh = getattr(
                explorer.select_trajectory_plot_data, "_last_diagnostics", None
            )
        scenario_result["select_helper_diagnostics"] = dict(sh) if sh else {}
        print("select_helper _last_diagnostics:", sh)

        # restore originals
        if orig_load_positions is not None:
            explorer.load_positions = orig_load_positions
        if orig_load_party_map is not None:
            explorer.load_party_map = orig_load_party_map
        if orig_select_helper is not None:
            explorer.select_trajectory_plot_data = orig_select_helper

        all_results["scenarios"][name] = scenario_result

    # Scenario 1: NORMAL - Uses real data
    print("\n" + "=" * 80)
    print("SCENARIO 1: NORMAL (using real data)")
    print("=" * 80)
    run_scenario("normal", use_real_data=True)

    # Scenario 2: Empty positions (ARTIFICIAL - for comparison)
    print("\n" + "=" * 80)
    print("SCENARIO 2: EMPTY_POSITIONS (ARTIFICIAL - for comparison)")
    print("=" * 80)
    run_scenario(
        "empty_positions_ARTIFICIAL",
        load_positions_ret=({}, {}),
        load_party_map_ret=None,  # Use real party_map
    )

    # Scenario 3: Empty party_map (ARTIFICIAL - for comparison)
    print("\n" + "=" * 80)
    print("SCENARIO 3: EMPTY_PARTY_MAP (ARTIFICIAL - for comparison)")
    print("=" * 80)
    run_scenario(
        "empty_party_map_ARTIFICIAL",
        load_positions_ret=None,  # Use real positions
        load_party_map_ret={},
    )

    # Scenario 4: Both empty (ARTIFICIAL - for comparison)
    print("\n" + "=" * 80)
    print("SCENARIO 4: BOTH_EMPTY (ARTIFICIAL - for comparison)")
    print("=" * 80)
    run_scenario(
        "both_empty_ARTIFICIAL", load_positions_ret=({}, {}), load_party_map_ret={}
    )

    # Write results to diagnostics file
    output_dir = os.path.join(root, "thoughts", "shared", "diagnostics")
    os.makedirs(output_dir, exist_ok=True)
    output_path = os.path.join(output_dir, "2026-03-31-trajectories-diagnostics.json")

    with open(output_path, "w") as f:
        json.dump(all_results, f, indent=2, default=str)

    print("\n" + "=" * 80)
    print(f"DIAGNOSTICS SAVED TO: {output_path}")
    print("=" * 80)

    # Summary
    print("\n" + "=" * 80)
    print("SUMMARY")
    print("=" * 80)

    normal_scenario = all_results["scenarios"].get("normal", {})
    real_data = normal_scenario.get("real_data", {})
    party_map_count = real_data.get("party_map_count", 0)

    print(f"DB Path: {DB_PATH}")
    print(f"DB Exists: {all_results['db_exists']}")
    print(f"Real data party_map_count: {party_map_count}")

    if party_map_count > 0:
        print("\n✅ SUCCESS: Real data scenario shows party_map_count > 0")
        print(f"   Found {party_map_count} party entries (expected ~1000+)")
    else:
        print("\n❌ ISSUE: Real data scenario shows party_map_count = 0")

    # Check diagnostics from normal scenario
    normal_diag = normal_scenario.get("diagnostics", {})
    if normal_diag:
        print(f"\nNormal scenario diagnostics keys: {list(normal_diag.keys())}")
        print(f"Normal scenario stage: {normal_diag.get('stage', 'N/A')}")

    return all_results


if __name__ == "__main__":
    results = run()
