"""Generic webhook adapter with user-defined JSON path mappings.

Allows users to define custom JSON path mappings via the adapter_config
rather than a YAML file. Delegates all parsing logic to MappingAdapter.
"""

from typing import Any, ClassVar

from wled_controller.core.game_integration.base_adapter import GameAdapter
from wled_controller.core.game_integration.events import GameEvent
from wled_controller.core.game_integration.mapping_adapter import MappingAdapter
from wled_controller.utils import get_logger

logger = get_logger(__name__)


class GenericWebhookAdapter(GameAdapter):
    """Generic webhook adapter with user-defined JSON path mappings.

    Users configure mappings in the adapter_config field of their
    game integration config. The mappings follow the same format as
    MappingAdapter YAML files.
    """

    ADAPTER_TYPE: ClassVar[str] = "generic_webhook"
    DISPLAY_NAME: ClassVar[str] = "Generic Webhook"
    GAME_NAME: ClassVar[str] = "Any Game"
    SUPPORTED_EVENTS: ClassVar[list[str]] = []  # Dynamic based on mappings

    @classmethod
    def parse_payload(
        cls,
        payload: dict[str, Any],
        adapter_config: dict[str, Any],
        prev_state: dict[str, Any],
    ) -> tuple[list[GameEvent], dict[str, Any]]:
        """Parse a webhook payload using user-defined mappings.

        Delegates to a MappingAdapter instance built from adapter_config["mappings"].
        """
        mappings = adapter_config.get("mappings", [])
        if not mappings:
            return [], dict(prev_state)

        # Build a transient MappingAdapter from the config
        mapping_adapter = _build_mapping_adapter(adapter_config)

        return mapping_adapter.parse_payload(payload, adapter_config, prev_state)

    @classmethod
    def validate_auth(
        cls,
        headers: dict[str, str],
        payload: dict[str, Any],
        adapter_config: dict[str, Any],
    ) -> bool:
        """Validate auth using a configurable header token."""
        expected_token = adapter_config.get("auth_token")
        if not expected_token:
            # No auth configured
            return True

        auth_header = adapter_config.get("auth_header", "Authorization")
        actual_value = headers.get(auth_header, "")

        # Support "Bearer <token>" format
        if actual_value.startswith("Bearer "):
            actual_value = actual_value[7:]

        return bool(actual_value and actual_value == expected_token)

    @classmethod
    def get_config_schema(cls) -> dict[str, Any]:
        """Return generic webhook config schema."""
        return {
            "type": "object",
            "properties": {
                "auth_token": {
                    "type": "string",
                    "title": "Auth Token",
                    "description": "Optional token for authenticating incoming webhooks.",
                },
                "auth_header": {
                    "type": "string",
                    "title": "Auth Header",
                    "description": (
                        "HTTP header to check for auth token "
                        "(default: Authorization). Supports Bearer prefix."
                    ),
                    "default": "Authorization",
                },
                "mappings": {
                    "type": "array",
                    "title": "Event Mappings",
                    "description": "List of JSON path to event type mappings.",
                    "items": {
                        "type": "object",
                        "properties": {
                            "source_path": {
                                "type": "string",
                                "description": "Dot-notation path in JSON payload (e.g. player.health)",
                            },
                            "event": {
                                "type": "string",
                                "description": "Standard event type (e.g. health, kill, death)",
                            },
                            "min": {
                                "type": "number",
                                "description": "Minimum raw value for normalization (default: 0)",
                                "default": 0,
                            },
                            "max": {
                                "type": "number",
                                "description": "Maximum raw value for normalization (default: 100)",
                                "default": 100,
                            },
                            "trigger": {
                                "type": "string",
                                "description": "Trigger mode: on_change, on_increase, on_decrease, on_value",
                                "default": "on_change",
                                "enum": ["on_change", "on_increase", "on_decrease", "on_value"],
                            },
                        },
                        "required": ["source_path", "event"],
                    },
                },
            },
        }

    @classmethod
    def get_setup_instructions(cls) -> str:
        """Return generic webhook setup instructions."""
        return (
            "## Generic Webhook Setup\n\n"
            "Use this adapter to connect any game or application that can send "
            "HTTP POST requests with JSON payloads.\n\n"
            "**Steps:**\n"
            "1. Configure your event mappings above — map JSON paths to standard events\n"
            "2. Set an auth token (optional but recommended)\n"
            "3. Point your game/application to:\n"
            "   `POST http://<YOUR_IP>:8080/api/v1/game-integrations/<ID>/event`\n\n"
            "**Mapping example:**\n"
            "- Source path: `player.stats.health` → Event: `health` (min: 0, max: 100)\n"
            "- Source path: `events.kill_count` → Event: `kill` (trigger: on_increase)\n\n"
            "**Auth:**\n"
            "- Set `Authorization: Bearer <token>` header in your webhook sender\n"
            "- Or configure a custom auth header name in the adapter config\n"
        )


def _build_mapping_adapter(adapter_config: dict[str, Any]) -> MappingAdapter:
    """Build a MappingAdapter instance from adapter_config."""
    mappings = adapter_config.get("mappings", [])
    name = adapter_config.get("adapter_id", "generic_webhook")
    game = adapter_config.get("game_name", "Custom Game")

    auth: dict[str, Any] = {}
    if adapter_config.get("auth_token"):
        auth = {
            "type": "header",
            "header": adapter_config.get("auth_header", "Authorization"),
        }

    return MappingAdapter(
        {
            "name": name,
            "game": game,
            "protocol": "webhook",
            "mappings": mappings,
            "auth": auth,
        }
    )
