from __future__ import annotations

import argparse
import json
from collections import Counter, defaultdict
from datetime import datetime, timezone
from decimal import Decimal
from pathlib import Path
from typing import Any

from paper_scorecard_report import build_paper_scorecard_report
from src.ctb_copy.reports.phase7_scorecard import build_phase7_scorecard, format_phase7_scorecard
from src.strategies.strategy_sleeves import build_sleeve_scorecard, format_sleeve_scorecard
from src.tools.hl_reconcile_watchdog import _load_json_from_reconcile, assess as assess_reconcile
from src.tools.tradingview_community_ideas import summarize_community_ideas
from src.tools.tradingview_community_track_record import summarize_track_record
from src.tools.tradingview_operational_gates import format_operational_gate_report, load_operational_gates
from src.tools.tradingview_paper_bridge import summarize_tradingview_paper_bridge
from src.tools.tradingview_promotion_gates import evaluate_promotion_gates, format_promotion_gate_report
from src.tools.tradingview_strategy_performance import recommend_strategy_actions, summarize_strategy_performance
from src.tools.v76_paper_runtime import BASE_ID, RESEARCH_ID, STRICT_ID, supervisor_status

ROOT = Path("runtime/experiments")


def _read_jsonl(path: Path) -> list[dict[str, Any]]:
    rows: list[dict[str, Any]] = []
    if not path.exists():
        return rows
    for line in path.read_text(encoding="utf-8", errors="replace").splitlines():
        if not line.strip():
            continue
        try:
            rows.append(json.loads(line))
        except json.JSONDecodeError:
            continue
    return rows


def _variant_stats(strategy_id: str) -> dict[str, Any]:
    trades = _read_jsonl(ROOT / strategy_id / "trade_journal.jsonl")
    signals = _read_jsonl(ROOT / strategy_id / "signal_journal.jsonl")
    pnls = [Decimal(str(row.get("net_pnl_usd") or row.get("realized_pnl_usd") or "0")) for row in trades]
    by_coin: defaultdict[str, Decimal] = defaultdict(lambda: Decimal("0"))
    counts: Counter[str] = Counter()
    for row, pnl in zip(trades, pnls):
        coin = str(row.get("coin") or "UNKNOWN").upper()
        by_coin[coin] += pnl
        counts[coin] += 1
    block_reasons: Counter[str] = Counter()
    regimes: Counter[str] = Counter()
    for row in signals[-240:]:
        for reason in row.get("block_reason") or []:
            block_reasons[str(reason)] += 1
        trend = str(row.get("trend_state") or "unknown")
        final = str(row.get("final_decision") or "")
        if "api_degraded" in final:
            regimes["api_degraded"] += 1
        elif final == "paper_entered" and trend == "up":
            regimes["breakout_confirmed"] += 1
        elif trend in {"flat", "unknown"}:
            regimes["choppy"] += 1
        elif trend == "up":
            regimes["risk_on"] += 1
        elif trend == "down":
            regimes["risk_off"] += 1
    total = sum(pnls, Decimal("0"))
    return {
        "strategy_id": strategy_id,
        "trades": len(trades),
        "signals_seen": len(signals),
        "signals_blocked": sum(1 for row in signals if not row.get("would_enter")),
        "pnl_total_net": str(total),
        "pnl_ex_wld": str(total - by_coin["WLD"]),
        "wld_pnl": str(by_coin["WLD"]),
        "top_coin_share_last_30": round((Counter(str(row.get("coin") or "UNKNOWN").upper() for row in trades[-30:]).most_common(1)[0][1] / min(30, len(trades)) * 100), 2) if trades else 0.0,
        "trade_share_by_coin": dict(sorted((coin, round(count / len(trades) * 100, 2)) for coin, count in counts.items())) if trades else {},
        "pnl_by_coin": dict(sorted((coin, str(pnl)) for coin, pnl in by_coin.items())),
        "top_block_reasons": dict(block_reasons.most_common(5)),
        "market_regime": regimes.most_common(1)[0][0] if regimes else "unknown",
    }


def _safe_decimal(value: Any) -> Decimal:
    try:
        return Decimal(str(value))
    except Exception:
        return Decimal("0")


def _fmt_decimal(value: Decimal, places: str = "0.01") -> str:
    return str(value.quantize(Decimal(places)))


def summarize_v76_lifecycle(strategy_id: str = STRICT_ID, runtime_dir: str | Path = "runtime") -> dict[str, Any]:
    root = Path(runtime_dir) / "experiments" / strategy_id
    trades = _read_jsonl(root / "trade_journal.jsonl")
    state_path = root / "state.json"
    state: dict[str, Any] = {}
    if state_path.exists():
        try:
            state = json.loads(state_path.read_text(encoding="utf-8"))
        except json.JSONDecodeError:
            state = {}
    raw_open_positions = state.get("open_positions")
    open_positions: dict[str, Any] = raw_open_positions if isinstance(raw_open_positions, dict) else {}
    entries = [row for row in trades if row.get("event") == "entry"]
    exits = [row for row in trades if row.get("event") == "exit" and row.get("exit_reason")]
    legacy_synthetic_exits = sum(1 for row in trades if row.get("event") == "exit" and not row.get("exit_reason"))
    exit_reasons = Counter(str(row.get("exit_reason") or "unknown") for row in exits)
    live_flags = sum(1 for row in trades if row.get("live_order_allowed") is True or row.get("mainnet_signed_action") is True)
    mfe_values = [_safe_decimal(row.get("mfe_pct")) for row in exits if row.get("mfe_pct") is not None]
    mae_values = [_safe_decimal(row.get("mae_pct")) for row in exits if row.get("mae_pct") is not None]
    net_pnl = sum((_safe_decimal(row.get("net_pnl_usd") or row.get("realized_pnl_usd")) for row in exits), Decimal("0"))
    pnl_by_coin: defaultdict[str, Decimal] = defaultdict(lambda: Decimal("0"))
    pnl_by_exit_reason: defaultdict[str, Decimal] = defaultdict(lambda: Decimal("0"))
    winning_exits = 0
    losing_exits = 0
    gross_wins = Decimal("0")
    gross_losses = Decimal("0")
    for row in exits:
        pnl = _safe_decimal(row.get("net_pnl_usd") or row.get("realized_pnl_usd"))
        coin = str(row.get("coin") or "UNKNOWN").upper()
        reason = str(row.get("exit_reason") or "unknown")
        pnl_by_coin[coin] += pnl
        pnl_by_exit_reason[reason] += pnl
        if pnl > 0:
            winning_exits += 1
            gross_wins += pnl
        elif pnl < 0:
            losing_exits += 1
            gross_losses += pnl
    open_by_coin = Counter(str(coin).upper() for coin in open_positions.keys())
    return {
        "strategy_id": strategy_id,
        "entries": len(entries),
        "exits": len(exits),
        "legacy_synthetic_exits": legacy_synthetic_exits,
        "open_positions": len(open_positions),
        "open_by_coin": dict(open_by_coin.most_common()),
        "exit_reasons": dict(exit_reasons.most_common()),
        "pnl_by_coin": dict(sorted((coin, _fmt_decimal(pnl)) for coin, pnl in pnl_by_coin.items())),
        "pnl_by_exit_reason": dict(sorted((reason, _fmt_decimal(pnl)) for reason, pnl in pnl_by_exit_reason.items())),
        "winning_exits": winning_exits,
        "losing_exits": losing_exits,
        "gross_wins_usd": _fmt_decimal(gross_wins),
        "gross_losses_usd": _fmt_decimal(gross_losses),
        "avg_mfe_pct": _fmt_decimal(sum(mfe_values, Decimal("0")) / Decimal(len(mfe_values)) if mfe_values else Decimal("0")),
        "avg_mae_pct": _fmt_decimal(sum(mae_values, Decimal("0")) / Decimal(len(mae_values)) if mae_values else Decimal("0")),
        "closed_net_pnl_usd": _fmt_decimal(net_pnl),
        "live_order_allowed_count": live_flags,
    }


def summarize_v76_lifecycle_scorecard(summary: dict[str, Any]) -> dict[str, Any]:
    """Build a promotion-safe scorecard from true lifecycle exits only.

    Legacy synthetic exits are intentionally excluded from all quality metrics.
    This function is read-only and never grants live permissions.
    """
    exits = int(summary.get("exits") or 0)
    by_reason = summary.get("pnl_by_exit_reason") or {}
    wins = int(summary.get("winning_exits") or 0)
    losses = int(summary.get("losing_exits") or 0)
    gross_wins = _safe_decimal(summary.get("gross_wins_usd"))
    gross_losses = abs(_safe_decimal(summary.get("gross_losses_usd")))
    profit_factor = Decimal("99") if gross_losses == 0 and gross_wins > 0 else (gross_wins / gross_losses if gross_losses else Decimal("0"))
    winrate = Decimal(wins) / Decimal(exits) * Decimal("100") if exits else Decimal("0")
    blockers: list[str] = []
    if int(summary.get("legacy_synthetic_exits") or 0) > 0:
        blockers.append("legacy_synthetic_exits_ignored")
    if exits < 30:
        blockers.append("lifecycle_sample_too_small")
    if _safe_decimal(summary.get("closed_net_pnl_usd")) <= 0:
        blockers.append("lifecycle_pnl_not_positive")
    if winrate < Decimal("50"):
        blockers.append("lifecycle_winrate_below_threshold")
    if int(summary.get("live_order_allowed_count") or 0) > 0:
        blockers.append("unexpected_live_flag")
    if losses and not by_reason.get("take_profit") and not by_reason.get("trailing_stop"):
        blockers.append("no_positive_exit_reason_edge")
    return {
        "evidence_source": "true_lifecycle_exits_only",
        "closed_trades": exits,
        "winning_exits": wins,
        "losing_exits": losses,
        "winrate_pct": _fmt_decimal(winrate),
        "profit_factor": _fmt_decimal(profit_factor),
        "net_pnl_usd": summary.get("closed_net_pnl_usd", "0.00"),
        "pnl_by_exit_reason": by_reason,
        "pnl_by_coin": summary.get("pnl_by_coin", {}),
        "blockers": blockers,
        "shadow_candidate": not blockers,
        "live_allowed": False,
    }


def format_v76_lifecycle_report(summary: dict[str, Any]) -> str:
    return (
        f"v76 Lifecycle: entries={summary['entries']}, exits={summary['exits']}, open={summary['open_positions']}, "
        f"legacy_synthetic_exits={summary['legacy_synthetic_exits']}, "
        f"open_coins={summary['open_by_coin'] or 'keine'}, exits_by_reason={summary['exit_reasons'] or 'keine'}, "
        f"closed_pnl={summary['closed_net_pnl_usd']} USDC, avg_mfe={summary['avg_mfe_pct']}%, avg_mae={summary['avg_mae_pct']}%, "
        f"live_flags={summary['live_order_allowed_count']}"
    )


def format_v76_lifecycle_scorecard(scorecard: dict[str, Any]) -> str:
    blockers = scorecard.get("blockers") or []
    blocker_text = ",".join(blockers[:5]) if blockers else "keine"
    return (
        "v76 Lifecycle Scorecard: "
        f"source={scorecard['evidence_source']}, "
        f"closed={scorecard['closed_trades']}, "
        f"winrate={scorecard['winrate_pct']}%, "
        f"pf={scorecard['profit_factor']}, "
        f"net_pnl={scorecard['net_pnl_usd']} USDC, "
        f"by_exit={scorecard['pnl_by_exit_reason'] or 'keine'}, "
        f"by_coin={scorecard['pnl_by_coin'] or 'keine'}, "
        f"blocker={blocker_text}, live=nein"
    )


def _parse_ts(value: Any) -> datetime | None:
    if not value:
        return None
    try:
        return datetime.fromisoformat(str(value).replace("Z", "+00:00"))
    except ValueError:
        return None


def summarize_v76_anti_chase_impact(strategy_id: str = STRICT_ID, runtime_dir: str | Path = "runtime") -> dict[str, Any]:
    root = Path(runtime_dir) / "experiments" / strategy_id
    signals = _read_jsonl(root / "signal_journal.jsonl")
    trades = _read_jsonl(root / "trade_journal.jsonl")
    anti_prefix = "anti_chase_"
    anti_signals = [row for row in signals if any(str(reason).startswith(anti_prefix) for reason in (row.get("block_reason") or []))]
    anti_timestamps = [ts for ts in (_parse_ts(row.get("timestamp")) for row in anti_signals) if ts is not None]
    first_anti_ts = min(anti_timestamps) if anti_timestamps else None
    signal_window = signals[-240:]
    blocker_counts: Counter[str] = Counter()
    blocker_counts_recent: Counter[str] = Counter()
    for row in signals:
        for reason in row.get("block_reason") or []:
            if str(reason).startswith(anti_prefix):
                blocker_counts[str(reason)] += 1
    for row in signal_window:
        for reason in row.get("block_reason") or []:
            if str(reason).startswith(anti_prefix):
                blocker_counts_recent[str(reason)] += 1
    paper_entries = [row for row in signals if row.get("final_decision") == "paper_opened_lifecycle"]
    exits = [row for row in trades if row.get("event") == "exit" and row.get("exit_reason")]
    post_filter_exits = []
    if first_anti_ts is not None:
        for row in exits:
            ts = _parse_ts(row.get("timestamp"))
            if ts is not None and ts >= first_anti_ts:
                post_filter_exits.append(row)
    post_pnl = sum((_safe_decimal(row.get("net_pnl_usd") or row.get("realized_pnl_usd")) for row in post_filter_exits), Decimal("0"))
    post_wins = sum(1 for row in post_filter_exits if _safe_decimal(row.get("net_pnl_usd") or row.get("realized_pnl_usd")) > 0)
    post_winrate = Decimal(post_wins) / Decimal(len(post_filter_exits)) * Decimal("100") if post_filter_exits else Decimal("0")
    post_exit_reasons = Counter(str(row.get("exit_reason") or "unknown") for row in post_filter_exits)
    status = "collecting"
    if not signals:
        status = "no_signals_yet"
    elif not anti_signals:
        status = "armed_no_anti_chase_blocks_seen_yet"
    elif len(post_filter_exits) >= 30:
        status = "enough_post_filter_sample"
    return {
        "status": status,
        "signals_seen": len(signals),
        "recent_signals": len(signal_window),
        "paper_opened_lifecycle": len(paper_entries),
        "anti_chase_blocked_total": sum(blocker_counts.values()),
        "anti_chase_blocked_recent": sum(blocker_counts_recent.values()),
        "anti_chase_blockers": dict(blocker_counts.most_common()),
        "anti_chase_blockers_recent": dict(blocker_counts_recent.most_common()),
        "first_anti_chase_block_at": first_anti_ts.isoformat() if first_anti_ts else None,
        "post_filter_exits": len(post_filter_exits),
        "post_filter_net_pnl_usd": _fmt_decimal(post_pnl),
        "post_filter_winrate_pct": _fmt_decimal(post_winrate),
        "post_filter_exit_reasons": dict(post_exit_reasons.most_common()),
        "live_allowed": False,
    }


def format_v76_anti_chase_impact(summary: dict[str, Any]) -> str:
    return (
        "v76 Anti-Chase Impact: "
        f"status={summary['status']}, "
        f"signals={summary['signals_seen']}, recent={summary['recent_signals']}, "
        f"opened={summary['paper_opened_lifecycle']}, "
        f"blocked_total={summary['anti_chase_blocked_total']}, blocked_recent={summary['anti_chase_blocked_recent']}, "
        f"blockers={summary['anti_chase_blockers_recent'] or summary['anti_chase_blockers'] or 'keine'}, "
        f"post_exits={summary['post_filter_exits']}, post_pnl={summary['post_filter_net_pnl_usd']} USDC, "
        f"post_winrate={summary['post_filter_winrate_pct']}%, post_exits_by_reason={summary['post_filter_exit_reasons'] or 'noch keine'}, "
        "live=nein"
    )


def load_market_confluence_latest(runtime_dir: str | Path = "runtime") -> dict[str, Any] | None:
    path = Path(runtime_dir) / "reports" / "market_confluence_latest.json"
    if not path.exists():
        return None
    try:
        loaded = json.loads(path.read_text(encoding="utf-8"))
        return loaded if isinstance(loaded, dict) else None
    except json.JSONDecodeError:
        return None


def format_market_confluence_line(payload: dict[str, Any] | None) -> str:
    if not payload:
        return "Market Confluence Light: noch kein Snapshot vorhanden, live=nein"
    raw_conf = payload.get("confluence")
    conf: dict[str, Any] = raw_conf if isinstance(raw_conf, dict) else {}
    raw_scores = conf.get("scores")
    scores: dict[str, Any] = raw_scores if isinstance(raw_scores, dict) else {}
    top = sorted(scores.items(), key=lambda item: _safe_decimal(item[1].get("final_score") if isinstance(item[1], dict) else 0), reverse=True)[:5]
    top_text = {coin: {"score": row.get("final_score"), "rec": row.get("recommendation")} for coin, row in top if isinstance(row, dict)}
    return (
        "Market Confluence Light: "
        f"regime={conf.get('market_regime', 'unknown')}, eligible={conf.get('eligible_count', 0)}, "
        f"top={top_text or 'keine'}, live=nein"
    )


def summarize_tradingview_signals(runtime_dir: str | Path = "runtime") -> dict[str, Any]:
    runtime = Path(runtime_dir)
    rows = _read_jsonl(runtime / "signals" / "signal_journal.jsonl")
    rejected_rows = _read_jsonl(runtime / "signals" / "rejected_signal_journal.jsonl")
    tv_rows = [row for row in rows if str(row.get("source") or "").lower() == "tradingview"]
    tv_rejected = [row for row in rejected_rows if str(row.get("source") or "").lower() == "tradingview"]
    by_strategy = Counter(str(row.get("strategy_id") or "unknown") for row in tv_rows)
    by_coin = Counter(str(row.get("coin") or "UNKNOWN").upper() for row in tv_rows)
    by_action = Counter(str(row.get("action") or "unknown") for row in tv_rows)
    reject_reasons = Counter(str(row.get("reason") or "unknown") for row in tv_rejected)
    live_order_allowed_count = sum(1 for row in tv_rows if row.get("live_order_allowed") is True)
    live_order_allowed_count += sum(1 for row in tv_rejected if row.get("live_order_allowed") is True)
    paper_signal_count = sum(1 for row in tv_rows if row.get("execution_mode") == "paper_signal")
    return {
        "received": len(tv_rows),
        "rejected": len(tv_rejected),
        "paper_signal": paper_signal_count,
        "live_order_allowed_count": live_order_allowed_count,
        "by_strategy": dict(by_strategy.most_common(5)),
        "by_coin": dict(by_coin.most_common(8)),
        "by_action": dict(by_action.most_common(5)),
        "reject_reasons": dict(reject_reasons.most_common(5)),
    }


def build_tradingview_report_lines(runtime_dir: str | Path = "runtime") -> list[str]:
    summary = summarize_tradingview_signals(runtime_dir)
    bridge = summarize_tradingview_paper_bridge(runtime_dir)
    perf = summarize_strategy_performance(runtime_dir)
    recs = recommend_strategy_actions(perf)
    ops = load_operational_gates(runtime_dir)
    promo = evaluate_promotion_gates(perf, operational_gates=ops["gates"])
    community = summarize_community_ideas(runtime_dir)
    track_record = summarize_track_record(runtime_dir)
    live_count = summary["live_order_allowed_count"] + bridge["live_order_allowed_count"] + community["live_order_allowed_count"]
    live_status = "BLOCKIERT — unerwartetes live_order_allowed Flag gefunden" if live_count else "nein"
    return [
        f"TradingView Signals: empfangen={summary['received']}, abgelehnt={summary['rejected']}, paper_signal={summary['paper_signal']}, live_flags={summary['live_order_allowed_count']}",
        f"TradingView Strategien: {summary['by_strategy'] or 'keine'}; Coins: {summary['by_coin'] or 'keine'}; Actions: {summary['by_action'] or 'keine'}; Rejects: {summary['reject_reasons'] or 'keine'}",
        f"TradingView Paper Bridge: entries={bridge['paper_entries']}, exits={bridge['paper_exits']}, closed_pnl={bridge['closed_net_pnl_usd']} USDC, blocked={bridge['blocked'] or 'keine'}, live_flags={bridge['live_order_allowed_count']}",
        f"Bridge Strategien: {bridge['by_strategy'] or 'keine'}; Coins: {bridge['by_coin'] or 'keine'}",
        f"Strategy Performance: closed={perf['overall']['closed_trades']}, net_pnl={perf['overall']['net_pnl_usd']} USDC, recs={recs or 'keine'}",
        f"TradingView Community Ideas: total={community['total']}, coins={community['by_coin'] or 'keine'}, bias={community['by_bias'] or 'keine'}, mode=research_only, live_flags={community['live_order_allowed_count']}",
        f"Community Track Record: evaluated={track_record['evaluated']}, by_author={track_record['by_author'] or 'noch keine'}, recommendation={track_record['recommendation']}",
        format_operational_gate_report(ops),
        format_promotion_gate_report(promo),
        f"Live-Freigabe aus TradingView: {live_status}",
    ]


def build_report() -> str:
    now = datetime.now(timezone.utc).isoformat()
    reconcile_raw = _load_json_from_reconcile("mainnet")
    rec = assess_reconcile(reconcile_raw)
    strict = _variant_stats(STRICT_ID)
    strict_lifecycle = summarize_v76_lifecycle(STRICT_ID, "runtime")
    strict_lifecycle_scorecard = summarize_v76_lifecycle_scorecard(strict_lifecycle)
    sleeve_scorecard = build_sleeve_scorecard(
        lifecycle_summary=strict_lifecycle,
        lifecycle_scorecard=strict_lifecycle_scorecard,
        runtime_dir="runtime",
    )
    strict_anti_chase_impact = summarize_v76_anti_chase_impact(STRICT_ID, "runtime")
    market_confluence_latest = load_market_confluence_latest("runtime")
    copy_phase7_scorecard = build_phase7_scorecard()
    lifecycle_ops = load_operational_gates("runtime")
    strict_lifecycle_promotion = evaluate_promotion_gates(
        {"overall": {}},
        operational_gates=lifecycle_ops["gates"],
        lifecycle_scorecard=strict_lifecycle_scorecard,
        min_closed_trades=30,
    )
    research = _variant_stats(RESEARCH_ID)
    base = _variant_stats(BASE_ID)
    sup = supervisor_status([STRICT_ID, RESEARCH_ID, BASE_ID])
    scorecard = build_paper_scorecard_report(runtime_dir="runtime", max_bots=10)
    api_quality = "grün" if rec["status"] == "ok" else rec["status"]
    autonomy_safe = rec["status"] == "ok" and not rec["block_new_entries"]
    statistically_mature = Decimal(strict["pnl_total_net"]) > 0 and Decimal(strict["pnl_ex_wld"]) > 0 and strict["trades"] >= 30
    tiny_auto = "nein"
    tiny_reason = "Technik nähert sich an, aber Live-Autonomie bleibt bis Live-Preflight/Alert-Gates und echter LiveRuntime-Safety-Freigabe blockiert."
    lines = [
        "## Hyperliquid Tagesbericht 19:00",
        f"Zeitpunkt: {now}",
        "",
        f"Equity/Free USDC: equity={rec.get('equity')} / free={rec.get('free_usdc')}",
        f"Tages-PnL netto: Paper strict kumuliert {strict['pnl_total_net']} USDC; Live-PnL heute noch nicht aktiv.",
        f"Offene Positionen Mainnet: {rec['positions_count']}; offene Orders: {rec['open_orders_count']}; Stop-Alerts: {rec['alerts'] or 'keine'}",
        f"Trades: strict={strict['trades']}, base={base['trades']}, research_probe={research['trades']}",
        f"Beste/schlechteste Coins strict: {strict['pnl_by_coin']}",
        f"WLD: pnl={strict['wld_pnl']} USDC, pnl_ex_wld={strict['pnl_ex_wld']} USDC, shares={strict['trade_share_by_coin'].get('WLD', 0)}%",
        f"Blockierte Signale strict: {strict['top_block_reasons']}",
        f"Marktregime: {strict['market_regime']}",
        f"API/Data Quality: {api_quality}; block_new_entries={rec['block_new_entries']}",
        format_v76_lifecycle_report(strict_lifecycle),
        format_v76_lifecycle_scorecard(strict_lifecycle_scorecard),
        format_sleeve_scorecard(sleeve_scorecard),
        format_v76_anti_chase_impact(strict_anti_chase_impact),
        format_market_confluence_line(market_confluence_latest),
        format_phase7_scorecard(copy_phase7_scorecard),
        "v76 " + format_promotion_gate_report(strict_lifecycle_promotion),
        *build_tradingview_report_lines("runtime"),
        f"Prozesse: {sup}",
        "Gut funktioniert: v76 strict/base bleiben Paper-only netto positiv und ex-WLD positiv.",
        "Schlecht/Watch: research_probe blockiert weiterhin alles; Live-Autonomie ist technisch noch nicht final freigegeben.",
        "Learnings: Long-only squeeze/reclaim funktioniert im Paper breit über mehrere Coins; WLD ist aktuell kein alleiniger Treiber, bleibt aber sichtbar limitiert.",
        "Weiter beobachten: echte LiveRuntime-Safety, Alerts, Reconcile-Watchdog, Top-Coin-Share, Loss-Streaks, API-Degraded-Phasen.",
        "Vorschlag: morgen unverändert Paper strict + research_probe weiterlaufen lassen; keine Risikoerhöhung.",
        f"Autonomie technisch sicher? {'ja für Paper/Watchdog, noch nein für Live-Auto' if autonomy_safe else 'nein, Reconcile nicht sauber'}.",
        f"Strategie statistisch reif? {'Paper ja; Live-Auto noch nein' if statistically_mature else 'nein'}.",
        f"Tiny Autonomous Live Empfehlung: {tiny_auto} — {tiny_reason}",
        "",
        "Scorecard-Auszug:",
        "```",
        "\n".join(scorecard.splitlines()[-12:]),
        "```",
    ]
    return "\n".join(lines)


def main(argv: list[str] | None = None) -> int:
    parser = argparse.ArgumentParser(description="Build concise daily Hyperliquid trading report.")
    parser.add_argument("--json", action="store_true")
    parser.add_argument("--output", default="runtime/reports/hyperliquid_daily_report_latest.md")
    args = parser.parse_args(argv)
    report = build_report()
    out = Path(args.output)
    out.parent.mkdir(parents=True, exist_ok=True)
    out.write_text(report, encoding="utf-8")
    if args.json:
        print(json.dumps({"status": "ok", "output": str(out), "report": report}, indent=2, sort_keys=True))
    else:
        print(report)
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
