"""
Date Normalizer

Normalizes dates in various formats to ISO and generates variants.
"""

import re
from datetime import datetime
from .base import BaseNormalizer


class DateNormalizer(BaseNormalizer):
    """
    Normalizes dates to YYYY-MM-DD and generates variants.

    Handles Swedish and international date formats.

    Examples:
        '2025-12-13' -> ['2025-12-13', '13/12/2025', '13.12.2025']
        '13/12/2025' -> ['2025-12-13', '13/12/2025', ...]
        '13 december 2025' -> ['2025-12-13', ...]
    """

    # Swedish month names
    SWEDISH_MONTHS = {
        'januari': '01', 'jan': '01',
        'februari': '02', 'feb': '02',
        'mars': '03', 'mar': '03',
        'april': '04', 'apr': '04',
        'maj': '05',
        'juni': '06', 'jun': '06',
        'juli': '07', 'jul': '07',
        'augusti': '08', 'aug': '08',
        'september': '09', 'sep': '09', 'sept': '09',
        'oktober': '10', 'okt': '10',
        'november': '11', 'nov': '11',
        'december': '12', 'dec': '12'
    }

    def normalize(self, value: str) -> list[str]:
        """Generate variants of date."""
        value = self.clean_text(value)
        variants = [value]
        parsed_dates = []

        # Try unambiguous patterns first
        date_patterns = [
            # ISO format with optional time
            (r'^(\d{4})-(\d{1,2})-(\d{1,2})(?:\s+\d{1,2}:\d{2}:\d{2})?$',
             lambda m: (int(m[1]), int(m[2]), int(m[3]))),
            # Swedish format: YYMMDD
            (r'^(\d{2})(\d{2})(\d{2})$',
             lambda m: (2000 + int(m[1]) if int(m[1]) < 50 else 1900 + int(m[1]), int(m[2]), int(m[3]))),
            # Swedish format: YYYYMMDD
            (r'^(\d{4})(\d{2})(\d{2})$',
             lambda m: (int(m[1]), int(m[2]), int(m[3]))),
        ]

        for pattern, extractor in date_patterns:
            match = re.match(pattern, value)
            if match:
                try:
                    year, month, day = extractor(match)
                    parsed_dates.append(datetime(year, month, day))
                    break
                except ValueError:
                    continue

        # Try ambiguous patterns with 4-digit year
        ambiguous_patterns_4digit = [
            r'^(\d{1,2})/(\d{1,2})/(\d{4})$',
            r'^(\d{1,2})\.(\d{1,2})\.(\d{4})$',
            r'^(\d{1,2})-(\d{1,2})-(\d{4})$',
        ]

        if not parsed_dates:
            for pattern in ambiguous_patterns_4digit:
                match = re.match(pattern, value)
                if match:
                    n1, n2, year = int(match[1]), int(match[2]), int(match[3])

                    # Try DD/MM/YYYY (European - day first)
                    try:
                        parsed_dates.append(datetime(year, n2, n1))
                    except ValueError:
                        pass

                    # Try MM/DD/YYYY (US - month first) if different
                    if n1 != n2:
                        try:
                            parsed_dates.append(datetime(year, n1, n2))
                        except ValueError:
                            pass

                    if parsed_dates:
                        break

        # Try ambiguous patterns with 2-digit year
        ambiguous_patterns_2digit = [
            r'^(\d{1,2})\.(\d{1,2})\.(\d{2})$',
            r'^(\d{1,2})/(\d{1,2})/(\d{2})$',
            r'^(\d{1,2})-(\d{1,2})-(\d{2})$',
        ]

        if not parsed_dates:
            for pattern in ambiguous_patterns_2digit:
                match = re.match(pattern, value)
                if match:
                    n1, n2, yy = int(match[1]), int(match[2]), int(match[3])
                    year = 2000 + yy if yy < 50 else 1900 + yy

                    # Try DD/MM/YY (European)
                    try:
                        parsed_dates.append(datetime(year, n2, n1))
                    except ValueError:
                        pass

                    # Try MM/DD/YY (US) if different
                    if n1 != n2:
                        try:
                            parsed_dates.append(datetime(year, n1, n2))
                        except ValueError:
                            pass

                    if parsed_dates:
                        break

        # Try Swedish month names
        if not parsed_dates:
            for month_name, month_num in self.SWEDISH_MONTHS.items():
                if month_name in value.lower():
                    numbers = re.findall(r'\d+', value)
                    if len(numbers) >= 2:
                        day = int(numbers[0])
                        year = int(numbers[-1])
                        if year < 100:
                            year = 2000 + year if year < 50 else 1900 + year
                        try:
                            parsed_dates.append(datetime(year, int(month_num), day))
                            break
                        except ValueError:
                            continue

        # Generate variants for all parsed dates
        swedish_months_full = [
            'januari', 'februari', 'mars', 'april', 'maj', 'juni',
            'juli', 'augusti', 'september', 'oktober', 'november', 'december'
        ]
        swedish_months_abbrev = [
            'jan', 'feb', 'mar', 'apr', 'maj', 'jun',
            'jul', 'aug', 'sep', 'okt', 'nov', 'dec'
        ]

        for parsed_date in parsed_dates:
            iso = parsed_date.strftime('%Y-%m-%d')
            eu_slash = parsed_date.strftime('%d/%m/%Y')
            us_slash = parsed_date.strftime('%m/%d/%Y')
            eu_dot = parsed_date.strftime('%d.%m.%Y')
            iso_dot = parsed_date.strftime('%Y.%m.%d')
            compact = parsed_date.strftime('%Y%m%d')
            compact_short = parsed_date.strftime('%y%m%d')
            eu_dot_short = parsed_date.strftime('%d.%m.%y')
            eu_slash_short = parsed_date.strftime('%d/%m/%y')
            yy_mm_dd_short = parsed_date.strftime('%y-%m-%d')
            iso_middot = parsed_date.strftime('%Y·%m·%d')
            spaced_full = parsed_date.strftime('%Y %m %d')
            spaced_short = parsed_date.strftime('%y %m %d')

            # Swedish month name formats
            month_full = swedish_months_full[parsed_date.month - 1]
            month_abbrev = swedish_months_abbrev[parsed_date.month - 1]
            swedish_format_full = f"{parsed_date.day} {month_full} {parsed_date.year}"
            swedish_format_abbrev = f"{parsed_date.day} {month_abbrev} {parsed_date.year}"

            month_abbrev_upper = month_abbrev.upper()
            swedish_hyphen_short = f"{parsed_date.day:02d}-{month_abbrev_upper}-{parsed_date.strftime('%y')}"
            swedish_hyphen_short_lower = f"{parsed_date.day:02d}-{month_abbrev}-{parsed_date.strftime('%y')}"
            swedish_hyphen_short_no_zero = f"{parsed_date.day}-{month_abbrev_upper}-{parsed_date.strftime('%y')}"
            month_year_only = f"{month_abbrev_upper}-{parsed_date.strftime('%y')}"
            swedish_spaced = f"{parsed_date.day:02d} {month_abbrev_upper} {parsed_date.strftime('%y')}"

            variants.extend([
                iso, eu_slash, us_slash, eu_dot, iso_dot, compact, compact_short,
                eu_dot_short, eu_slash_short, yy_mm_dd_short, iso_middot, spaced_full, spaced_short,
                swedish_format_full, swedish_format_abbrev,
                swedish_hyphen_short, swedish_hyphen_short_lower, swedish_hyphen_short_no_zero,
                month_year_only, swedish_spaced
            ])

        return list(set(v for v in variants if v))
