"""
Target month parser for time-shifting configuration.

Parses target month specifications from config including explicit lists
and month ranges.
"""

from typing import List, Optional
from datetime import datetime
import re


class TargetMonthParser:
    """
    Parses target month specifications from config.

    Supports:
    - Explicit month lists: ["2026-01", "2026-02"]
    - Month ranges: "2026-01:2026-12"
    - Combination of both
    """

    def parse_targets(
        self,
        explicit_months: Optional[List[str]] = None,
        month_range: Optional[str] = None
    ) -> List[str]:
        """
        Parse and combine target month specifications.

        Args:
            explicit_months: List of explicit months (e.g., ["2026-01"])
            month_range: Month range spec (e.g., "2026-01:2026-12")

        Returns:
            Sorted, deduplicated list of target months in YYYY-MM format

        Raises:
            ValueError: If both inputs are None or formats are invalid

        Examples:
            >>> parser = TargetMonthParser()
            >>> parser.parse_targets(["2026-01", "2026-02"])
            ['2026-01', '2026-02']
            >>> parser.parse_targets(month_range="2026-01:2026-03")
            ['2026-01', '2026-02', '2026-03']
        """
        if not explicit_months and not month_range:
            raise ValueError(
                "Must specify either explicit_months or month_range"
            )

        months = set()

        # Add explicit months
        if explicit_months:
            for month in explicit_months:
                self._validate_month_format(month)
                months.add(month)

        # Expand and add range
        if month_range:
            range_months = self._expand_range(month_range)
            months.update(range_months)

        return sorted(list(months))

    def _expand_range(self, range_spec: str) -> List[str]:
        """
        Expand month range specification.

        Args:
            range_spec: Range in format "YYYY-MM:YYYY-MM"

        Returns:
            List of months in range (inclusive)

        Raises:
            ValueError: If range format is invalid

        Examples:
            >>> parser = TargetMonthParser()
            >>> parser._expand_range("2026-01:2026-03")
            ['2026-01', '2026-02', '2026-03']
        """
        if ":" not in range_spec:
            raise ValueError(
                f"Invalid range format: {range_spec}. "
                "Expected format: 'YYYY-MM:YYYY-MM'"
            )

        start_str, end_str = range_spec.split(":")
        self._validate_month_format(start_str)
        self._validate_month_format(end_str)

        start = datetime.strptime(start_str, "%Y-%m")
        end = datetime.strptime(end_str, "%Y-%m")

        if start > end:
            raise ValueError(
                f"Invalid range: start ({start_str}) after end ({end_str})"
            )

        months = []
        current = start
        while current <= end:
            months.append(current.strftime("%Y-%m"))
            # Increment month
            year = current.year
            month = current.month + 1
            if month > 12:
                year += 1
                month = 1
            current = datetime(year, month, 1)

        return months

    def _validate_month_format(self, month: str) -> None:
        """
        Validate month string format.

        Args:
            month: Month string to validate

        Raises:
            ValueError: If format is not YYYY-MM or date is invalid

        Examples:
            >>> parser = TargetMonthParser()
            >>> parser._validate_month_format("2026-01")  # Valid
            >>> parser._validate_month_format("2026-13")  # Raises ValueError
        """
        if not re.match(r'^\d{4}-\d{2}$', month):
            raise ValueError(
                f"Invalid month format: {month}. Expected format: YYYY-MM"
            )

        try:
            datetime.strptime(month, "%Y-%m")
        except ValueError as e:
            raise ValueError(
                f"Invalid month date: {month}. Error: {str(e)}"
            )
