"""MeshMonitor trigger sync via HTTP."""

import json
import logging
import re
import time
from typing import Optional
from urllib.error import HTTPError, URLError
from urllib.request import Request, urlopen

logger = logging.getLogger(__name__)


def _trigger_to_regex(trigger: str) -> re.Pattern:
    """Convert MeshMonitor trigger pattern to compiled regex.

    MeshMonitor patterns:
    - !weather {location:.+}  -> !weather (.+)
    - !ping                   -> !ping
    - !status                 -> !status

    Args:
        trigger: MeshMonitor trigger pattern

    Returns:
        Compiled regex pattern
    """
    # Extract just the command part (before any {param} placeholders)
    # Replace {name:pattern} with just the pattern for matching
    pattern = re.sub(r"\{[^:}]+:([^}]+)\}", r"(\1)", trigger)
    # Replace {name} (no pattern) with (.+)
    pattern = re.sub(r"\{[^}]+\}", r"(.+)", pattern)
    # Escape regex special chars except what we just inserted
    # Actually, we need to be careful - just anchor it
    pattern = "^" + pattern + "$"
    return re.compile(pattern, re.IGNORECASE)


class MeshMonitorSync:
    """Sync auto-responder triggers from MeshMonitor HTTP API."""

    def __init__(self, url: str, refresh_interval: int = 300):
        """Initialize MeshMonitor sync.

        Args:
            url: Base URL of MeshMonitor (e.g., http://100.64.0.11:3333)
            refresh_interval: Seconds between refresh checks (default 5 minutes)
        """
        self._url = url.rstrip("/")
        self._refresh_interval = refresh_interval
        self._patterns: list[re.Pattern] = []
        self._raw_triggers: list[str] = []
        self._last_refresh: float = 0.0
        self._last_error: Optional[str] = None

    @property
    def raw_triggers(self) -> list[str]:
        """Get raw trigger patterns (for display)."""
        return list(self._raw_triggers)

    @property
    def last_error(self) -> Optional[str]:
        """Get last error message if any."""
        return self._last_error

    def load(self) -> int:
        """Fetch triggers from MeshMonitor API.

        Returns:
            Number of triggers loaded
        """
        endpoint = f"{self._url}/api/settings"
        try:
            req = Request(endpoint, headers={"Accept": "application/json"})
            with urlopen(req, timeout=10) as resp:
                data = json.loads(resp.read().decode("utf-8"))

            # autoResponderTriggers is a JSON string inside the response
            triggers_json = data.get("autoResponderTriggers", "[]")
            if isinstance(triggers_json, str):
                triggers = json.loads(triggers_json)
            else:
                triggers = triggers_json

            # Extract trigger patterns
            self._raw_triggers = []
            self._patterns = []
            for item in triggers:
                if isinstance(item, dict):
                    trigger_value = item.get("trigger", "")
                else:
                    trigger_value = item

                # Handle both string and list of strings
                if isinstance(trigger_value, list):
                    trigger_list = trigger_value
                elif isinstance(trigger_value, str) and trigger_value:
                    trigger_list = [trigger_value]
                else:
                    continue

                for trigger in trigger_list:
                    if not trigger:
                        continue
                    self._raw_triggers.append(trigger)
                    try:
                        self._patterns.append(_trigger_to_regex(trigger))
                    except re.error as e:
                        logger.warning(f"Invalid trigger pattern '{trigger}': {e}")

            self._last_refresh = time.time()
            self._last_error = None
            logger.info(f"Loaded {len(self._patterns)} MeshMonitor triggers")
            return len(self._patterns)

        except HTTPError as e:
            self._last_error = f"HTTP {e.code}: {e.reason}"
            logger.error(f"Failed to fetch MeshMonitor triggers: {self._last_error}")
            return 0
        except URLError as e:
            self._last_error = f"Connection error: {e.reason}"
            logger.error(f"Failed to fetch MeshMonitor triggers: {self._last_error}")
            return 0
        except json.JSONDecodeError as e:
            self._last_error = f"Invalid JSON: {e}"
            logger.error(f"Failed to parse MeshMonitor response: {self._last_error}")
            return 0
        except Exception as e:
            self._last_error = str(e)
            logger.error(f"Failed to fetch MeshMonitor triggers: {self._last_error}")
            return 0

    def maybe_refresh(self) -> bool:
        """Refresh triggers if interval has passed.

        Returns:
            True if refresh was performed
        """
        if time.time() - self._last_refresh >= self._refresh_interval:
            self.load()
            return True
        return False

    def matches(self, text: str) -> bool:
        """Check if text matches any MeshMonitor trigger.

        Args:
            text: Message text to check

        Returns:
            True if MeshMonitor will handle this message
        """
        text = text.strip()
        for pattern in self._patterns:
            if pattern.match(text):
                return True
        return False

    def get_commands_summary(self) -> str:
        """Get a summary of MeshMonitor commands for prompt injection.

        Returns:
            Human-readable summary of available commands
        """
        if not self._raw_triggers:
            return ""

        lines = ["MeshMonitor handles these commands (do not respond to them):"]
        for trigger in self._raw_triggers:
            lines.append(f"  - {trigger}")
        return "\n".join(lines)
