"""
Callback configuration system for FSM state transitions.

This module provides centralized configuration for all FSM transition callbacks,
including enable/disable settings, priorities, and environment-specific overrides.
"""

import logging
from dataclasses import dataclass, field
from typing import Any

from django.conf import settings
from django.db import models

logger = logging.getLogger(__name__)


@dataclass
class TransitionCallbackConfig:
    """Configuration for callbacks on a specific transition."""

    notifications_enabled: bool = True
    cache_invalidation_enabled: bool = True
    related_updates_enabled: bool = True
    notification_template: str | None = None
    cache_patterns: list[str] = field(default_factory=list)
    priority: int = 100
    extra_data: dict[str, Any] = field(default_factory=dict)


@dataclass
class ModelCallbackConfig:
    """Configuration for all callbacks on a model."""

    model_name: str
    field_name: str = "status"
    transitions: dict[tuple, TransitionCallbackConfig] = field(default_factory=dict)
    default_config: TransitionCallbackConfig = field(default_factory=TransitionCallbackConfig)


class CallbackConfig:
    """
    Centralized configuration for all FSM transition callbacks.

    Provides settings for:
    - Enabling/disabling callback types globally or per-transition
    - Configuring notification templates
    - Setting cache invalidation patterns
    - Defining callback priorities

    Configuration can be overridden via Django settings.
    """

    # Default settings
    DEFAULT_SETTINGS = {
        "enabled": True,
        "notifications_enabled": True,
        "cache_invalidation_enabled": True,
        "related_updates_enabled": True,
        "debug_mode": False,
        "log_callbacks": False,
    }

    # Model-specific configurations
    MODEL_CONFIGS: dict[str, ModelCallbackConfig] = {}

    def __init__(self):
        self._settings = self._load_settings()
        self._model_configs = self._build_model_configs()

    def _load_settings(self) -> dict[str, Any]:
        """Load settings from Django configuration."""
        django_settings = getattr(settings, "STATE_MACHINE_CALLBACKS", {})
        merged = dict(self.DEFAULT_SETTINGS)
        merged.update(django_settings)
        return merged

    def _build_model_configs(self) -> dict[str, ModelCallbackConfig]:
        """Build model-specific configurations."""
        return {
            "EditSubmission": ModelCallbackConfig(
                model_name="EditSubmission",
                field_name="status",
                transitions={
                    ("PENDING", "APPROVED"): TransitionCallbackConfig(
                        notification_template="submission_approved",
                        cache_patterns=["*submission*", "*moderation*"],
                    ),
                    ("PENDING", "REJECTED"): TransitionCallbackConfig(
                        notification_template="submission_rejected",
                        cache_patterns=["*submission*", "*moderation*"],
                    ),
                    ("PENDING", "ESCALATED"): TransitionCallbackConfig(
                        notification_template="submission_escalated",
                        cache_patterns=["*submission*", "*moderation*"],
                    ),
                },
            ),
            "PhotoSubmission": ModelCallbackConfig(
                model_name="PhotoSubmission",
                field_name="status",
                transitions={
                    ("PENDING", "APPROVED"): TransitionCallbackConfig(
                        notification_template="photo_approved",
                        cache_patterns=["*photo*", "*moderation*"],
                    ),
                    ("PENDING", "REJECTED"): TransitionCallbackConfig(
                        notification_template="photo_rejected",
                        cache_patterns=["*photo*", "*moderation*"],
                    ),
                },
            ),
            "ModerationReport": ModelCallbackConfig(
                model_name="ModerationReport",
                field_name="status",
                transitions={
                    ("PENDING", "UNDER_REVIEW"): TransitionCallbackConfig(
                        notification_template="report_under_review",
                        cache_patterns=["*report*", "*moderation*"],
                    ),
                    ("UNDER_REVIEW", "RESOLVED"): TransitionCallbackConfig(
                        notification_template="report_resolved",
                        cache_patterns=["*report*", "*moderation*"],
                    ),
                },
            ),
            "ModerationQueue": ModelCallbackConfig(
                model_name="ModerationQueue",
                field_name="status",
                transitions={
                    ("PENDING", "IN_PROGRESS"): TransitionCallbackConfig(
                        notification_template="queue_in_progress",
                        cache_patterns=["*queue*", "*moderation*"],
                    ),
                    ("IN_PROGRESS", "COMPLETED"): TransitionCallbackConfig(
                        notification_template="queue_completed",
                        cache_patterns=["*queue*", "*moderation*"],
                    ),
                },
            ),
            "BulkOperation": ModelCallbackConfig(
                model_name="BulkOperation",
                field_name="status",
                transitions={
                    ("PENDING", "RUNNING"): TransitionCallbackConfig(
                        notification_template="bulk_operation_started",
                        cache_patterns=["*operation*", "*moderation*"],
                    ),
                    ("RUNNING", "COMPLETED"): TransitionCallbackConfig(
                        notification_template="bulk_operation_completed",
                        cache_patterns=["*operation*", "*moderation*"],
                    ),
                    ("RUNNING", "FAILED"): TransitionCallbackConfig(
                        notification_template="bulk_operation_failed",
                        cache_patterns=["*operation*", "*moderation*"],
                    ),
                },
            ),
            "Park": ModelCallbackConfig(
                model_name="Park",
                field_name="status",
                default_config=TransitionCallbackConfig(
                    cache_patterns=["*park*", "api:*", "geo:*"],
                ),
                transitions={
                    ("*", "CLOSED_PERM"): TransitionCallbackConfig(
                        notifications_enabled=True,
                        notification_template="park_closed_permanently",
                        cache_patterns=["*park*", "api:*", "geo:*"],
                    ),
                    ("*", "OPERATING"): TransitionCallbackConfig(
                        notifications_enabled=False,
                        cache_patterns=["*park*", "api:*", "geo:*"],
                    ),
                },
            ),
            "Ride": ModelCallbackConfig(
                model_name="Ride",
                field_name="status",
                default_config=TransitionCallbackConfig(
                    cache_patterns=["*ride*", "*park*", "api:*", "geo:*"],
                ),
                transitions={
                    ("*", "OPERATING"): TransitionCallbackConfig(
                        cache_patterns=["*ride*", "*park*", "api:*", "geo:*"],
                        related_updates_enabled=True,
                    ),
                    ("*", "CLOSED_PERM"): TransitionCallbackConfig(
                        cache_patterns=["*ride*", "*park*", "api:*", "geo:*"],
                        related_updates_enabled=True,
                    ),
                    ("*", "DEMOLISHED"): TransitionCallbackConfig(
                        cache_patterns=["*ride*", "*park*", "api:*", "geo:*"],
                        related_updates_enabled=True,
                    ),
                    ("*", "RELOCATED"): TransitionCallbackConfig(
                        cache_patterns=["*ride*", "*park*", "api:*", "geo:*"],
                        related_updates_enabled=True,
                    ),
                },
            ),
        }

    @property
    def enabled(self) -> bool:
        """Check if callbacks are globally enabled."""
        return self._settings.get("enabled", True)

    @property
    def notifications_enabled(self) -> bool:
        """Check if notification callbacks are enabled."""
        return self._settings.get("notifications_enabled", True)

    @property
    def cache_invalidation_enabled(self) -> bool:
        """Check if cache invalidation is enabled."""
        return self._settings.get("cache_invalidation_enabled", True)

    @property
    def related_updates_enabled(self) -> bool:
        """Check if related model updates are enabled."""
        return self._settings.get("related_updates_enabled", True)

    @property
    def debug_mode(self) -> bool:
        """Check if debug mode is enabled."""
        return self._settings.get("debug_mode", False)

    @property
    def log_callbacks(self) -> bool:
        """Check if callback logging is enabled."""
        return self._settings.get("log_callbacks", False)

    def get_config(
        self,
        model_name: str,
        source: str,
        target: str,
    ) -> TransitionCallbackConfig:
        """
        Get configuration for a specific transition.

        Args:
            model_name: Name of the model.
            source: Source state.
            target: Target state.

        Returns:
            TransitionCallbackConfig for the transition.
        """
        model_config = self._model_configs.get(model_name)
        if not model_config:
            return TransitionCallbackConfig()

        # Try exact match first
        config = model_config.transitions.get((source, target))
        if config:
            return config

        # Try wildcard source
        config = model_config.transitions.get(("*", target))
        if config:
            return config

        # Try wildcard target
        config = model_config.transitions.get((source, "*"))
        if config:
            return config

        # Return default config
        return model_config.default_config

    def is_notification_enabled(
        self,
        model_name: str,
        source: str,
        target: str,
    ) -> bool:
        """Check if notifications are enabled for a transition."""
        if not self.enabled or not self.notifications_enabled:
            return False

        config = self.get_config(model_name, source, target)
        return config.notifications_enabled

    def is_cache_invalidation_enabled(
        self,
        model_name: str,
        source: str,
        target: str,
    ) -> bool:
        """Check if cache invalidation is enabled for a transition."""
        if not self.enabled or not self.cache_invalidation_enabled:
            return False

        config = self.get_config(model_name, source, target)
        return config.cache_invalidation_enabled

    def is_related_updates_enabled(
        self,
        model_name: str,
        source: str,
        target: str,
    ) -> bool:
        """Check if related updates are enabled for a transition."""
        if not self.enabled or not self.related_updates_enabled:
            return False

        config = self.get_config(model_name, source, target)
        return config.related_updates_enabled

    def get_cache_patterns(
        self,
        model_name: str,
        source: str,
        target: str,
    ) -> list[str]:
        """Get cache invalidation patterns for a transition."""
        config = self.get_config(model_name, source, target)
        return config.cache_patterns

    def get_notification_template(
        self,
        model_name: str,
        source: str,
        target: str,
    ) -> str | None:
        """Get notification template for a transition."""
        config = self.get_config(model_name, source, target)
        return config.notification_template

    def register_model_config(
        self,
        model_class: type[models.Model],
        config: ModelCallbackConfig,
    ) -> None:
        """
        Register a custom model configuration.

        Args:
            model_class: The model class.
            config: The configuration to register.
        """
        model_name = model_class.__name__
        self._model_configs[model_name] = config
        logger.debug(f"Registered callback config for {model_name}")

    def update_transition_config(
        self,
        model_name: str,
        source: str,
        target: str,
        **kwargs,
    ) -> None:
        """
        Update configuration for a specific transition.

        Args:
            model_name: Name of the model.
            source: Source state.
            target: Target state.
            **kwargs: Configuration values to update.
        """
        if model_name not in self._model_configs:
            self._model_configs[model_name] = ModelCallbackConfig(model_name=model_name)

        model_config = self._model_configs[model_name]
        transition_key = (source, target)

        if transition_key not in model_config.transitions:
            model_config.transitions[transition_key] = TransitionCallbackConfig()

        config = model_config.transitions[transition_key]

        for key, value in kwargs.items():
            if hasattr(config, key):
                setattr(config, key, value)

    def reload_settings(self) -> None:
        """Reload settings from Django configuration."""
        self._settings = self._load_settings()
        logger.debug("Reloaded callback configuration settings")


# Global configuration instance
callback_config = CallbackConfig()


def get_callback_config() -> CallbackConfig:
    """Get the global callback configuration instance."""
    return callback_config


__all__ = [
    "TransitionCallbackConfig",
    "ModelCallbackConfig",
    "CallbackConfig",
    "callback_config",
    "get_callback_config",
]
