"""Temporal coordinates and astronomical calculations.

This module provides temporal positioning including solstices, equinoxes,
and other astronomical/calendrical coordinates.
"""

from dataclasses import dataclass
from enum import Enum
from typing import Optional


class Season(Enum):
    """The four seasons of the year."""

    SPRING = "Spring"  # Vernal Equinox (Mar 20/21)
    SUMMER = "Summer"  # Summer Solstice (Jun 20/21)
    AUTUMN = "Autumn"  # Autumnal Equinox (Sep 22/23)
    WINTER = "Winter"  # Winter Solstice (Dec 21/22)


@dataclass
class SolarEvent:
    """Represents a solar event (solstice or equinox).

    Attributes:
        event_type: The type of solar event (solstice or equinox)
        date: The approximate date of the event
        season: The associated season
    """

    event_type: str  # "solstice" or "equinox"
    date: tuple  # (month, day)
    season: Season

    def __str__(self) -> str:
        return f"{self.season.value} {self.event_type.title()} ({self.date[0]}/{self.date[1]})"


class TemporalCoordinates:
    """Temporal positioning and astronomical calculations."""

    # Approximate dates for solar events (can vary by ±1-2 days yearly)
    SOLAR_EVENTS = {
        Season.SPRING: SolarEvent("equinox", (3, 20), Season.SPRING),
        Season.SUMMER: SolarEvent("solstice", (6, 21), Season.SUMMER),
        Season.AUTUMN: SolarEvent("equinox", (9, 22), Season.AUTUMN),
        Season.WINTER: SolarEvent("solstice", (12, 21), Season.WINTER),
    }

    @staticmethod
    def get_season(month: int, day: int) -> Season:
        """Get the season for a given month and day.

        Args:
            month: Month number (1-12)
            day: Day of month (1-31)

        Returns:
            The Season enum value
        """
        # Define season boundaries
        if (month == 3 and day >= 20) or (month in (4, 5)) or (month == 6 and day < 21):
            return Season.SPRING
        elif (month == 6 and day >= 21) or (month in (7, 8)) or (month == 9 and day < 22):
            return Season.SUMMER
        elif (month == 9 and day >= 22) or (month in (10, 11)) or (month == 12 and day < 21):
            return Season.AUTUMN
        else:  # Winter
            return Season.WINTER

    @staticmethod
    def get_solar_event(season: Season) -> Optional[SolarEvent]:
        """Get the solar event for a given season.

        Args:
            season: The Season enum value

        Returns:
            SolarEvent object for that season
        """
        return TemporalCoordinates.SOLAR_EVENTS.get(season)

    @staticmethod
    def days_until_event(month: int, day: int, target_season: Season) -> int:
        """Calculate days until a solar event.

        Args:
            month: Current month (1-12)
            day: Current day (1-31)
            target_season: Target season for calculation

        Returns:
            Number of days until the target seasonal event
        """
        # This is a simplified calculation
        event = TemporalCoordinates.get_solar_event(target_season)
        if not event:
            return -1

        event_month, event_day = event.date

        # Simple day-of-year calculation
        current_doy = TemporalCoordinates._day_of_year(month, day)
        event_doy = TemporalCoordinates._day_of_year(event_month, event_day)

        if event_doy >= current_doy:
            return event_doy - current_doy
        else:
            return (365 - current_doy) + event_doy

    @staticmethod
    def _day_of_year(month: int, day: int) -> int:
        """Get the day of year (1-365/366).

        Args:
            month: Month (1-12)
            day: Day (1-31)

        Returns:
            Day of year
        """
        days_in_months = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
        return sum(days_in_months[: month - 1]) + day
