import datetime
import enum
import sys
from _typeshed import Unused
from collections.abc import Iterable, Iterator
from time import struct_time
from typing import ClassVar, Final, TypeAlias, overload

__all__ = [
    "FRIDAY",
    "MONDAY",
    "SATURDAY",
    "SUNDAY",
    "THURSDAY",
    "TUESDAY",
    "WEDNESDAY",
    "IllegalMonthError",
    "IllegalWeekdayError",
    "setfirstweekday",
    "firstweekday",
    "isleap",
    "leapdays",
    "weekday",
    "monthrange",
    "monthcalendar",
    "prmonth",
    "month",
    "prcal",
    "calendar",
    "timegm",
    "month_name",
    "month_abbr",
    "day_name",
    "day_abbr",
    "Calendar",
    "TextCalendar",
    "HTMLCalendar",
    "LocaleTextCalendar",
    "LocaleHTMLCalendar",
    "weekheader",
]

if sys.version_info >= (3, 12):
    __all__ += [
        "Day",
        "Month",
        "JANUARY",
        "FEBRUARY",
        "MARCH",
        "APRIL",
        "MAY",
        "JUNE",
        "JULY",
        "AUGUST",
        "SEPTEMBER",
        "OCTOBER",
        "NOVEMBER",
        "DECEMBER",
    ]
if sys.version_info >= (3, 15):
    __all__ += ["standalone_month_name", "standalone_month_abbr"]

_LocaleType: TypeAlias = tuple[str | None, str | None]

class IllegalMonthError(ValueError, IndexError):
    month: int
    def __init__(self, month: int) -> None: ...

class IllegalWeekdayError(ValueError):
    weekday: int
    def __init__(self, weekday: int) -> None: ...

def isleap(year: int) -> bool: ...
def leapdays(y1: int, y2: int) -> int: ...
def weekday(year: int, month: int, day: int) -> int: ...
def monthrange(year: int, month: int) -> tuple[int, int]: ...

class Calendar:
    firstweekday: int
    def __init__(self, firstweekday: int = 0) -> None: ...
    def getfirstweekday(self) -> int: ...
    def setfirstweekday(self, firstweekday: int) -> None: ...
    def iterweekdays(self) -> Iterator[int]: ...
    def itermonthdates(self, year: int, month: int) -> Iterator[datetime.date]: ...
    def itermonthdays2(self, year: int, month: int) -> Iterator[tuple[int, int]]: ...
    def itermonthdays(self, year: int, month: int) -> Iterator[int]: ...
    def monthdatescalendar(self, year: int, month: int) -> list[list[datetime.date]]: ...
    def monthdays2calendar(self, year: int, month: int) -> list[list[tuple[int, int]]]: ...
    def monthdayscalendar(self, year: int, month: int) -> list[list[int]]: ...
    def yeardatescalendar(self, year: int, width: int = 3) -> list[list[list[list[datetime.date]]]]: ...
    def yeardays2calendar(self, year: int, width: int = 3) -> list[list[list[list[tuple[int, int]]]]]: ...
    def yeardayscalendar(self, year: int, width: int = 3) -> list[list[list[list[int]]]]: ...
    def itermonthdays3(self, year: int, month: int) -> Iterator[tuple[int, int, int]]: ...
    def itermonthdays4(self, year: int, month: int) -> Iterator[tuple[int, int, int, int]]: ...

class TextCalendar(Calendar):
    def prweek(self, theweek: Iterable[tuple[int, int]], width: int) -> None: ...
    def formatday(self, day: int, weekday: int, width: int) -> str: ...
    def formatweek(self, theweek: Iterable[tuple[int, int]], width: int) -> str: ...
    def formatweekday(self, day: int, width: int) -> str: ...
    def formatweekheader(self, width: int) -> str: ...
    def formatmonthname(self, theyear: int, themonth: int, width: int, withyear: bool = True) -> str: ...
    def prmonth(self, theyear: int, themonth: int, w: int = 0, l: int = 0) -> None: ...
    def formatmonth(self, theyear: int, themonth: int, w: int = 0, l: int = 0) -> str: ...
    def formatyear(self, theyear: int, w: int = 2, l: int = 1, c: int = 6, m: int = 3) -> str: ...
    def pryear(self, theyear: int, w: int = 0, l: int = 0, c: int = 6, m: int = 3) -> None: ...

def firstweekday() -> int: ...
def monthcalendar(year: int, month: int) -> list[list[int]]: ...
def prweek(theweek: int, width: int) -> None: ...
def week(theweek: int, width: int) -> str: ...
def weekheader(width: int) -> str: ...
def prmonth(theyear: int, themonth: int, w: int = 0, l: int = 0) -> None: ...
def month(theyear: int, themonth: int, w: int = 0, l: int = 0) -> str: ...
def calendar(theyear: int, w: int = 2, l: int = 1, c: int = 6, m: int = 3) -> str: ...
def prcal(theyear: int, w: int = 0, l: int = 0, c: int = 6, m: int = 3) -> None: ...

class HTMLCalendar(Calendar):
    cssclasses: ClassVar[list[str]]
    cssclass_noday: ClassVar[str]
    cssclasses_weekday_head: ClassVar[list[str]]
    cssclass_month_head: ClassVar[str]
    cssclass_month: ClassVar[str]
    cssclass_year: ClassVar[str]
    cssclass_year_head: ClassVar[str]
    def formatday(self, day: int, weekday: int) -> str: ...
    def formatweek(self, theweek: int) -> str: ...
    def formatweekday(self, day: int) -> str: ...
    def formatweekheader(self) -> str: ...
    def formatmonthname(self, theyear: int, themonth: int, withyear: bool = True) -> str: ...
    def formatmonth(self, theyear: int, themonth: int, withyear: bool = True) -> str: ...
    if sys.version_info >= (3, 15):
        def formatmonthpage(
            self, theyear: int, themonth: int, width: int = 3, css: str | None = "calendar.css", encoding: str | None = None
        ) -> bytes: ...

    def formatyear(self, theyear: int, width: int = 3) -> str: ...
    def formatyearpage(
        self, theyear: int, width: int = 3, css: str | None = "calendar.css", encoding: str | None = None
    ) -> bytes: ...

class different_locale:
    def __init__(self, locale: _LocaleType) -> None: ...
    def __enter__(self) -> None: ...
    def __exit__(self, *args: Unused) -> None: ...

class LocaleTextCalendar(TextCalendar):
    def __init__(self, firstweekday: int = 0, locale: _LocaleType | None = None) -> None: ...

class LocaleHTMLCalendar(HTMLCalendar):
    def __init__(self, firstweekday: int = 0, locale: _LocaleType | None = None) -> None: ...
    def formatweekday(self, day: int) -> str: ...
    def formatmonthname(self, theyear: int, themonth: int, withyear: bool = True) -> str: ...

c: TextCalendar

def setfirstweekday(firstweekday: int) -> None: ...
def format(cols: int, colwidth: int = 20, spacing: int = 6) -> str: ...
def formatstring(cols: Iterable[str], colwidth: int = 20, spacing: int = 6) -> str: ...
def timegm(tuple: tuple[int, ...] | struct_time) -> int: ...

# Data attributes
class _localized_month:
    format: str
    def __init__(self, format: str) -> None: ...

    @overload
    def __getitem__(self, i: int) -> str: ...
    @overload
    def __getitem__(self, i: slice) -> list[str]: ...

    def __len__(self) -> int: ...
    def __iter__(self) -> Iterator[str]: ...

class _localized_day:
    format: str
    def __init__(self, format: str) -> None: ...

    @overload
    def __getitem__(self, i: int) -> str: ...
    @overload
    def __getitem__(self, i: slice) -> list[str]: ...

    def __len__(self) -> int: ...
    def __iter__(self) -> Iterator[str]: ...

day_name: _localized_day
day_abbr: _localized_day
month_name: _localized_month
month_abbr: _localized_month

if sys.version_info >= (3, 12):
    class Month(enum.IntEnum):
        JANUARY = 1
        FEBRUARY = 2
        MARCH = 3
        APRIL = 4
        MAY = 5
        JUNE = 6
        JULY = 7
        AUGUST = 8
        SEPTEMBER = 9
        OCTOBER = 10
        NOVEMBER = 11
        DECEMBER = 12

    JANUARY: Final = Month.JANUARY
    FEBRUARY: Final = Month.FEBRUARY
    MARCH: Final = Month.MARCH
    APRIL: Final = Month.APRIL
    MAY: Final = Month.MAY
    JUNE: Final = Month.JUNE
    JULY: Final = Month.JULY
    AUGUST: Final = Month.AUGUST
    SEPTEMBER: Final = Month.SEPTEMBER
    OCTOBER: Final = Month.OCTOBER
    NOVEMBER: Final = Month.NOVEMBER
    DECEMBER: Final = Month.DECEMBER

    class Day(enum.IntEnum):
        MONDAY = 0
        TUESDAY = 1
        WEDNESDAY = 2
        THURSDAY = 3
        FRIDAY = 4
        SATURDAY = 5
        SUNDAY = 6

    MONDAY: Final = Day.MONDAY
    TUESDAY: Final = Day.TUESDAY
    WEDNESDAY: Final = Day.WEDNESDAY
    THURSDAY: Final = Day.THURSDAY
    FRIDAY: Final = Day.FRIDAY
    SATURDAY: Final = Day.SATURDAY
    SUNDAY: Final = Day.SUNDAY
else:
    MONDAY: Final = 0
    TUESDAY: Final = 1
    WEDNESDAY: Final = 2
    THURSDAY: Final = 3
    FRIDAY: Final = 4
    SATURDAY: Final = 5
    SUNDAY: Final = 6

EPOCH: Final = 1970

if sys.version_info >= (3, 15):
    standalone_month_name: _localized_month
    standalone_month_abbr: _localized_month
