"""PollState — process-wide singleton."""
from collections import deque
from dataclasses import dataclass, field
from datetime import datetime


@dataclass
class PollState:
    portfolio: dict | None = None
    news_sentiment: dict | None = None
    screener_preview: dict | None = None
    minute_bars: dict[str, deque] = field(default_factory=dict)
    asking_price: dict[str, dict] = field(default_factory=dict)
    # Phase 3b additions
    daily_ohlcv: dict[str, list[dict]] = field(default_factory=dict)
    chronos_predictions: dict[str, dict] = field(default_factory=dict)
    minute_momentum: dict[str, str] = field(default_factory=dict)
    signals: dict[str, dict] = field(default_factory=dict)
    # F5 lifecycle
    signal_cycle_id: int = 0
    last_updated: dict[str, str] = field(default_factory=dict)
    fetch_errors: dict[str, int] = field(default_factory=dict)

    def get_active_signals(self, now: datetime) -> list[dict]:
        """expires_at > now 인 신호만 반환. expires_at 없거나 파싱 실패는 expired 취급."""
        active: list[dict] = []
        for sig in self.signals.values():
            expires_at = sig.get("expires_at")
            if not expires_at:
                continue
            try:
                exp_dt = datetime.fromisoformat(expires_at)
            except ValueError:
                continue
            if exp_dt > now:
                active.append(sig)
        return active

    def purge_expired_signals(self, now: datetime) -> int:
        """만료된 signal 제거. expires_at 없거나 파싱 실패도 제거. 제거 개수 반환."""
        to_drop = []
        for ticker, sig in self.signals.items():
            expires_at = sig.get("expires_at")
            if not expires_at:
                to_drop.append(ticker)
                continue
            try:
                exp_dt = datetime.fromisoformat(expires_at)
            except ValueError:
                to_drop.append(ticker)
                continue
            if exp_dt <= now:
                to_drop.append(ticker)
        for t in to_drop:
            del self.signals[t]
        return len(to_drop)


state = PollState()
