"""Third-party connector foundation for the Helpdesk module.

Provides a registry-based architecture for integrating external systems
(Slack, Telegram, WhatsApp, MS Teams, etc.) with the helpdesk.

Models
------
``ConnectorConfig`` — Tenant-scoped configuration for one connector instance.
  Stores credentials, target channel mapping, and enabled status.

Registry
--------
``ConnectorRegistry`` — Maps ``connector_type`` (e.g. "slack", "telegram")
  to a handler callable that knows how to send messages / process commands.

Built-in connectors can be registered in downstream modules or via the
``register`` / ``unregister`` methods.
"""

from __future__ import annotations

from typing import Any, ClassVar

from django.conf import settings
from django.db import models
from django.utils.translation import gettext_lazy as _

from simorgh.core.models import TenantScopedModel, TimeStampedModel, UUIDModel


class ConnectorConfig(UUIDModel, TenantScopedModel, TimeStampedModel):
    """Tenant-scoped configuration for one external channel connector."""

    CONNECTOR_TYPES: ClassVar = [
        ("slack", "Slack"),
        ("telegram", "Telegram"),
        ("whatsapp", "WhatsApp"),
        ("msteams", "Microsoft Teams"),
        ("discord", "Discord"),
        ("custom", "Custom"),
    ]

    connector_type = models.CharField(
        _("connector type"),
        max_length=32,
        choices=CONNECTOR_TYPES,
        db_index=True,
    )
    name = models.CharField(_("name"), max_length=128)
    description = models.TextField(_("description"), blank=True, default="")
    is_active = models.BooleanField(_("is active"), default=True, db_index=True)

    target_queue = models.ForeignKey(
        "helpdesk.Queue",
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="connectors",
        verbose_name=_("target queue"),
        help_text=_("Queue where tickets from this connector will land."),
    )

    config = models.JSONField(
        _("configuration"),
        default=dict,
        blank=True,
        help_text=_(
            "Connector-specific configuration dict.  Keys vary per connector_type: "
            "slack → bot_token, signing_secret, channel_id.  "
            "telegram → bot_token, chat_id.  "
            "custom → arbitrary key-value pairs."
        ),
    )

    class Meta:
        verbose_name = _("connector config")
        verbose_name_plural = _("connector configs")
        ordering = ("connector_type", "name")
        indexes: ClassVar = [
            models.Index(fields=("tenant", "connector_type", "is_active")),
        ]

    def __str__(self) -> str:
        return f"{self.connector_type}: {self.name}"


class ConnectorRegistry:
    """Registry mapping connector_type → handler callable.

    Handlers receive a ``ConnectorConfig`` instance and an action dict with:
      - ``action``: "send_message", "create_ticket", etc.
      - ``params``: dict of action-specific parameters.

    Returns a dict with at least a ``success`` bool.
    """

    def __init__(self) -> None:
        self._handlers: dict[str, Any] = {}

    def register(self, connector_type: str, handler: Any) -> None:
        if connector_type in self._handlers:
            raise ValueError(f"Connector handler for '{connector_type}' already registered.")
        self._handlers[connector_type] = handler

    def unregister(self, connector_type: str) -> None:
        self._handlers.pop(connector_type, None)

    def get(self, connector_type: str) -> Any | None:
        return self._handlers.get(connector_type)

    def execute(self, connector_type: str, config: ConnectorConfig, action: dict) -> dict:
        handler = self.get(connector_type)
        if handler is None:
            return {"success": False, "error": f"No handler registered for '{connector_type}'."}
        try:
            return handler(config, action)
        except Exception as exc:
            return {"success": False, "error": str(exc)}

    def list_types(self) -> list[str]:
        return sorted(self._handlers)


connector_registry = ConnectorRegistry()
