from __future__ import annotations

import argparse
import hashlib
import json
from pathlib import Path
from typing import Any


ROOT = Path(__file__).resolve().parents[1]
DEFAULT_SOURCE = ROOT / "Temp" / "strategy_decision_result_v3.json"
DEFAULT_REPORT = ROOT / "Temp" / "operational_report.json"
DEFAULT_OUT = ROOT / "Temp" / "truthful_decision_ledger_v2.json"


def _load_json(path: Path) -> dict[str, Any]:
    if not path.exists():
        return {}
    try:
        payload = json.loads(path.read_text(encoding="utf-8"))
    except Exception:
        return {}
    return payload if isinstance(payload, dict) else {}


def _as_rows(value: Any) -> list[dict[str, Any]]:
    if isinstance(value, list):
        return [row for row in value if isinstance(row, dict)]
    return []


def _canonical(obj: Any) -> str:
    return json.dumps(obj, ensure_ascii=False, sort_keys=True, separators=(",", ":"))


def _sha256_text(text: str) -> str:
    return hashlib.sha256(text.encode("utf-8")).hexdigest()


def _row_hash(row: dict[str, Any]) -> str:
    payload = dict(row)
    payload.pop("output_hash", None)
    return _sha256_text(_canonical(payload))


def _source_fields(row: dict[str, Any]) -> list[str]:
    keys = [
        "account",
        "ticker",
        "name",
        "current_holding_quantity",
        "average_cost_krw",
        "current_price_krw",
        "order_type",
        "mode",
        "limit_price_krw",
        "quantity",
        "stop_price_krw",
        "take_profit_price_krw",
        "validation_status",
        "rationale_code",
        "spsv2_verdict",
        "blocked_by_gate",
        "lock_applied",
    ]
    return [key for key in keys if row.get(key) not in (None, "", [])]


def _reason_codes(row: dict[str, Any]) -> list[str]:
    reasons: list[str] = []
    for key in ("rationale_code", "blocked_by_gate", "lock_applied", "export_gate"):
        value = row.get(key)
        if isinstance(value, str) and value.strip():
            reasons.extend([part.strip() for part in value.split("|") if part.strip()])
    if not reasons:
        reasons.append("NO_REASON_CODE")
    return reasons


def _gate_stack(row: dict[str, Any], export_gate: str) -> list[str]:
    stack = [f"EXPORT_GATE={export_gate}"]
    if row.get("validation_status"):
        stack.append(f"VALIDATION={row.get('validation_status')}")
    if row.get("spsv2_verdict"):
        stack.append(f"SPSV2={row.get('spsv2_verdict')}")
    if row.get("blocked_by_gate"):
        stack.append(f"BLOCKED_BY={row.get('blocked_by_gate')}")
    if row.get("lock_applied"):
        stack.append(f"LOCK={row.get('lock_applied')}")
    return stack


def main() -> int:
    ap = argparse.ArgumentParser(description="Build truthful decision ledger v2.")
    ap.add_argument("--source", default=str(DEFAULT_SOURCE))
    ap.add_argument("--report", default=str(DEFAULT_REPORT))
    ap.add_argument("--out", default=str(DEFAULT_OUT))
    args = ap.parse_args()

    source_path = Path(args.source)
    report_path = Path(args.report)
    out_path = Path(args.out)
    if not source_path.is_absolute():
        source_path = ROOT / source_path
    if not report_path.is_absolute():
        report_path = ROOT / report_path
    if not out_path.is_absolute():
        out_path = ROOT / out_path

    source = _load_json(source_path)
    report = _load_json(report_path)
    orders = _as_rows(source.get("order_blueprint"))
    shadow = _as_rows(source.get("shadow_ledger"))
    export_gate = str((source.get("global_gates") or {}).get("export_gate") or "UNKNOWN")
    route = source.get("route") if isinstance(source.get("route"), dict) else {}
    route_id = str(route.get("route_id") or "UNKNOWN_ROUTE")

    input_hash = _sha256_text(_canonical(source))
    report_hash = _sha256_text(_canonical(report)) if report else None

    ledger_rows: list[dict[str, Any]] = []
    for idx, row in enumerate(orders):
        decision_id = f"{route_id}:{idx:03d}:{str(row.get('ticker') or 'NA')}"
        base_row = {
            "decision_id": decision_id,
            "proposal_id": f"{str(row.get('ticker') or 'NA')}:{idx:03d}",
            "ticker": row.get("ticker"),
            "action": row.get("order_type"),
            "state": row.get("validation_status"),
            "formula_id": "TRUTHFUL_DECISION_LEDGER_V2",
            "input_hash": input_hash,
            "source_snapshot_hash": input_hash,
            "price_basis": "HARNESS_ONLY",
            "qty_basis": "ORDER_BLUEPRINT",
            "source_fields": _source_fields(row),
            "reason_codes": _reason_codes(row),
            "gate_stack": _gate_stack(row, export_gate),
            "export_gate": export_gate,
            "renderer_section": "concise_hts_input_sheet" if str(row.get("validation_status") or "").upper() == "PASS" else "reference_price_ledger",
            "llm_numeric_generated_flag": False,
            "outcome_binding_id": f"{route_id}:{str(row.get('ticker') or 'NA')}:{str(row.get('validation_status') or 'UNKNOWN')}",
            "record_type": "order_blueprint",
        }
        if report_hash is not None:
            base_row["report_hash"] = report_hash
        base_row["output_hash"] = _row_hash(base_row)
        ledger_rows.append(base_row)

    for idx, row in enumerate(shadow):
        decision_id = f"{route_id}:shadow:{idx:03d}:{str(row.get('ticker') or 'NA')}"
        base_row = {
            "decision_id": decision_id,
            "proposal_id": f"SHADOW:{str(row.get('ticker') or 'NA')}:{idx:03d}",
            "ticker": row.get("ticker"),
            "action": row.get("order_type"),
            "state": row.get("validation_status"),
            "formula_id": "TRUTHFUL_DECISION_LEDGER_V2",
            "input_hash": input_hash,
            "source_snapshot_hash": input_hash,
            "price_basis": "HARNESS_ONLY",
            "qty_basis": "ORDER_BLUEPRINT",
            "source_fields": _source_fields(row),
            "reason_codes": _reason_codes(row),
            "gate_stack": _gate_stack(row, export_gate),
            "export_gate": export_gate,
            "renderer_section": "reference_price_ledger",
            "llm_numeric_generated_flag": False,
            "outcome_binding_id": f"{route_id}:{str(row.get('ticker') or 'NA')}:{str(row.get('validation_status') or 'UNKNOWN')}",
            "record_type": "shadow_ledger",
        }
        if report_hash is not None:
            base_row["report_hash"] = report_hash
        base_row["output_hash"] = _row_hash(base_row)
        ledger_rows.append(base_row)

    result = {
        "formula_id": "TRUTHFUL_DECISION_LEDGER_V2",
        "schema_version": "truthful-decision-ledger-v2",
        "as_of": source.get("as_of") or source.get("analysis_date") or "",
        "input_hash": input_hash,
        "report_hash": report_hash,
        "route_id": route_id,
        "price_basis": "HARNESS_ONLY",
        "qty_basis": "ORDER_BLUEPRINT",
        "llm_numeric_generated_flag": False,
        "ledger_rows": ledger_rows,
        "ledger_count": len(ledger_rows),
        "targets": {
            "llm_numeric_generated_flag": False,
            "source_fields_required": True,
            "output_hash_required": True,
            "report_hash_required": bool(report_hash is not None),
        },
    }

    out_path.parent.mkdir(parents=True, exist_ok=True)
    out_path.write_text(json.dumps(result, ensure_ascii=False, indent=2), encoding="utf-8")
    print(json.dumps(result, ensure_ascii=False, indent=2))
    return 0


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