from __future__ import annotations

from dataclasses import dataclass
from datetime import datetime, timedelta, timezone
try:
    from zoneinfo import ZoneInfo
except ModuleNotFoundError:  # Python < 3.9
    from backports.zoneinfo import ZoneInfo


@dataclass(frozen=True)
class TimeRange:
    label: str
    start_utc: datetime
    end_utc: datetime


def get_local_now(tz_name: str) -> datetime:
    tz = ZoneInfo(tz_name)
    return datetime.now(tz)


def to_utc(dt: datetime) -> datetime:
    if dt.tzinfo is None:
        dt = dt.replace(tzinfo=timezone.utc)
    return dt.astimezone(timezone.utc)


def range_today(tz_name: str) -> TimeRange:
    now_local = get_local_now(tz_name)
    start_local = now_local.replace(hour=0, minute=0, second=0, microsecond=0)
    return TimeRange("today", to_utc(start_local), to_utc(now_local))


def range_7d(tz_name: str) -> TimeRange:
    now_local = get_local_now(tz_name)
    start_local = now_local - timedelta(days=7)
    return TimeRange("7d", to_utc(start_local), to_utc(now_local))


def range_month(tz_name: str) -> TimeRange:
    now_local = get_local_now(tz_name)
    start_local = now_local.replace(day=1, hour=0, minute=0, second=0, microsecond=0)
    return TimeRange("month", to_utc(start_local), to_utc(now_local))


def range_week(tz_name: str) -> TimeRange:
    now_local = get_local_now(tz_name)
    start_local = (now_local - timedelta(days=now_local.weekday())).replace(
        hour=0, minute=0, second=0, microsecond=0
    )
    return TimeRange("week", to_utc(start_local), to_utc(now_local))


def format_duration(seconds: int) -> str:
    seconds = max(0, int(seconds))
    hours = seconds // 3600
    minutes = (seconds % 3600) // 60
    return f"{hours:02d}:{minutes:02d}"


def format_time_local(dt_utc: datetime, tz_name: str) -> str:
    tz = ZoneInfo(tz_name)
    local = dt_utc.astimezone(tz)
    return local.strftime("%H:%M")


def format_datetime_local(dt_utc: datetime, tz_name: str) -> str:
    tz = ZoneInfo(tz_name)
    local = dt_utc.astimezone(tz)
    return local.strftime("%d.%m.%Y %H:%M")


def local_date(dt_utc: datetime, tz_name: str):
    tz = ZoneInfo(tz_name)
    return dt_utc.astimezone(tz).date()


def get_tz(tz_name: str):
    return ZoneInfo(tz_name)


def day_range_for(date_obj, tz_name: str) -> TimeRange:
    tz = ZoneInfo(tz_name)
    start_local = datetime(date_obj.year, date_obj.month, date_obj.day, tzinfo=tz)
    end_local = start_local + timedelta(days=1)
    return TimeRange("day", to_utc(start_local), to_utc(end_local))
