"""
MLP artifact status report — shows what's trained, what's winning, and whether
Pine is in sync.

Usage:
    python3 tools/mlp_status.py
    python3 tools/mlp_status.py --asset COINBASE_BTCUSD
"""

from __future__ import annotations

import json
import os
import re
import sys
from pathlib import Path

REPO = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(REPO))

ALL_ASSETS = ["COINBASE_BTCUSD", "COINBASE_ETHUSD", "BINANCE_SOLUSD", "BINANCE_LINKUSD"]
ALL_TFS    = ["4H", "6H", "8H", "12H", "1D"]
WEIGHTS_DIR = REPO / "strategies" / "params" / "mlp"
WINNER_DIR  = REPO / "results" / "winners"
PINE_FILE   = REPO / "strategies" / "strategy_mlp_scores.pine"


def winner_path(asset: str, tf: str) -> Path:
    return WINNER_DIR / f"optimization_winner_strategy_mlp_scores_{asset}_{tf}.csv"


def load_winner_artifact(asset: str, tf: str) -> str | None:
    p = winner_path(asset, tf)
    if not p.exists():
        return None
    import csv
    with open(p) as f:
        rows = list(csv.DictReader(f))
    if not rows:
        return None
    return rows[0].get("mlp_weights_file", "").strip() or None


def artifact_arch(path: str) -> list[int] | None:
    if not os.path.exists(path):
        return None
    try:
        with open(path) as f:
            data = json.load(f)
        return data.get("arch")
    except Exception:
        return None


def pine_preset_artifacts() -> dict[str, str]:
    """Parse the Pine sentinel block to find which artifact sha8 each preset uses."""
    if not PINE_FILE.exists():
        return {}
    content = PINE_FILE.read_text()
    result = {}
    for line in content.splitlines():
        # Lines like: // COINBASE_BTCUSD 4H  arch: [49, 16, 8, 1]  artifact: 9c6546f0
        if line.strip().startswith("//") and "artifact:" in line:
            parts = line.split("artifact:")
            if len(parts) == 2:
                sha = parts[1].strip()
                key_part = parts[0].replace("//", "").strip()
                # key_part like "COINBASE_BTCUSD 4H  arch: [49, 16, 8, 1]  "
                key = key_part.split("arch:")[0].strip()
                result[key] = sha
    return result


def artifact_sha8(path: str) -> str | None:
    if not os.path.exists(path):
        return None
    try:
        import hashlib
        with open(path, "rb") as f:
            return hashlib.sha256(f.read()).hexdigest()[:8]
    except Exception:
        return None


_PLOT_RE = re.compile(
    r"\bplot(?:char|shape|arrow|bar|candle)?\s*\(|\bbgcolor\s*\(",
    re.MULTILINE,
)
_PLOT_LIMIT = 64


def pine_plot_budget() -> tuple[int, int]:
    """Return (used, limit) for strategy_mlp_scores.pine, ignoring commented lines."""
    if not PINE_FILE.exists():
        return 0, _PLOT_LIMIT
    lines = [re.sub(r"//.*", "", ln) for ln in PINE_FILE.read_text().splitlines()]
    used = len(_PLOT_RE.findall("\n".join(lines)))
    return used, _PLOT_LIMIT


def seeds_for(asset: str, tf: str) -> dict[str, list[int]]:
    """Return {tag: [seeds]} for all tagged artifacts."""
    tags: dict[str, list[int]] = {}
    for p in sorted(WEIGHTS_DIR.glob(f"mlp_weights_{asset}_{tf}_*.json")):
        stem = p.stem  # mlp_weights_ASSET_TF_tag_seedN
        suffix = stem[len(f"mlp_weights_{asset}_{tf}_"):]
        if "_seed" in suffix:
            tag, seed_str = suffix.rsplit("_seed", 1)
            try:
                tags.setdefault(tag, []).append(int(seed_str))
            except ValueError:
                pass
        elif suffix.startswith("seed"):
            try:
                tags.setdefault("(base)", []).append(int(suffix[4:]))
            except ValueError:
                pass
    return {k: sorted(v) for k, v in tags.items()}


def main() -> None:
    import argparse
    parser = argparse.ArgumentParser(description="MLP artifact status report")
    parser.add_argument("--asset", nargs="*", default=ALL_ASSETS, choices=ALL_ASSETS)
    args = parser.parse_args()

    pine_shas = pine_preset_artifacts()
    arch_counts: dict[tuple, int] = {}

    print(f"\n{'Asset/TF':<20} {'Winner artifact':<48} {'Arch':<16} {'Seeds (tags)':<30} {'Pine'}")
    print("─" * 120)

    warnings = []
    for asset in args.asset:
        for tf in ALL_TFS:
            winner_art = load_winner_artifact(asset, tf)
            if winner_art:
                art_name = Path(winner_art).name
                arch = artifact_arch(winner_art) or []
                arch_str = "→".join(str(d) for d in arch) if arch else "?"
                arch_counts[tuple(arch)] = arch_counts.get(tuple(arch), 0) + 1
            else:
                art_name = "(no winner)"
                arch_str = "?"

            tag_seeds = seeds_for(asset, tf)
            seed_str = ", ".join(f"{t}×{len(s)}" for t, s in tag_seeds.items()) or "none"

            # Pine sync check (BTC only — others not in Pine yet)
            pine_status = ""
            if asset == "COINBASE_BTCUSD":
                pine_key = f"COINBASE_BTCUSD {tf}"
                pine_sha = pine_shas.get(pine_key)
                if winner_art and pine_sha:
                    art_sha = artifact_sha8(winner_art)
                    if art_sha and pine_sha == art_sha[:8]:
                        pine_status = "✅ synced"
                    elif art_sha:
                        pine_status = f"⚠️  pine={pine_sha} art={art_sha[:8]}"
                        warnings.append(f"{asset} {tf}: Pine sha {pine_sha} ≠ artifact sha {art_sha[:8]}")
                    else:
                        pine_status = "?"
                elif not winner_art:
                    pine_status = "—"
                else:
                    pine_status = "? (not in pine)"

            label = f"{asset} {tf}"
            print(f"{label:<20} {art_name:<48} {arch_str:<16} {seed_str:<30} {pine_status}")

        print()

    # Summary
    if len(arch_counts) > 1:
        print("⚠️  MIXED ARCHITECTURES DETECTED:")
        for arch, count in sorted(arch_counts.items()):
            print(f"   {'→'.join(str(d) for d in arch)}: {count} TFs")
        print("   Pine can only use ONE arch. Do Phase 2 upgrade before pasting.\n")
    elif arch_counts:
        arch = list(arch_counts.keys())[0]
        print(f"Architecture: {'→'.join(str(d) for d in arch)} (consistent across all TFs ✅)\n")

    # Pine plot slot budget
    used, limit = pine_plot_budget()
    remaining = limit - used
    budget_icon = "🔴" if remaining <= 3 else ("⚠️ " if remaining <= 10 else "✅")
    print(f"Pine plot budget: {budget_icon} {used}/{limit} used, {remaining} slots remaining")

    if warnings:
        print("\nWarnings:")
        for w in warnings:
            print(f"  ⚠️  {w}")


if __name__ == "__main__":
    main()
