#!/usr/bin/env python3
from __future__ import annotations

import argparse
import json
import yaml
from pathlib import Path

ROOT = Path(__file__).resolve().parents[1]

def main() -> int:
    ap = argparse.ArgumentParser()
    ap.add_argument("--manifest", default="runtime/active_artifact_manifest.yaml")
    ap.add_argument("--packet", default="Temp/final_decision_packet_active.json")
    ap.add_argument("--out", default="Temp/final_context_for_llm_v5.yaml")
    args = ap.parse_args()

    manifest_path = ROOT / args.manifest
    packet_path = ROOT / args.packet
    out_path = ROOT / args.out

    if not manifest_path.exists():
        print(f"Manifest not found: {manifest_path}")
        return 1
    if not packet_path.exists():
        print(f"Packet not found: {packet_path}")
        return 1

    manifest = yaml.safe_load(manifest_path.read_text(encoding="utf-8"))
    packet = json.loads(packet_path.read_text(encoding="utf-8"))

    # Also load GatherTradingData.json to get harness context fields!
    trading_data_path = ROOT / "GatherTradingData.json"
    trading_data = {}
    if trading_data_path.exists():
        try:
            trading_data = json.loads(trading_data_path.read_text(encoding="utf-8"))
        except Exception:
            pass
    
    # Extract _harness_context from GatherTradingData.json
    harness_context = trading_data.get("data", {}).get("_harness_context", {})

    # Extract info from manifest
    manifest_info = {
        "generated_at": manifest.get("generated_at"),
        "active_count_per_formula": manifest.get("active_count_per_formula"),
        "report_active_artifact_match_pct": manifest.get("report_active_artifact_match_pct"),
    }

    # Extract canonical metrics
    metrics = packet.get("canonical_metrics", {})
    total_asset = metrics.get("total_asset_krw", {}).get("value")
    cash_shortfall = metrics.get("cash_shortfall_min_krw", {}).get("value")
    cash_recovered = metrics.get("cash_recovered_krw", {}).get("value") or metrics.get("cash_recovered", {}).get("value")
    gate = metrics.get("final_execution_gate", {}).get("value") or packet.get("routing_serving", {}).get("global_execution_gate", {}).get("value")
    hts_order_count = metrics.get("hts_order_count", {}).get("value")

    # Build blockers
    blockers = []
    if gate != "PASS":
        blockers.append({
            "gate": gate,
            "reason": "final_execution_gate is not PASS (AUDIT_ONLY / BLOCK_EXECUTION)"
        })

    action_table = []
    # Add per ticker decisions
    for item in packet.get("per_ticker_final_judgment", []):
        action_table.append({
            "ticker": item.get("ticker"),
            "verdict": item.get("verdict"),
            "effective_confidence": item.get("effective_confidence"),
            "horizon": item.get("horizon")
        })

    order_blueprints = []
    if "order_blueprint" in packet and isinstance(packet["order_blueprint"], dict):
        order_blueprints = packet["order_blueprint"].get("rows", [])

    shadow_ledger_info = {
        "cash_raise_plan": packet.get("cash_raise_plan", {}),
        "total_asset_krw": total_asset,
        "cash_shortfall_min_krw": cash_shortfall,
        "cash_recovered_krw": cash_recovered,
        "hts_order_count": hts_order_count,
        "order_blueprints": order_blueprints
    }

    data_missing_info = []
    data_quality = packet.get("data_quality", {})
    if data_quality.get("missing_critical_field_count", {}).get("value", 0) > 0:
        data_missing_info.append(f"Missing {data_quality.get('missing_critical_field_count', {}).get('value')} critical fields")

    dq_gate_raw = harness_context.get("data_quality_gate_v2_json")
    if dq_gate_raw:
        if isinstance(dq_gate_raw, str):
            try:
                dq_gate_raw = json.loads(dq_gate_raw)
            except Exception:
                pass
        if isinstance(dq_gate_raw, dict):
            for warn in dq_gate_raw.get("special_warnings", []):
                data_missing_info.append(warn)

    education_notes = [
        "LLM must copy and render already calculated values only.",
        "Do NOT perform any mathematical calculations.",
        "Strictly forbidden to modify target execution actions or sizing.",
    ]

    # Map the 11 contract-required sections:
    
    # 01_metadata_and_manifest_alias
    metadata_kst = manifest.get("generated_at", "")
    if metadata_kst.endswith("Z"):
        metadata_kst = metadata_kst.replace("Z", "+00:00")
    try:
        dt = datetime.fromisoformat(metadata_kst)
        kst = timezone(timedelta(hours=9))
        dt_kst = dt.astimezone(kst)
        generated_at_kst = dt_kst.isoformat()
    except Exception:
        generated_at_kst = metadata_kst

    active_aliases = manifest.get("active_aliases", {})
    active_alias = list(active_aliases.keys())[0] if active_aliases else "final_decision_packet_active"

    sec01 = {
        "document_id": "FINAL_CONTEXT_FOR_LLM_V5",
        "generated_at_kst": generated_at_kst,
        "active_artifact_alias": active_alias
    }

    # 02_portfolio_health
    cash_ratio = harness_context.get("cash_current_pct_d2") or harness_context.get("settlement_cash_pct") or 0.0
    if not cash_ratio and total_asset:
        buy_power = harness_context.get("buy_power_krw") or harness_context.get("settlement_cash_d2_krw") or 0.0
        cash_ratio = round(buy_power / total_asset * 100, 2)
    
    achievement_pct = harness_context.get("goal_achievement_pct") or 0.0
    if not achievement_pct and total_asset:
        achievement_pct = round(total_asset / 500_000_000 * 100, 2)

    sec02 = {
        "total_asset_krw": total_asset or 0,
        "cash_ratio_pct": float(cash_ratio),
        "goal_achievement_pct": float(achievement_pct)
    }

    # 03_hard_blockers
    blocked_tickers = []
    blocker_reasons = []
    for blocker in blockers:
        blocker_reasons.append(blocker.get("reason"))
    for item in packet.get("per_ticker_final_judgment", []):
        if item.get("verdict") in ("BLOCK", "BLOCK_BUY"):
            blocked_tickers.append(item.get("ticker"))
            blocker_reasons.append(f"{item.get('ticker')} verdict is {item.get('verdict')}")

    sec03 = {
        "blocked_tickers": blocked_tickers,
        "blocker_reasons": blocker_reasons
    }

    # 04_sell_priority_table
    sell_priority_rows = []
    raw_sell_priority = trading_data.get("data", {}).get("sell_priority", []) or []
    for row in raw_sell_priority:
        sell_priority_rows.append({
            "rank": row.get("Rank"),
            "ticker": row.get("Ticker"),
            "sell_action": row.get("Sell_Action"),
            "sell_reason_code": row.get("Action_Reason") or "STOP_OR_TIME_EXIT"
        })
    sec04 = sell_priority_rows

    # 05_buy_hold_sell_action_table
    buy_hold_sell_rows = []
    decisions_raw = harness_context.get("decisions_json") or []
    if isinstance(decisions_raw, str):
        try:
            decisions_raw = json.loads(decisions_raw)
        except Exception:
            decisions_raw = []
            
    prices_raw = harness_context.get("prices_json") or []
    if isinstance(prices_raw, str):
        try:
            prices_raw = json.loads(prices_raw)
        except Exception:
            prices_raw = []
            
    prices_by_ticker = {p.get("ticker"): p for p in prices_raw if p.get("ticker")}
    
    sell_qtys_raw = harness_context.get("sell_quantities_json") or []
    if isinstance(sell_qtys_raw, str):
        try:
            sell_qtys_raw = json.loads(sell_qtys_raw)
        except Exception:
            sell_qtys_raw = []
    sell_qtys_by_ticker = {q.get("ticker"): q.get("sell_qty") for q in sell_qtys_raw if q.get("ticker")}

    account_snap = trading_data.get("data", {}).get("account_snapshot", []) or []
    acct_by_ticker = {a.get("ticker"): a for a in account_snap if a.get("ticker")}

    for d in decisions_raw:
        ticker = d.get("ticker")
        action = d.get("final_action")
        p_info = prices_by_ticker.get(ticker, {})
        a_info = acct_by_ticker.get(ticker, {})
        
        entry_price = p_info.get("avg_cost") or a_info.get("average_cost") or 0
        stop_price = p_info.get("stop_price") or a_info.get("stop_price") or 0
        qty = sell_qtys_by_ticker.get(ticker) or a_info.get("holding_quantity") or 0
        
        buy_hold_sell_rows.append({
            "ticker": ticker,
            "final_action": action,
            "entry_price": entry_price,
            "stop_price": stop_price,
            "quantity": qty
        })
    sec05 = buy_hold_sell_rows

    # 06_cash_and_risk_budget
    available_cash = harness_context.get("buy_power_krw") or harness_context.get("settlement_cash_d2_krw") or 0
    d2_cash = harness_context.get("settlement_cash_d2_krw") or available_cash
    
    sec06 = {
        "available_cash_krw": available_cash,
        "d2_cash_krw": d2_cash,
        "max_allowed_mdd_pct": 20.0
    }

    # 07_shadow_ledger_visible_items
    sec07 = []
    shadow_ledger_path = ROOT / "Temp" / "shadow_ledger_v2.json"
    if shadow_ledger_path.exists():
        try:
            sl_data = json.loads(shadow_ledger_path.read_text(encoding="utf-8"))
            for f in sl_data.get("shadow_formulas", []):
                sec07.append({
                    "formula_id": f.get("formula_id"),
                    "lifecycle_state": f.get("lifecycle_state"),
                    "sample_n": f.get("sample_n"),
                    "promotion_allowed": f.get("promotion_allowed")
                })
        except Exception:
            pass

    # 08_data_missing_items
    sec08 = []
    if data_missing_info:
        for idx, warn in enumerate(data_missing_info):
            sec08.append({
                "missing_field": f"warning_{idx}",
                "reason": warn
            })
    else:
        sec08.append({
            "missing_field": "None",
            "reason": "No missing critical fields detected."
        })

    # 09_market_regime_summary_precomputed
    regime_label = harness_context.get("market_regime_state") or "NEUTRAL"
    regime_score = harness_context.get("mrs_score") or 0
    pos_scale = harness_context.get("regime_size_scale") or 1.0
    
    sec09 = {
        "regime_label": regime_label,
        "regime_score": regime_score,
        "position_scale_factor": pos_scale
    }

    # 10_education_notes_preapproved
    sec10 = education_notes

    # 11_forbidden_phrases_and_no_math_rules
    sec11 = {
        "forbidden_phrases": [
            "최종 수량 결정",
            "손절가 구하기",
            "익절가 구하기",
            "LLM에 의한 임의 수치 생성"
        ],
        "no_math_rule": "LLM must copy-only pre-calculated values. Arithmetic calculations are strictly prohibited."
    }

    context = {
        "formula_id": "FINAL_CONTEXT_FOR_LLM_V5",
        "executive": {
            "display_value": "FINAL_CONTEXT_FOR_LLM_V5",
            "source_key": "meta.builder_version",
            "manifest": manifest_info
        },
        "blockers": blockers,
        "action_table": action_table,
        "shadow_ledger": shadow_ledger_info,
        "data_missing": data_missing_info,
        "education_notes": education_notes,
        "llm_forbidden_numeric_fields": [
            "price",
            "quantity",
            "stop_price",
            "take_profit_price",
            "score",
            "gate"
        ],
        "instruction_source": "This file is the single read path source of truth for the LLM. Do not read other directories.",
        
        # 11 contract-required sections
        "01_metadata_and_manifest_alias": sec01,
        "02_portfolio_health": sec02,
        "03_hard_blockers": sec03,
        "04_sell_priority_table": sec04,
        "05_buy_hold_sell_action_table": sec05,
        "06_cash_and_risk_budget": sec06,
        "07_shadow_ledger_visible_items": sec07,
        "08_data_missing_items": sec08,
        "09_market_regime_summary_precomputed": sec09,
        "10_education_notes_preapproved": sec10,
        "11_forbidden_phrases_and_no_math_rules": sec11
    }

    out_path.parent.mkdir(parents=True, exist_ok=True)
    out_path.write_text(yaml.safe_dump(context, sort_keys=False, allow_unicode=True), encoding="utf-8")

    print(json.dumps({
        "formula_id": context["formula_id"],
        "section_count": len(context),
        "gate": "PASS"
    }, ensure_ascii=True))
    return 0

if __name__ == "__main__":
    import sys
    sys.exit(main())
