from features.base_feature import BaseFeature
from datetime import datetime
from urllib.parse import quote as _url_quote


class SchedulingFeature(BaseFeature):

    async def get_context(
        self,
        preferences_a: dict,
        preferences_b: dict,
        user_a_id: int = None,
        user_b_id: int = None,
    ) -> str:
        """
        Compute overlapping time windows. If a user hasn't provided any times
        in their message AND they have Google Calendar connected, automatically
        fetch their free slots from the calendar instead of leaving it empty.
        """
        windows_a = self._extract_windows(preferences_a)
        windows_b = self._extract_windows(preferences_b)

        # ── Google Calendar fallback: fetch free slots when no times given ──
        if not windows_a and user_a_id:
            windows_a = await self._fetch_calendar_slots(user_a_id, tag="A")
        if not windows_b and user_b_id:
            windows_b = await self._fetch_calendar_slots(user_b_id, tag="B")

        overlap_lines = []
        if windows_a and windows_b:
            for wa in windows_a:
                for wb in windows_b:
                    if wa.lower() == wb.lower():
                        overlap_lines.append(f"  • {wa}")
                    # Simple keyword matching for day/time overlap
                    elif any(
                        word in wa.lower() for word in wb.lower().split()
                        if len(word) > 3
                    ):
                        overlap_lines.append(f"  • {wa} (aligns with {wb})")

        location_a = preferences_a.get("raw_details", {}).get("location", "")
        location_b = preferences_b.get("raw_details", {}).get("location", "")

        lines = ["SCHEDULING DOMAIN RULES:"]
        lines.append("• Only propose times that appear in BOTH parties' available windows.")
        lines.append("• Duration is non-negotiable — respect it.")
        lines.append("• If no overlap exists, escalate immediately with closest alternatives.")

        if windows_a:
            lines.append(f"\nPerson A available: {', '.join(windows_a)}")
        if windows_b:
            lines.append(f"Person B available: {', '.join(windows_b)}")
        if overlap_lines:
            lines.append(f"\nDetected overlapping windows:\n" + "\n".join(overlap_lines))
        else:
            lines.append("\nNo clear overlap detected — propose closest alternatives and offer to adjust.")

        if location_a or location_b:
            loc = location_a or location_b
            lines.append(f"\nMeeting location preference: {loc}")

        return "\n".join(lines)

    async def _fetch_calendar_slots(
        self, user_id: int, tag: str = ""
    ) -> list[str]:
        """
        Query Google Calendar for the user's free slots over the next 7 days.
        Returns a list of human-readable strings like
        "Mon Mar 2 10:00-11:00 AM".  Returns [] silently on any error so
        the negotiation always continues even without calendar access.
        """
        try:
            from tools.google_calendar import GoogleCalendarTool
            tool = GoogleCalendarTool()
            slots = await tool.get_free_slots(user_id)
            if slots:
                label = f" (from Google Calendar{' — Person ' + tag if tag else ''})"
                print(f"[Calendar] Fetched {len(slots)} free slots for user {user_id}")
                # Attach the source label only to the first entry for readability
                return [slots[0] + label] + slots[1:]
            return []
        except Exception as e:
            print(f"[Calendar] Could not fetch slots for user {user_id}: {e}")
            return []

    def _extract_windows(self, preferences: dict) -> list:
        windows = (
            preferences.get("raw_details", {}).get("available_windows")
            or preferences.get("constraints", [])
        )
        if isinstance(windows, list):
            return [str(w) for w in windows]
        if isinstance(windows, str):
            return [windows]
        return []

    def format_resolution(
        self, resolution: dict, preferences_a: dict, preferences_b: dict
    ) -> str:
        status = resolution.get("status", "resolved")
        final = resolution.get("final_proposal", {})
        details = final.get("details", {})
        rounds = resolution.get("rounds_taken", "?")
        summary = resolution.get("summary", "")

        if status == "escalated":
            return (
                f"⚠️ *Meeting — Human Decision Needed*\n\n"
                f"_{summary}_\n\n"
                f"Our agents couldn't find a perfect time in {rounds} round(s). "
                f"Please compare calendars directly."
            )

        proposed_time = (
            details.get("proposed_datetime")
            or details.get("date_time")
            or details.get("time")
            or final.get("summary", "")
        )
        duration = details.get("duration") or preferences_a.get("raw_details", {}).get("duration", "")
        location = (
            details.get("location")
            or preferences_a.get("raw_details", {}).get("location")
            or preferences_b.get("raw_details", {}).get("location")
            or "TBD"
        )
        meeting_type = details.get("meeting_type") or details.get("type") or "Meeting"
        reasoning = resolution.get("summary", "")

        lines = [
            "✅ *Meeting Scheduled!*\n",
            f"📅 *When:* {proposed_time}",
        ]
        if duration:
            lines.append(f"⏱ *Duration:* {duration}")
        if location and location != "TBD":
            maps_url = f"https://maps.google.com/?q={_url_quote(str(location))}"
            lines.append(f"📍 *Location:* [{location}]({maps_url})")
        else:
            lines.append(f"📍 *Location:* {location}")
        lines.append(f"📋 *Type:* {meeting_type}")
        lines.append(f"\n⏱ Agreed in {rounds} round(s)")
        if reasoning and reasoning != "Agreement reached":
            lines.append(f"_{reasoning}_")

        return "\n".join(lines)
