from __future__ import annotations

from datetime import datetime
from zoneinfo import ZoneInfo

_MS = ZoneInfo("Europe/Moscow")

# MOEX market hours (MSK)
MARKET_OPEN_HOUR = 10
MARKET_CLOSE_HOUR = 19
MARKET_CLOSE_MINUTE = 50

HOLIDAYS = frozenset([
    # ---- 2023 ----
    datetime(2023, 1, 1), datetime(2023, 1, 2), datetime(2023, 1, 3),
    datetime(2023, 1, 4), datetime(2023, 1, 5), datetime(2023, 1, 6),
    datetime(2023, 1, 7), datetime(2023, 1, 8), datetime(2023, 1, 9),
    datetime(2023, 2, 23), datetime(2023, 2, 24),
    datetime(2023, 3, 8),
    datetime(2023, 5, 1), datetime(2023, 5, 8), datetime(2023, 5, 9),
    datetime(2023, 6, 12),
    datetime(2023, 11, 4), datetime(2023, 11, 6),
    # ---- 2024 ----
    datetime(2024, 1, 1), datetime(2024, 1, 2), datetime(2024, 1, 3),
    datetime(2024, 1, 4), datetime(2024, 1, 5), datetime(2024, 1, 6),
    datetime(2024, 1, 7), datetime(2024, 1, 8),
    datetime(2024, 2, 23),
    datetime(2024, 3, 8),
    datetime(2024, 5, 1), datetime(2024, 5, 9),
    datetime(2024, 6, 12),
    datetime(2024, 11, 4),
    # ---- 2025 ----
    datetime(2025, 1, 1), datetime(2025, 1, 2), datetime(2025, 1, 3),
    datetime(2025, 1, 4), datetime(2025, 1, 5), datetime(2025, 1, 6),
    datetime(2025, 1, 7), datetime(2025, 1, 8),
    datetime(2025, 2, 23), datetime(2025, 2, 24),
    datetime(2025, 3, 8),
    datetime(2025, 5, 1), datetime(2025, 5, 9),
    datetime(2025, 6, 12),
    datetime(2025, 11, 4),
    # ---- 2026 ----
    datetime(2026, 1, 1), datetime(2026, 1, 2), datetime(2026, 1, 3),
    datetime(2026, 1, 4), datetime(2026, 1, 5), datetime(2026, 1, 6),
    datetime(2026, 1, 7), datetime(2026, 1, 8),
    datetime(2026, 2, 23),
    datetime(2026, 3, 8),
    datetime(2026, 5, 1), datetime(2026, 5, 9),
    datetime(2026, 5, 11),
    datetime(2026, 6, 12),
    datetime(2026, 11, 4),
])


def is_in_session_range(dt: datetime) -> bool:
    """Check if datetime falls within Moscow Trading Session."""
    hour = dt.hour
    minute = dt.minute
    if dt.weekday() >= 5:
        return False
    if dt.date() in HOLIDAYS:
        return False
    if hour < MARKET_OPEN_HOUR or hour >= MARKET_CLOSE_HOUR:
        return False
    if hour == MARKET_CLOSE_HOUR - 1 and minute >= MARKET_CLOSE_MINUTE:
        return False
    return True
