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

__all__ = [
    "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, 10):
    __all__ += ["FRIDAY", "MONDAY", "SATURDAY", "SUNDAY", "THURSDAY", "TUESDAY", "WEDNESDAY"]
if sys.version_info >= (3, 12):
    __all__ += [
        "Day",
        "Month",
        "JANUARY",
        "FEBRUARY",
        "MARCH",
        "APRIL",
        "MAY",
        "JUNE",
        "JULY",
        "AUGUST",
        "SEPTEMBER",
        "OCTOBER",
        "NOVEMBER",
        "DECEMBER",
    ]

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

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

class IllegalWeekdayError(ValueError):
    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) -> Iterable[int]: ...
    def itermonthdates(self, year: int, month: int) -> Iterable[datetime.date]: ...
    def itermonthdays2(self, year: int, month: int) -> Iterable[tuple[int, int]]: ...
    def itermonthdays(self, year: int, month: int) -> Iterable[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) -> Iterable[tuple[int, int, int]]: ...
    def itermonthdays4(self, year: int, month: int) -> Iterable[tuple[int, int, int, int]]: ...

class TextCalendar(Calendar):
    def prweek(self, theweek: int, width: int) -> None: ...
    def formatday(self, day: int, weekday: int, width: int) -> str: ...
    def formatweek(self, theweek: 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: ...
    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: int, colwidth: int = 20, spacing: int = 6) -> str: ...
def timegm(tuple: tuple[int, ...] | struct_time) -> int: ...

# Data attributes
day_name: Sequence[str]
day_abbr: Sequence[str]
month_name: Sequence[str]
month_abbr: Sequence[str]

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 = Month.JANUARY
    FEBRUARY = Month.FEBRUARY
    MARCH = Month.MARCH
    APRIL = Month.APRIL
    MAY = Month.MAY
    JUNE = Month.JUNE
    JULY = Month.JULY
    AUGUST = Month.AUGUST
    SEPTEMBER = Month.SEPTEMBER
    OCTOBER = Month.OCTOBER
    NOVEMBER = Month.NOVEMBER
    DECEMBER = Month.DECEMBER

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

    MONDAY = Day.MONDAY
    TUESDAY = Day.TUESDAY
    WEDNESDAY = Day.WEDNESDAY
    THURSDAY = Day.THURSDAY
    FRIDAY = Day.FRIDAY
    SATURDAY = Day.SATURDAY
    SUNDAY = 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
