"""Post-processing extraction of schedule info from conversation text.

Two-stage approach (U4):
1. Zero-LLM regex keyword gate — skip LLM entirely if no time-related keywords.
2. LLM extraction — call the LLM gateway to pull structured event data.

Extracted events are persisted via ``CalendarService.create_event`` with
``source="post_extract"`` and the originating ``conversation_id`` for
traceability (R15).
"""

from __future__ import annotations

import json
import logging
import re

from agentkit.calendar.service import CalendarService

logger = logging.getLogger(__name__)


class PostProcessingExtractor:
    """Extract schedule info from conversation text after a chat turn.

    Two-stage: regex keyword gate (zero LLM) → LLM extraction.
    """

    # Time-related keywords that trigger LLM extraction
    _KEYWORD_RE = re.compile(
        r"明天|后天|下周|本周|今天下午|今天上午|上午|下午|晚上|"
        r"\d+点|\d+月\d+日|\d+号|开会|截止|deadline|schedule|"
        r"reminder|提醒|预约|约定|安排",
        re.IGNORECASE,
    )

    def __init__(self, calendar_service: CalendarService, llm_gateway=None):
        self.service = calendar_service
        self.llm_gateway = llm_gateway  # Optional, may be set later

    async def extract(
        self,
        conversation_text: str,
        conversation_id: str,
        user_id: str,
    ) -> list[dict]:
        """Extract events from conversation text.

        Returns list of created event dicts. Empty if no keywords or no events extracted.
        Never raises — all failures are logged and swallowed.
        """
        # 1. Keyword gate — zero LLM cost if no match
        if not self._KEYWORD_RE.search(conversation_text):
            return []

        # 2. LLM extraction
        events_data = await self._llm_extract(conversation_text)
        if not events_data:
            return []

        # 3. Create events with source="post_extract"
        created = []
        for event_data in events_data:
            try:
                event = await self.service.create_event(
                    user_id=user_id,
                    title=event_data.get("title", ""),
                    start_time=event_data.get("start_time", ""),
                    end_time=event_data.get("end_time", ""),
                    description=event_data.get("description", ""),
                    source="post_extract",
                    conversation_id=conversation_id,
                )
                created.append(event.to_dict())
            except Exception as e:
                logger.warning(f"Failed to create extracted event: {e}")
                continue

        return created

    async def _llm_extract(self, text: str) -> list[dict]:
        """Call LLM gateway to extract events from text.

        Returns list of event dicts: [{title, start_time, end_time, description}].
        Returns [] on any error or empty result.
        """
        if self.llm_gateway is None:
            return []

        prompt = self._build_extraction_prompt(text)
        try:
            response = await self.llm_gateway.acomplete(
                messages=[{"role": "user", "content": prompt}],
                temperature=0.1,
            )
            return self._parse_llm_response(response)
        except Exception as e:
            logger.warning(f"LLM extraction failed: {e}")
            return []

    def _build_extraction_prompt(self, text: str) -> str:
        """Build the LLM extraction prompt."""
        return f"""Extract schedule/event information from the following conversation text.
Return a JSON array of events. Each event should have: title, start_time (ISO 8601), end_time (ISO 8601), description.
If no events are found, return an empty array [].

Conversation text:
{text}

Respond with ONLY the JSON array, no other text."""

    def _parse_llm_response(self, response: str) -> list[dict]:
        """Parse LLM response as JSON array. Returns [] on any error."""
        try:
            # Strip markdown code fences if present
            cleaned = response.strip()
            if cleaned.startswith("```"):
                cleaned = cleaned.split("\n", 1)[1] if "\n" in cleaned else cleaned[3:]
            if cleaned.endswith("```"):
                cleaned = cleaned[:-3]
            cleaned = cleaned.strip()

            data = json.loads(cleaned)
            if not isinstance(data, list):
                return []
            return [item for item in data if isinstance(item, dict) and "title" in item]
        except (json.JSONDecodeError, TypeError) as e:
            logger.warning(f"Failed to parse LLM response as JSON: {e}")
            return []
