from __future__ import annotations

from datetime import datetime, time as dt_time


def dashboard_has_usable_data(dashboard: dict[str, object]) -> bool:
    if not isinstance(dashboard, dict) or dashboard.get("status") == "failed":
        return False
    meta = dashboard.get("meta") or {}
    overview = dashboard.get("overview") or {}
    if isinstance(meta, dict) and (meta.get("trade_date") or meta.get("carried_forward")):
        return True
    return bool(isinstance(overview, dict) and overview)


def verified_dashboard_result(dashboard: dict[str, object]) -> dict[str, object]:
    """Manual refresh and automatic catch-up share this rule.

    Derived limit lists or a previous usable snapshot are not whole-job failures.
    Only a payload with no displayable market data is recorded as failed.
    """
    if dashboard_has_usable_data(dashboard):
        return dashboard
    meta = dashboard.get("meta") if isinstance(dashboard, dict) else None
    notice = ""
    if isinstance(meta, dict):
        notice = str(meta.get("notice") or meta.get("display_notice") or "")
    return {
        "status": "failed",
        "error": notice or "未获取到可用行情",
    }


def official_catchup_due(today: str, snapshot: dict[str, object]) -> bool:
    now = datetime.now().astimezone().time().replace(tzinfo=None)
    if not (dt_time(15, 5) <= now < dt_time(22, 0)):
        return False
    meta = snapshot.get("meta") if isinstance(snapshot.get("meta"), dict) else {}
    actual = str(meta.get("trade_date") or "").replace("-", "")
    if (
        actual == today
        and meta.get("limit_data_source") != "derived"
        and not meta.get("carried_forward")
    ):
        return False
    return True
