"""Market lifecycle management helpers.

Wraps engine lifecycle methods with Python-level convenience:
expiry registration from Market objects, periodic lifecycle checks
in the run loop, and settlement-aware behavior.
"""

from __future__ import annotations

import logging
import time
from datetime import datetime

logger = logging.getLogger("horizon.lifecycle")


def register_expiry(engine, market_id: str, expiry: str | float | None) -> bool:
    """Register a market's expiry time with the engine.

    Accepts ISO 8601 string, Unix timestamp float, or None (no-op).
    Returns True if successfully registered.
    """
    if expiry is None:
        return False

    ts: float
    if isinstance(expiry, (int, float)):
        ts = float(expiry)
    elif isinstance(expiry, str):
        try:
            dt = datetime.fromisoformat(expiry.replace("Z", "+00:00"))
            ts = dt.timestamp()
        except ValueError:
            logger.warning("Cannot parse expiry '%s' for market %s", expiry, market_id)
            return False
    else:
        return False

    engine.set_market_expiry(market_id, ts)
    return True


def register_market_expiries(engine, markets) -> int:
    """Register expiries for a list of Market objects.

    Reads the `expiry` field from each Market. Returns count registered.
    """
    count = 0
    for m in markets:
        if register_expiry(engine, m.id, m.expiry):
            count += 1
    return count


def check_lifecycle(engine) -> list[str]:
    """Run lifecycle check and return list of market IDs acted upon.

    Wraps engine.check_lifecycle() with logging.
    """
    acted = engine.check_lifecycle()
    for market_id in acted:
        logger.info("Lifecycle action: canceled orders for expiring market %s", market_id)
    return acted


def time_to_expiry(engine, market_id: str) -> float | None:
    """Seconds until market expires. None if no expiry registered."""
    expiries = engine.market_expiries()
    if market_id not in expiries:
        return None
    return max(0.0, expiries[market_id] - time.time())


def approaching_expiry(engine, market_id: str, lead_secs: float = 300.0) -> bool:
    """Check if a market is within lead_secs of expiry."""
    tte = time_to_expiry(engine, market_id)
    if tte is None:
        return False
    return tte <= lead_secs
