#!/usr/bin/env python3
"""STATE_VECTOR_CONSTRUCTOR_V1 — spec/formulas/domains/portfolio.yaml.

Merges holdings/cash/tax_lots/sector_graph/factor_exposures/macro_regime_probabilities
into one state_vector. Missing components stay null -- never backfilled from another
component. governance/todo/v8_9_p3_adoption_plan.yaml P3-A.
"""
from __future__ import annotations

import argparse
import json
from pathlib import Path

ROOT = Path(__file__).resolve().parents[1]
DEFAULT_CASH_LADDER = ROOT / "Temp" / "cash_ratios_v1.json"
DEFAULT_POSITIONS = ROOT / "Temp" / "account_snapshot_v1.json"
DEFAULT_SECTOR_GRAPH = ROOT / "Temp" / "sector_exposure_graph_v1.json"
DEFAULT_OUT = ROOT / "Temp" / "state_vector_constructor_v1.json"

COMPONENT_KEYS = [
    "cash_ladder",
    "positions",
    "sector_exposure_graph",
    "factor_exposures",
    "tax_lots",
    "risk_bucket_weights",
    "macro_regime_probabilities",
    "goal_progress_pct",
]


def _load(path: Path) -> dict:
    if not path.exists():
        return {}
    try:
        data = json.loads(path.read_text(encoding="utf-8"))
        return data if isinstance(data, dict) else {}
    except Exception:
        return {}


def construct_state_vector(components: dict) -> dict:
    state_vector = {}
    missing_components = []
    for key in COMPONENT_KEYS:
        value = components.get(key)
        state_vector[key] = value
        if value is None:
            missing_components.append(key)
    completeness_pct = 100.0 * (len(COMPONENT_KEYS) - len(missing_components)) / len(COMPONENT_KEYS)
    return {
        "state_vector": state_vector,
        "state_vector_completeness_pct": completeness_pct,
        "missing_components": missing_components,
    }


def main() -> int:
    ap = argparse.ArgumentParser()
    ap.add_argument("--cash-ladder", default=str(DEFAULT_CASH_LADDER))
    ap.add_argument("--positions", default=str(DEFAULT_POSITIONS))
    ap.add_argument("--sector-graph", default=str(DEFAULT_SECTOR_GRAPH))
    ap.add_argument("--out", default=str(DEFAULT_OUT))
    args = ap.parse_args()

    cash_ladder_doc = _load(Path(args.cash_ladder))
    positions_doc = _load(Path(args.positions))
    sector_graph_doc = _load(Path(args.sector_graph))

    components = {
        "cash_ladder": cash_ladder_doc or None,
        "positions": positions_doc.get("positions") if positions_doc else None,
        "sector_exposure_graph": sector_graph_doc.get("rows") if sector_graph_doc.get("rows") else None,
        "factor_exposures": None,
        "tax_lots": positions_doc.get("tax_lots") if positions_doc else None,
        "risk_bucket_weights": None,
        "macro_regime_probabilities": None,
        "goal_progress_pct": positions_doc.get("goal_progress_pct") if positions_doc else None,
    }

    result = {"formula_id": "STATE_VECTOR_CONSTRUCTOR_V1", **construct_state_vector(components)}
    result["source_paths"] = [str(Path(args.cash_ladder)), str(Path(args.positions)), str(Path(args.sector_graph))]

    out = Path(args.out)
    out.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())
