"""
core/quiet_hours.py — мёртвые часы (ночные паузы) для аккаунтов прогрева.

До этой фичи прогрев работал 24/7. Реальные люди спят 6-8 часов в сутки —
у Telegram-антифрод есть метрика «message rate per hour», и аккаунт который
шлёт сообщения в 4 утра локального времени (когда живые юзеры спят) — palится.

Что делаем:
- По country-code номера определяем timezone аккаунта.
- В user_settings есть quiet_hours_start / quiet_hours_end (по умолчанию 23 / 7).
- При выборе следующего действия в warmup-loop — если у акка сейчас quiet hours →
  пропускаем его на этом тике / возвращаем большую паузу.

Реализация максимально lightweight — без зависимостей вроде pytz/zoneinfo
для каждой страны, мы используем фиксированный UTC offset по country code.
Точность ±1 час нас устраивает (всё равно границы quiet hours размытые).
"""
from __future__ import annotations

import logging
from datetime import datetime, timezone, timedelta
from typing import Dict, Optional, Tuple

logger = logging.getLogger("telepush.quiet")


# ── Country code → UTC offset (часы) ────────────────────────────────────
# Берём «среднюю» зону страны: где живёт большинство населения.
# Большинство кодов — однозонные. Для США / РФ / Канады берём европейскую/
# восточную часть как наиболее населённую.
PHONE_PREFIX_TO_TZ_OFFSET: Dict[str, float] = {
    # СНГ
    "7":   3.0,    # Россия — Москва (большинство абонентов)
    "375": 3.0,    # Беларусь
    "380": 2.0,    # Украина (зимой 2 / летом 3, берём 2)
    "374": 4.0,    # Армения
    "994": 4.0,    # Азербайджан
    "995": 4.0,    # Грузия
    "996": 6.0,    # Кыргызстан
    "998": 5.0,    # Узбекистан
    "992": 5.0,    # Таджикистан
    "993": 5.0,    # Туркменистан
    "77":  6.0,    # Казахстан
    "370": 2.0,    # Литва
    "371": 2.0,    # Латвия
    "372": 2.0,    # Эстония
    "373": 2.0,    # Молдова
    # Европа
    "44":  0.0,    # UK
    "49":  1.0,    # Германия
    "33":  1.0,    # Франция
    "39":  1.0,    # Италия
    "34":  1.0,    # Испания
    "31":  1.0,    # Нидерланды
    "48":  1.0,    # Польша
    "420": 1.0,    # Чехия
    "421": 1.0,    # Словакия
    "36":  1.0,    # Венгрия
    "40":  2.0,    # Румыния
    "359": 2.0,    # Болгария
    "30":  2.0,    # Греция
    "90":  3.0,    # Турция
    "972": 2.0,    # Израиль
    "351": 0.0,    # Португалия
    "353": 0.0,    # Ирландия
    "46":  1.0,    # Швеция
    "47":  1.0,    # Норвегия
    "45":  1.0,    # Дания
    "358": 2.0,    # Финляндия
    "41":  1.0,    # Швейцария
    "43":  1.0,    # Австрия
    # Америка
    "1":   -5.0,   # США/Канада — Восточное побережье
    "52":  -6.0,   # Мексика
    "55":  -3.0,   # Бразилия
    "54":  -3.0,   # Аргентина
    "56":  -4.0,   # Чили
    # Азия
    "86":  8.0,    # Китай
    "81":  9.0,    # Япония
    "82":  9.0,    # Корея
    "91":  5.5,    # Индия
    "62":  7.0,    # Индонезия
    "60":  8.0,    # Малайзия
    "65":  8.0,    # Сингапур
    "66":  7.0,    # Таиланд
    "84":  7.0,    # Вьетнам
    "63":  8.0,    # Филиппины
    "98":  3.5,    # Иран
    "971": 4.0,    # ОАЭ
    "966": 3.0,    # Саудовская Аравия
    "20":  2.0,    # Египет
    # Африка
    "27":  2.0,    # ЮАР
    "234": 1.0,    # Нигерия
    "254": 3.0,    # Кения
}


def _phone_to_offset(phone: str) -> float:
    """Возвращает UTC offset в часах для номера. По умолчанию 3 (МСК)."""
    if not phone:
        return 3.0
    p = str(phone).lstrip("+").strip()
    if not p:
        return 3.0
    # Подбираем самый длинный matching prefix
    for length in (4, 3, 2, 1):
        if len(p) >= length:
            prefix = p[:length]
            if prefix in PHONE_PREFIX_TO_TZ_OFFSET:
                return PHONE_PREFIX_TO_TZ_OFFSET[prefix]
    return 3.0


def local_hour_for_phone(phone: str) -> int:
    """Текущий час локального времени аккаунта (0-23)."""
    offset = _phone_to_offset(phone)
    now_utc = datetime.now(timezone.utc)
    local = now_utc + timedelta(hours=offset)
    return local.hour


def is_quiet_hours(phone: str, start_h: int = 23, end_h: int = 7) -> bool:
    """True если у аккаунта сейчас quiet hours.

    start_h / end_h — границы (включая start, исключая end).
    23..7 = тихо с 23:00 до 06:59 включительно (typical sleep).
    Если start > end — диапазон пересекает полночь.
    """
    try:
        h = local_hour_for_phone(phone)
        start_h = int(start_h) % 24
        end_h = int(end_h) % 24
        if start_h == end_h:
            return False  # нулевая зона
        if start_h < end_h:
            return start_h <= h < end_h
        # Пересекает полночь
        return h >= start_h or h < end_h
    except Exception as e:
        logger.debug("[quiet] %s: %s", phone, e)
        return False


def seconds_until_end_of_quiet(phone: str, start_h: int = 23, end_h: int = 7) -> int:
    """Сколько секунд осталось до конца quiet hours. Если сейчас НЕ в quiet — 0."""
    if not is_quiet_hours(phone, start_h, end_h):
        return 0
    offset = _phone_to_offset(phone)
    now_utc = datetime.now(timezone.utc)
    local = now_utc + timedelta(hours=offset)
    # Локальное время выхода из quiet — end_h:00 (следующее)
    target = local.replace(hour=int(end_h) % 24, minute=0, second=0, microsecond=0)
    if target <= local:
        target += timedelta(days=1)
    delta = target - local
    return int(delta.total_seconds())
