from __future__ import annotations

from typing import Any

from config import BotConfig
from strategy import PositionState


def _float_or_none(value: Any) -> float | None:
    try:
        if value is None:
            return None
        return float(value)
    except (TypeError, ValueError):
        return None


def recover_position_state(pos: dict[str, Any], *, now_ts: float, cfg: BotConfig, atr: float) -> tuple[PositionState, bool]:
    """Recover in-memory exit state for an already-open paper/live position.

    Returns (state, reconstructed). reconstructed=True means the position lacked
    persisted state metadata, so we use conservative defaults that make the bot
    eligible for time-stop evaluation rather than holding blindly forever.
    """
    entry_price = float(pos.get("entryPrice") or pos.get("entry_px") or 0.0)
    entry_ts = _float_or_none(pos.get("entryTs") or pos.get("entry_ts"))
    high_px = _float_or_none(pos.get("highPrice") or pos.get("high_px"))
    atr_sl_px = _float_or_none(pos.get("atrSlPx") or pos.get("atr_sl_px"))
    reconstructed = entry_ts is None or high_px is None or atr_sl_px is None

    if entry_ts is None:
        entry_ts = float(now_ts) - (float(cfg.dead_fish_time_limit_mins) * 60.0)
    if high_px is None:
        high_px = entry_price
    if atr_sl_px is None:
        atr_sl_px = entry_price - (float(cfg.atr_sl_multiplier) * float(atr))

    state = PositionState(
        entry_ts=float(entry_ts),
        high_px=float(high_px),
        atr_sl_px=float(atr_sl_px),
        be_active=bool(pos.get("beActive") or pos.get("be_active") or False),
        trailing_active=bool(pos.get("trailingActive") or pos.get("trailing_active") or False),
    )
    return state, reconstructed
