"""
Festival database and management for lunar calendar systems.
"""

from datetime import datetime, timedelta
from typing import Any

from .calendar_conversions import CalendarConverter


class FestivalManager:
    """Manager for lunar festivals across different cultures."""

    def __init__(self) -> None:
        """Initialize the festival manager."""
        self.calendar_converter = CalendarConverter()
        self._load_festival_data()

    def _load_festival_data(self) -> None:
        """Load festival data for different cultures."""
        # Chinese festivals
        self.chinese_festivals = {
            "spring_festival": {
                "name": "Spring Festival (Chinese New Year)",
                "lunar_date": "1-1",  # 1st month, 1st day
                "duration": 15,
                "significance": "Beginning of lunar new year, most important Chinese festival",
                "traditions": [
                    "family reunion dinner",
                    "fireworks",
                    "red envelopes (hongbao)",
                    "dragon and lion dances",
                    "visiting relatives",
                ],
                "foods": ["dumplings", "fish", "rice cakes", "spring rolls"],
                "taboos": ["sweeping", "breaking things", "arguing", "crying"],
                "lucky_activities": [
                    "wearing red",
                    "giving gifts",
                    "paying respects to ancestors",
                ],
                "regional_names": ["Chinese New Year", "Lunar New Year", "春节"],
            },
            "lantern_festival": {
                "name": "Lantern Festival",
                "lunar_date": "1-15",
                "duration": 1,
                "significance": "End of Spring Festival celebrations, first full moon of lunar year",
                "traditions": [
                    "lantern displays",
                    "riddles",
                    "lion dances",
                    "family gathering",
                ],
                "foods": ["tangyuan (sweet rice balls)", "yuanxiao"],
                "lucky_activities": [
                    "viewing lanterns",
                    "solving riddles",
                    "eating tangyuan",
                ],
                "regional_names": ["元宵节", "Shangyuan Festival"],
            },
            "qingming": {
                "name": "Qingming Festival",
                "solar_date": "04-04",  # Usually April 4-6
                "duration": 1,
                "significance": "Tomb sweeping day, honoring ancestors",
                "traditions": [
                    "tomb sweeping",
                    "ancestor worship",
                    "outdoor activities",
                ],
                "foods": ["qingtuan (green dumplings)", "cold food"],
                "lucky_activities": [
                    "cleaning graves",
                    "offering flowers",
                    "flying kites",
                ],
                "regional_names": ["Tomb Sweeping Day", "清明节"],
            },
            "dragon_boat": {
                "name": "Dragon Boat Festival",
                "lunar_date": "5-5",
                "duration": 1,
                "significance": "Commemorating poet Qu Yuan, warding off evil",
                "traditions": [
                    "dragon boat racing",
                    "hanging mugwort",
                    "five-color strings",
                ],
                "foods": ["zongzi (sticky rice dumplings)", "realgar wine"],
                "lucky_activities": [
                    "racing boats",
                    "wearing sachets",
                    "drinking wine",
                ],
                "regional_names": ["Duanwu Festival", "端午节"],
            },
            "qixi": {
                "name": "Qixi Festival",
                "lunar_date": "7-7",
                "duration": 1,
                "significance": "Chinese Valentine's Day, celebrating the weaver girl and cowherd",
                "traditions": ["making wishes", "stargazing", "romantic activities"],
                "foods": ["qiaoguo (clever fruits)", "noodles"],
                "lucky_activities": [
                    "praying for love",
                    "making handicrafts",
                    "stargazing",
                ],
                "regional_names": [
                    "Chinese Valentine's Day",
                    "七夕节",
                    "Double Seventh Festival",
                ],
            },
            "mid_autumn": {
                "name": "Mid-Autumn Festival",
                "lunar_date": "8-15",
                "duration": 1,
                "significance": "Moon festival, family reunion, harvest celebration",
                "traditions": ["moon viewing", "lanterns", "family gathering"],
                "foods": ["mooncakes", "pomelos", "osmanthus wine"],
                "lucky_activities": [
                    "moon gazing",
                    "eating mooncakes",
                    "family reunion",
                ],
                "regional_names": ["Moon Festival", "中秋节", "Mooncake Festival"],
            },
            "double_ninth": {
                "name": "Double Ninth Festival",
                "lunar_date": "9-9",
                "duration": 1,
                "significance": "Climbing heights, honoring elderly, ward off evil",
                "traditions": [
                    "mountain climbing",
                    "chrysanthemum viewing",
                    "wearing dogwood",
                ],
                "foods": ["chrysanthemum wine", "chongyang cake"],
                "lucky_activities": [
                    "climbing mountains",
                    "honoring elders",
                    "viewing flowers",
                ],
                "regional_names": [
                    "Chongyang Festival",
                    "重阳节",
                    "Senior Citizens Day",
                ],
            },
        }

    async def get_festivals_for_date(
        self, date_str: str, culture: str = "chinese"
    ) -> dict[str, Any]:
        """Get all festivals occurring on a specific date."""
        try:
            target_date = datetime.strptime(date_str, "%Y-%m-%d")
            festivals_found = []

            if culture == "chinese":
                # Convert to lunar date
                lunar_info = await self.calendar_converter.solar_to_lunar(
                    date_str, culture
                )
                lunar_month = lunar_info.get("lunar_month", 0)
                lunar_day = lunar_info.get("lunar_day", 0)
                lunar_date_str = f"{lunar_month}-{lunar_day}"

                # Check Chinese festivals
                for festival_id, festival_data in self.chinese_festivals.items():
                    if festival_data.get("lunar_date") == lunar_date_str:
                        festivals_found.append(
                            {
                                "id": festival_id,
                                "name": festival_data["name"],
                                "culture": "chinese",
                                "significance": festival_data["significance"],
                                "traditions": festival_data["traditions"],
                                "foods": festival_data["foods"],
                                "duration": festival_data["duration"],
                                "lucky_activities": festival_data.get(
                                    "lucky_activities", []
                                ),
                                "taboos": festival_data.get("taboos", []),
                                "is_major": festival_id
                                in ["spring_festival", "mid_autumn", "dragon_boat"],
                            }
                        )

                # Check solar-based Chinese festivals
                month_day = f"{target_date.month:02d}-{target_date.day:02d}"
                for festival_id, festival_data in self.chinese_festivals.items():
                    if festival_data.get("solar_date") == month_day:
                        festivals_found.append(
                            {
                                "id": festival_id,
                                "name": festival_data["name"],
                                "culture": "chinese",
                                "significance": festival_data["significance"],
                                "traditions": festival_data["traditions"],
                                "foods": festival_data["foods"],
                                "duration": festival_data["duration"],
                                "lucky_activities": festival_data.get(
                                    "lucky_activities", []
                                ),
                                "is_major": True,
                            }
                        )

            # Determine if any major festival
            is_major_festival = any(f.get("is_major", False) for f in festivals_found)

            return {
                "date": date_str,
                "culture": culture,
                "festivals": festivals_found,
                "festival_count": len(festivals_found),
                "is_major_festival": is_major_festival,
                "celebration_level": self._get_celebration_level(festivals_found),
            }

        except Exception as e:
            return {"error": f"Failed to get festivals for date: {str(e)}"}

    def _get_celebration_level(self, festivals: list[dict[str, Any]]) -> str:
        """Determine celebration level based on festivals."""
        if not festivals:
            return "none"

        major_count = sum(1 for f in festivals if f.get("is_major", False))
        total_count = len(festivals)

        if major_count > 0:
            return "major"
        elif total_count > 1:
            return "multiple"
        else:
            return "minor"

    async def get_next_festival(
        self, date_str: str, culture: str = "chinese"
    ) -> dict[str, Any]:
        """Find the next upcoming festival after a given date."""
        try:
            start_date = datetime.strptime(date_str, "%Y-%m-%d")
            search_limit = 365  # Search within next year

            current_date = start_date + timedelta(days=1)  # Start from next day
            days_searched = 0

            while days_searched < search_limit:
                check_date_str = current_date.strftime("%Y-%m-%d")
                festivals_result = await self.get_festivals_for_date(
                    check_date_str, culture
                )

                if festivals_result.get("festivals"):
                    next_festival = festivals_result["festivals"][
                        0
                    ]  # Get first festival
                    days_until = (current_date - start_date).days

                    return {
                        "search_date": date_str,
                        "next_festival_date": check_date_str,
                        "days_until": days_until,
                        "festival": next_festival,
                        "culture": culture,
                        "preparation_time": self._get_preparation_advice(
                            days_until, next_festival
                        ),
                    }

                current_date += timedelta(days=1)
                days_searched += 1

            return {
                "search_date": date_str,
                "culture": culture,
                "message": f"No festivals found in the next {search_limit} days",
            }

        except Exception as e:
            return {"error": f"Failed to find next festival: {str(e)}"}

    def _get_preparation_advice(self, days_until: int, festival: dict[str, Any]) -> str:
        """Get preparation advice based on time until festival."""
        if days_until <= 3:
            return f"Festival is very soon! Time for final preparations: {', '.join(festival.get('traditions', [])[:2])}"
        elif days_until <= 7:
            return f"Festival is next week. Start preparing: {', '.join(festival.get('traditions', [])[:3])}"
        elif days_until <= 30:
            return f"Festival is in {days_until} days. Plan ahead for: {festival.get('significance', 'celebration')}"
        else:
            return f"Festival is in {days_until} days. Early planning recommended."

    async def get_festival_details(
        self, festival_name: str, culture: str = "chinese"
    ) -> dict[str, Any]:
        """Get detailed information about a specific festival."""
        try:
            festival_data = None
            festival_id = None

            # Search by name or ID in Chinese festivals
            for fid, fdata in self.chinese_festivals.items():
                fest_name: str = str(fdata.get("name", ""))
                regional = fdata.get("regional_names", [])
                regional_list: list[Any] = (
                    regional if isinstance(regional, list) else []
                )
                if (
                    fest_name.lower() == festival_name.lower()
                    or fid.lower() == festival_name.lower()
                    or any(
                        str(name).lower() == festival_name.lower()
                        for name in regional_list
                    )
                ):
                    festival_data = fdata
                    festival_id = fid
                    break

            if not festival_data or festival_id is None:
                return {
                    "error": f"Festival '{festival_name}' not found in {culture} calendar",
                    "available_festivals": self._get_available_festivals(culture),
                }

            # Calculate next occurrence
            next_occurrence = await self._calculate_next_occurrence(
                festival_id, festival_data, culture
            )

            return {
                "festival_id": festival_id,
                "name": festival_data["name"],
                "culture": culture,
                "significance": festival_data["significance"],
                "duration": festival_data["duration"],
                "traditions": festival_data["traditions"],
                "foods": festival_data["foods"],
                "lucky_activities": festival_data.get("lucky_activities", []),
                "taboos": festival_data.get("taboos", []),
                "regional_names": festival_data.get("regional_names", []),
                "next_occurrence": next_occurrence,
                "preparation_guide": self._get_preparation_guide(festival_data),
                "cultural_context": self._get_cultural_context(festival_id, culture),
            }

        except Exception as e:
            return {"error": f"Failed to get festival details: {str(e)}"}

    def _get_available_festivals(self, culture: str) -> list[str]:
        """Get list of available festivals for Chinese culture."""
        return [str(data.get("name", "")) for data in self.chinese_festivals.values()]

    async def _calculate_next_occurrence(
        self, festival_id: str, festival_data: dict[str, Any], culture: str
    ) -> dict[str, Any]:
        """Calculate the next occurrence of a festival."""
        try:
            current_year = datetime.now().year

            # For lunar-based festivals, we need to convert
            if culture == "chinese" and "lunar_date" in festival_data:
                # This would require proper lunar calendar calculation
                # For now, return approximate date
                return {
                    "year": current_year,
                    "approximate_date": "Calculation requires lunar calendar conversion",
                    "note": "Exact date varies each year based on lunar calendar",
                }

            else:
                return {
                    "note": "Next occurrence calculation not available for this festival type"
                }

        except Exception:
            return {"error": "Failed to calculate next occurrence"}

    def _get_preparation_guide(
        self, festival_data: dict[str, Any]
    ) -> dict[str, list[str]]:
        """Get preparation guide for a festival."""
        return {
            "1_week_before": [
                "Plan gatherings and invitations",
                "Shop for special foods and decorations",
                "Prepare traditional items",
            ],
            "3_days_before": [
                "Complete major preparations",
                "Confirm family plans",
                "Prepare ceremonial items",
            ],
            "day_of_festival": festival_data.get("traditions", []),
            "foods_to_prepare": festival_data.get("foods", []),
            "activities": festival_data.get("lucky_activities", []),
        }

    def _get_cultural_context(self, festival_id: str, culture: str) -> str:
        """Get cultural context and historical background for Chinese festivals."""
        context_map = {
            "spring_festival": "The most important festival in Chinese culture, marking the lunar new year with over 4000 years of history.",
            "mid_autumn": "Ancient harvest festival celebrating family unity and the full moon, dating back over 1000 years.",
            "dragon_boat": "Commemorates the ancient poet Qu Yuan and traditionally wards off evil spirits.",
            "lantern_festival": "Marks the end of Spring Festival celebrations and the first full moon of the lunar year.",
        }

        return context_map.get(festival_id, "Cultural context not available.")

    async def get_annual_festivals(
        self, year: int, culture: str = "chinese"
    ) -> dict[str, Any]:
        """Get all festivals for a specific year."""
        try:
            annual_festivals = []
            festival_calendar: dict[int, list[dict[str, Any]]] = {}
            festivals_to_calculate = self.chinese_festivals

            # For demonstration, create a simplified calendar
            # In a full implementation, you'd calculate exact dates based on lunar/solar calendars
            for festival_id, festival_data in festivals_to_calculate.items():
                estimated_date = self._estimate_festival_date(
                    festival_data, year, culture
                )
                if estimated_date:
                    month = estimated_date.get("month", 1)
                    if month not in festival_calendar:
                        festival_calendar[month] = []

                    festival_calendar[month].append(
                        {
                            "id": festival_id,
                            "name": festival_data["name"],
                            "estimated_date": estimated_date,
                            "duration": festival_data["duration"],
                            "significance": festival_data["significance"],
                            "is_major": festival_id
                            in self._get_major_festivals(culture),
                        }
                    )

                    annual_festivals.append(
                        {
                            "id": festival_id,
                            "name": festival_data["name"],
                            "estimated_date": estimated_date,
                            "culture": culture,
                            "significance": festival_data["significance"],
                        }
                    )

            return {
                "year": year,
                "culture": culture,
                "total_festivals": len(annual_festivals),
                "festivals": annual_festivals,
                "calendar_view": festival_calendar,
                "major_festivals": [
                    f
                    for f in annual_festivals
                    if f["id"] in self._get_major_festivals(culture)
                ],
                "note": "Dates are estimated. Actual dates may vary based on lunar observations.",
            }

        except Exception as e:
            return {"error": f"Failed to get annual festivals: {str(e)}"}

    def _estimate_festival_date(
        self, festival_data: dict[str, Any], year: int, culture: str
    ) -> dict[str, Any] | None:
        """Estimate festival date for a given year."""
        if "solar_date" in festival_data:
            month, day = map(int, festival_data["solar_date"].split("-"))
            return {"year": year, "month": month, "day": day, "type": "solar"}

        elif "lunar_date" in festival_data and culture == "chinese":
            lunar_month, lunar_day = map(int, festival_data["lunar_date"].split("-"))
            # Simplified estimation - in reality, you'd need proper lunar calendar conversion
            estimated_solar_month = min(12, max(1, lunar_month + 1))
            return {
                "year": year,
                "month": estimated_solar_month,
                "day": min(28, lunar_day + 10),
                "type": "lunar_estimated",
                "lunar_month": lunar_month,
                "lunar_day": lunar_day,
            }

        return None

    def _get_major_festivals(self, culture: str) -> list[str]:
        """Get list of major Chinese festivals."""
        return ["spring_festival", "mid_autumn", "dragon_boat", "lantern_festival"]
