"""
Notification templates for different event types.
"""

from enum import Enum
from pathlib import Path
from typing import Dict, Any, Optional

from jinja2 import Environment, FileSystemLoader, select_autoescape
from loguru import logger


class EventType(Enum):
    """Types of events that can trigger notifications."""

    # Research events
    RESEARCH_COMPLETED = "research_completed"
    RESEARCH_FAILED = "research_failed"
    RESEARCH_QUEUED = "research_queued"

    # Subscription events
    SUBSCRIPTION_UPDATE = "subscription_update"
    SUBSCRIPTION_ERROR = "subscription_error"

    # System events
    RATE_LIMIT_WARNING = "rate_limit_warning"
    API_QUOTA_WARNING = "api_quota_warning"
    AUTH_ISSUE = "auth_issue"

    # Test event
    TEST = "test"


class NotificationTemplate:
    """
    Manages notification message templates using Jinja2.

    Uses Jinja2 templates for consistency with the rest of the project.
    Templates are stored in the notifications/templates/ directory.
    """

    # Map event types to template filenames
    TEMPLATE_FILES: Dict[EventType, str] = {
        EventType.RESEARCH_COMPLETED: "research_completed.jinja2",
        EventType.RESEARCH_FAILED: "research_failed.jinja2",
        EventType.RESEARCH_QUEUED: "research_queued.jinja2",
        EventType.SUBSCRIPTION_UPDATE: "subscription_update.jinja2",
        EventType.SUBSCRIPTION_ERROR: "subscription_error.jinja2",
        EventType.API_QUOTA_WARNING: "api_quota_warning.jinja2",
        EventType.AUTH_ISSUE: "auth_issue.jinja2",
        EventType.TEST: "test.jinja2",
    }

    # Shared Jinja2 environment for all template rendering
    _jinja_env: Optional[Environment] = None

    @classmethod
    def _get_jinja_env(cls) -> Environment:
        """
        Get or create the Jinja2 environment.

        Returns:
            Jinja2 Environment configured for notification templates
        """
        if cls._jinja_env is None:
            # Get the templates directory relative to this file
            template_dir = Path(__file__).parent / "templates"

            if not template_dir.exists():
                logger.warning(f"Templates directory not found: {template_dir}")
                # Fall back to simple string formatting
                return None

            try:
                cls._jinja_env = Environment(
                    loader=FileSystemLoader(template_dir),
                    autoescape=select_autoescape(["html", "xml"]),
                    trim_blocks=True,
                    lstrip_blocks=True,
                )
                logger.debug(
                    f"Jinja2 environment initialized with templates from: {template_dir}"
                )
            except Exception:
                logger.exception("Failed to initialize Jinja2 environment")
                return None

        return cls._jinja_env

    @classmethod
    def format(
        cls,
        event_type: EventType,
        context: Dict[str, Any],
        custom_template: Optional[Dict[str, str]] = None,
    ) -> Dict[str, str]:
        """
        Format a notification template with context data using Jinja2.

        Args:
            event_type: Type of event
            context: Context data for template formatting
            custom_template: Optional custom template override (still uses string format)

        Returns:
            Dict with 'title' and 'body' keys
        """
        # If custom template is provided, use the old string format for backward compatibility
        # Security: Sanitize context values to prevent format string attacks
        if custom_template:
            try:
                # Only allow simple string substitution - convert all values to strings
                # This prevents format string attacks like {query.__class__}
                safe_context = {
                    k: str(v) if v is not None else ""
                    for k, v in context.items()
                }
                title = custom_template["title"].format(**safe_context)
                body = custom_template["body"].format(**safe_context)
                return {"title": title, "body": body}
            except KeyError as e:
                return {
                    "title": f"Notification: {event_type.value}",
                    "body": f"Template error: Missing variable {e}",
                }

        # Get template filename for this event type
        template_file = cls.TEMPLATE_FILES.get(event_type)
        if not template_file:
            return {
                "title": f"Notification: {event_type.value}",
                "body": str(context),
            }

        # Try to render with Jinja2
        jinja_env = cls._get_jinja_env()
        if jinja_env is None:
            # Fallback to simple format if Jinja2 failed to initialize
            logger.warning(
                "Jinja2 not available, using fallback template format"
            )
            return cls._get_fallback_template(event_type, context)

        try:
            template = jinja_env.get_template(template_file)
            rendered_content = template.render(**context)

            # Parse the rendered content into title and body
            lines = rendered_content.strip().split("\n")
            title = lines[0].strip() if lines else "Notification"
            body = "\n".join(lines[1:]).strip() if len(lines) > 1 else ""

            return {"title": title, "body": body}
        except Exception:
            logger.exception(f"Error rendering Jinja2 template {template_file}")
            # Fall back to simple format
            return cls._get_fallback_template(event_type, context)

    @classmethod
    def _get_fallback_template(
        cls, event_type: EventType, context: Dict[str, Any]
    ) -> Dict[str, str]:
        """
        Get a simple fallback template when Jinja2 is not available.

        Args:
            event_type: Type of event
            context: Context data

        Returns:
            Dict with 'title' and 'body' keys
        """
        # Generic fallback that works for all event types
        # Reduces maintenance burden - no need to update for new events
        event_display_name = event_type.value.replace("_", " ").title()

        return {
            "title": f"Notification: {event_display_name}",
            "body": f"Event: {event_display_name}\n\nDetails: {str(context)}\n\nPlease check the application for complete information.",
        }

    @classmethod
    def get_required_context(cls, event_type: EventType) -> list[str]:
        """
        Get required context variables for an event type.

        Args:
            event_type: Type of event

        Returns:
            List of required variable names
        """
        template_file = cls.TEMPLATE_FILES.get(event_type)
        if not template_file:
            return []

        # Try to parse Jinja2 template to get variables
        jinja_env = cls._get_jinja_env()
        if jinja_env is None:
            # No Jinja2 environment available, return empty list
            # With simplified fallback approach, we don't need to track required variables
            return []

        try:
            template = jinja_env.get_template(template_file)
            # Get variables from the parsed Jinja2 template
            variables = set()
            if hasattr(template, "environment"):
                # Use Jinja2's meta module to find variables
                from jinja2 import meta

                template_source = template.environment.loader.get_source(
                    jinja_env, template_file
                )[0]
                ast = jinja_env.parse(template_source)
                variables = meta.find_undeclared_variables(ast)
            else:
                # Fallback: extract from template source
                template_source = template.environment.loader.get_source(
                    jinja_env, template_file
                )[0]
                import re

                variables.update(
                    re.findall(r"\{\{\s*(\w+)\s*\}\}", template_source)
                )

            return sorted(variables)
        except Exception:
            logger.exception(f"Error parsing Jinja2 template {template_file}")
            return []
