from __future__ import annotations

import json
from pathlib import Path
from typing import Any

import config_manager


def _normalize_direction(value: Any) -> str:
    text = str(value or "NEUTRAL").strip().upper()
    aliases = {
        "BUY": "LONG",
        "BULL": "LONG",
        "LONG": "LONG",
        "SELL": "SHORT",
        "BEAR": "SHORT",
        "SHORT": "SHORT",
        "NONE": "NEUTRAL",
        "FLAT": "NEUTRAL",
        "NEUTRAL": "NEUTRAL",
    }
    return aliases.get(text, "NEUTRAL")


def _safe_float(value: Any, default: float) -> float:
    try:
        return float(value)
    except (TypeError, ValueError):
        return default


def resolve_macro_authority(
    direction: Any,
    *,
    state: str = "UNKNOWN",
    degraded: bool = False,
    bias_weight: float = 0.0,
    disempowered: bool = False,
) -> str:
    normalized_direction = _normalize_direction(direction)
    normalized_state = str(state or "UNKNOWN").strip().upper()
    effective_bias = max(0.0, min(1.0, _safe_float(bias_weight, 0.0)))
    if disempowered or normalized_direction == "NEUTRAL":
        return "DISABLED"
    if degraded or normalized_state in {"DEGRADED", "STALE", "ERROR", "UNKNOWN"}:
        return "SOFT_BIAS"
    if effective_bias >= 0.55:
        return "HARD_BIND"
    return "SOFT_BIAS"


def resolve_allowed_side(binding_direction: Any, macro_authority: Any) -> str:
    authority = str(macro_authority or "DISABLED").strip().upper()
    direction = _normalize_direction(binding_direction)
    if authority != "HARD_BIND":
        return "BOTH"
    if direction == "LONG":
        return "BUY"
    if direction == "SHORT":
        return "SELL"
    return "BOTH"


def build_macro_direction_snapshot(
    macro_payload: dict[str, Any] | None,
    policy: dict[str, Any] | None,
) -> dict[str, Any]:
    payload = macro_payload if isinstance(macro_payload, dict) else {}
    macro_policy = policy if isinstance(policy, dict) else {}

    raw_direction = payload.get(
        "direction",
        payload.get("binding_direction", payload.get("effective_direction", "NEUTRAL")),
    )
    direction = _normalize_direction(raw_direction)

    state = str(payload.get("state", payload.get("macro_state", "UNKNOWN")) or "UNKNOWN").upper()
    degraded = bool(payload.get("degraded", False))
    bias_weight = max(
        0.0,
        min(
            1.0,
            _safe_float(
                payload.get(
                    "bias_weight",
                    payload.get("confidence", macro_policy.get("default_bias_weight", 0.0)),
                ),
                0.0,
            ),
        ),
    )
    direction_guard = payload.get("direction_guard", {})
    if not isinstance(direction_guard, dict):
        direction_guard = {}
    disempowered = bool(payload.get("direction_disempowered", False))
    if str(direction_guard.get("state", "inactive") or "inactive").lower() == "hard_penalty":
        disempowered = True

    authority = resolve_macro_authority(
        direction,
        state=state,
        degraded=degraded,
        bias_weight=bias_weight,
        disempowered=disempowered,
    )

    effective_direction = _normalize_direction(
        payload.get("effective_direction", direction if authority != "DISABLED" else "NEUTRAL")
    )
    if authority == "DISABLED":
        effective_direction = "NEUTRAL"

    binding_direction = _normalize_direction(payload.get("binding_direction", effective_direction))
    if authority != "HARD_BIND":
        binding_direction = "NEUTRAL"

    return {
        "direction": direction,
        "effective_direction": effective_direction,
        "binding_direction": binding_direction,
        "macro_authority": authority,
        "allowed_side": resolve_allowed_side(binding_direction, authority),
        "state": state,
        "degraded": degraded,
        "bias_weight": round(bias_weight, 4),
        "direction_guard": direction_guard,
        "direction_disempowered": disempowered,
    }


def load_decision_snapshot() -> dict[str, Any]:
    """Load the latest macro direction decision snapshot from disk."""
    p = config_manager.get_data_dir() / "bridge" / "state" / "agent_state.json"
    if not p.exists():
        return build_macro_direction_snapshot(None, None)
    try:
        data = json.loads(p.read_text(encoding="utf-8"))
        if not isinstance(data, dict):
            return build_macro_direction_snapshot(None, None)
        direction_data = data.get("agent_direction")
        if isinstance(direction_data, dict):
            return build_macro_direction_snapshot(direction_data, data.get("policy"))
        return build_macro_direction_snapshot(data, None)
    except Exception:
        return build_macro_direction_snapshot(None, None)
