"""
Calendar Suggester Utility

Provides intelligent school calendar suggestions based on POI detection data,
tenant location, and heuristics optimized for bakery demand forecasting.
"""

from typing import Optional, Dict, List, Any, Tuple
from datetime import datetime, date, timezone
import structlog

logger = structlog.get_logger()


class CalendarSuggester:
    """
    Suggests appropriate school calendars for tenants based on location context.

    Uses POI detection data, proximity analysis, and bakery-specific heuristics
    to provide intelligent calendar recommendations with confidence scores.
    """

    def __init__(self):
        self.logger = logger

    def suggest_calendar_for_tenant(
        self,
        city_id: str,
        available_calendars: List[Dict[str, Any]],
        poi_context: Optional[Dict[str, Any]] = None,
        tenant_data: Optional[Dict[str, Any]] = None
    ) -> Dict[str, Any]:
        """
        Suggest the most appropriate calendar for a tenant.

        Args:
            city_id: Normalized city ID (e.g., "madrid")
            available_calendars: List of available school calendars for the city
            poi_context: Optional POI detection results including school data
            tenant_data: Optional tenant information (location, etc.)

        Returns:
            Dict with:
                - suggested_calendar_id: UUID of suggested calendar or None
                - calendar_name: Name of suggested calendar
                - confidence: Float 0.0-1.0 confidence score
                - reasoning: List of reasoning steps
                - fallback_calendars: Alternative suggestions
                - should_assign: Boolean recommendation to auto-assign
        """
        if not available_calendars:
            return self._no_calendars_available(city_id)

        # Get current academic year
        academic_year = self._get_current_academic_year()

        # Filter calendars for current academic year
        current_year_calendars = [
            cal for cal in available_calendars
            if cal.get("academic_year") == academic_year
        ]

        if not current_year_calendars:
            # Fallback to any calendar if current year not available
            current_year_calendars = available_calendars
            self.logger.warning(
                "No calendars for current academic year, using all available",
                city_id=city_id,
                academic_year=academic_year
            )

        # Analyze POI context if available
        school_analysis = self._analyze_schools_from_poi(poi_context) if poi_context else None

        # Apply bakery-specific heuristics
        suggestion = self._apply_suggestion_heuristics(
            current_year_calendars,
            school_analysis,
            city_id
        )

        return suggestion

    def _get_current_academic_year(self) -> str:
        """
        Determine current academic year based on date.

        Academic year runs September to June (Spain):
        - Jan-Aug: Previous year (e.g., 2024-2025)
        - Sep-Dec: Current year (e.g., 2025-2026)

        Returns:
            Academic year string (e.g., "2024-2025")
        """
        today = date.today()
        year = today.year

        # Academic year starts in September
        if today.month >= 9:  # September onwards
            return f"{year}-{year + 1}"
        else:  # January-August
            return f"{year - 1}-{year}"

    def _analyze_schools_from_poi(
        self,
        poi_context: Dict[str, Any]
    ) -> Optional[Dict[str, Any]]:
        """
        Analyze school POIs to infer school type preferences.

        Args:
            poi_context: POI detection results

        Returns:
            Dict with:
                - has_schools_nearby: Boolean
                - school_count: Int count of schools
                - nearest_distance: Float distance to nearest school (meters)
                - proximity_score: Float proximity score
                - school_names: List of detected school names
        """
        try:
            poi_results = poi_context.get("poi_detection_results", {})
            schools_data = poi_results.get("schools", {})

            if not schools_data:
                return None

            school_pois = schools_data.get("pois", [])
            school_count = len(school_pois)

            if school_count == 0:
                return None

            # Extract school details
            school_names = [
                poi.get("name", "Unknown School")
                for poi in school_pois
                if poi.get("name")
            ]

            # Get proximity metrics
            features = schools_data.get("features", {})
            proximity_score = features.get("proximity_score", 0.0)

            # Calculate nearest distance (approximate from POI data)
            nearest_distance = None
            if school_pois:
                # If we have POIs, estimate nearest distance
                # This is approximate - exact calculation would require tenant coords
                nearest_distance = 100.0  # Default assumption if schools detected

            return {
                "has_schools_nearby": True,
                "school_count": school_count,
                "nearest_distance": nearest_distance,
                "proximity_score": proximity_score,
                "school_names": school_names
            }

        except Exception as e:
            self.logger.warning(
                "Failed to analyze schools from POI",
                error=str(e)
            )
            return None

    def _apply_suggestion_heuristics(
        self,
        calendars: List[Dict[str, Any]],
        school_analysis: Optional[Dict[str, Any]],
        city_id: str
    ) -> Dict[str, Any]:
        """
        Apply heuristics to suggest best calendar.

        Bakery-specific heuristics:
        1. If schools detected nearby -> Prefer primary (stronger morning rush)
        2. If no schools detected -> Still suggest primary (more common, safer default)
        3. Primary schools have stronger impact on bakery traffic

        Args:
            calendars: List of available calendars
            school_analysis: Analysis of nearby schools
            city_id: City identifier

        Returns:
            Suggestion dict with confidence and reasoning
        """
        reasoning = []
        confidence = 0.0

        # Separate calendars by type
        primary_calendars = [c for c in calendars if c.get("school_type") == "primary"]
        secondary_calendars = [c for c in calendars if c.get("school_type") == "secondary"]
        other_calendars = [c for c in calendars if c.get("school_type") not in ["primary", "secondary"]]

        # Heuristic 1: Schools detected nearby
        if school_analysis and school_analysis.get("has_schools_nearby"):
            school_count = school_analysis.get("school_count", 0)
            proximity_score = school_analysis.get("proximity_score", 0.0)

            reasoning.append(f"Detected {school_count} schools nearby (proximity score: {proximity_score:.2f})")

            if primary_calendars:
                suggested = primary_calendars[0]
                confidence = min(0.85, 0.65 + (proximity_score * 0.1))  # 65-85% confidence
                reasoning.append("Primary schools create strong morning rush (7:30-9am drop-off)")
                reasoning.append("Primary calendars recommended for bakeries near schools")
            elif secondary_calendars:
                suggested = secondary_calendars[0]
                confidence = 0.70
                reasoning.append("Secondary school calendars available (later morning start)")
            else:
                suggested = calendars[0]
                confidence = 0.50
                reasoning.append("Using available calendar (school type not specified)")

        # Heuristic 2: No schools detected
        else:
            reasoning.append("No schools detected within 500m radius")

            if primary_calendars:
                suggested = primary_calendars[0]
                confidence = 0.60  # Lower confidence without detected schools
                reasoning.append("Defaulting to primary calendar (more common, safer choice)")
                reasoning.append("Primary school holidays still affect general foot traffic")
            elif secondary_calendars:
                suggested = secondary_calendars[0]
                confidence = 0.55
                reasoning.append("Secondary calendar available as default")
            elif other_calendars:
                suggested = other_calendars[0]
                confidence = 0.50
                reasoning.append("Using available calendar")
            else:
                suggested = calendars[0]
                confidence = 0.45
                reasoning.append("No preferred calendar type available")

        # Confidence adjustment based on school analysis quality
        if school_analysis:
            if school_analysis.get("school_count", 0) >= 3:
                confidence = min(1.0, confidence + 0.05)  # Boost for multiple schools
                reasoning.append("High confidence: Multiple schools detected")

            proximity = school_analysis.get("proximity_score", 0.0)
            if proximity > 2.0:
                confidence = min(1.0, confidence + 0.05)  # Boost for close proximity
                reasoning.append("High confidence: Schools very close to bakery")

        # Determine if we should auto-assign
        # Only auto-assign if confidence >= 75% AND schools detected
        should_auto_assign = (
            confidence >= 0.75 and
            school_analysis is not None and
            school_analysis.get("has_schools_nearby", False)
        )

        # Build fallback suggestions
        fallback_calendars = []
        for cal in calendars:
            if cal.get("id") != suggested.get("id"):
                fallback_calendars.append({
                    "calendar_id": str(cal.get("id")),
                    "calendar_name": cal.get("name"),
                    "school_type": cal.get("school_type"),
                    "academic_year": cal.get("academic_year")
                })

        return {
            "suggested_calendar_id": str(suggested.get("id")),
            "calendar_name": suggested.get("name"),
            "school_type": suggested.get("school_type"),
            "academic_year": suggested.get("academic_year"),
            "confidence": round(confidence, 2),
            "confidence_percentage": round(confidence * 100, 1),
            "reasoning": reasoning,
            "fallback_calendars": fallback_calendars[:2],  # Top 2 alternatives
            "should_auto_assign": should_auto_assign,
            "school_analysis": school_analysis,
            "city_id": city_id
        }

    def _no_calendars_available(self, city_id: str) -> Dict[str, Any]:
        """Return response when no calendars available for city."""
        return {
            "suggested_calendar_id": None,
            "calendar_name": None,
            "school_type": None,
            "academic_year": None,
            "confidence": 0.0,
            "confidence_percentage": 0.0,
            "reasoning": [
                f"No school calendars configured for city: {city_id}",
                "Calendar assignment not possible at this time",
                "Location context created without calendar (can be added later)"
            ],
            "fallback_calendars": [],
            "should_auto_assign": False,
            "school_analysis": None,
            "city_id": city_id
        }

    def format_suggestion_for_admin(self, suggestion: Dict[str, Any]) -> str:
        """
        Format suggestion as human-readable text for admin UI.

        Args:
            suggestion: Suggestion dict from suggest_calendar_for_tenant

        Returns:
            Formatted string for display
        """
        if not suggestion.get("suggested_calendar_id"):
            return f"⚠️  No calendars available for {suggestion.get('city_id', 'this city')}"

        confidence_pct = suggestion.get("confidence_percentage", 0)
        calendar_name = suggestion.get("calendar_name", "Unknown")
        school_type = suggestion.get("school_type", "").capitalize()

        # Confidence emoji
        if confidence_pct >= 80:
            emoji = "✅"
        elif confidence_pct >= 60:
            emoji = "📊"
        else:
            emoji = "💡"

        text = f"{emoji} **Suggested**: {calendar_name}\n"
        text += f"**Type**: {school_type} | **Confidence**: {confidence_pct}%\n\n"
        text += "**Reasoning**:\n"

        for reason in suggestion.get("reasoning", []):
            text += f"• {reason}\n"

        if suggestion.get("fallback_calendars"):
            text += "\n**Alternatives**:\n"
            for alt in suggestion.get("fallback_calendars", [])[:2]:
                text += f"• {alt.get('calendar_name')} ({alt.get('school_type')})\n"

        return text
