from django.core.exceptions import ValidationError
from django.db import models
from django.db.models import Q

from flower.common import ModelBase


class NotifierChannelEnum(models.TextChoices):
    WECOM_WEBHOOK = "wecom_webhook", "企业微信机器人"
    MESSAGE_API = "message_api", "消息发送 API"


class NotificationEventKeyEnum(models.TextChoices):
    MISSION_CREATED = "mission.created", "任务已创建"
    MISSION_REPLIED = "mission.replied", "任务有新回应"
    MISSION_COMPLETED = "mission.completed", "任务已完成"
    MISSION_UNREPLIED = "mission.unreplied", "任务未回复提醒"
    MISSION_REPLY_REJECTED = "mission.reply_rejected", "任务回应已撤销"
    MISSION_REOPENED = "mission.reopened", "任务已重新打开"
    MISSION_CANCELLED = "mission.cancelled", "任务已取消"


class Notifier(ModelBase):
    id = models.BigAutoField(primary_key=True)
    merchant = models.ForeignKey(
        "basic_info.Merchant",
        on_delete=models.PROTECT,
        related_name="notifiers",
        verbose_name="所属商户",
    )
    name = models.CharField(max_length=100, verbose_name="通知器名称")
    channel = models.CharField(
        max_length=50,
        choices=NotifierChannelEnum.choices,
        default=NotifierChannelEnum.WECOM_WEBHOOK,
        verbose_name="通知渠道",
    )
    template_key = models.CharField(max_length=100, verbose_name="模板标识")
    is_enabled = models.BooleanField(default=True, db_index=True, verbose_name="是否启用")
    config = models.JSONField(default=dict, blank=True, verbose_name="渠道配置")
    description = models.TextField(blank=True, null=True, verbose_name="备注描述")

    def get_template_name(self) -> str:
        suffix = "json" if self.channel == NotifierChannelEnum.MESSAGE_API else "md"
        return f"notifier/events/{self.template_key}.{suffix}"

    def get_config_value(self, key: str, default=None):
        config = self.config or {}
        return config.get(key, default)

    def __str__(self):
        return self.name

    class Meta:
        verbose_name = "通知器"
        verbose_name_plural = "通知器"
        constraints = [
            models.UniqueConstraint(fields=["merchant", "name"], name="unique_notifier_name_per_merchant"),
        ]
        indexes = [
            models.Index(fields=["merchant", "channel", "is_enabled"], name="notifier_no_merchan_532b51_idx"),
        ]


class NotifierRoute(ModelBase):
    id = models.BigAutoField(primary_key=True)
    merchant = models.ForeignKey(
        "basic_info.Merchant",
        on_delete=models.PROTECT,
        related_name="notifier_routes",
        verbose_name="所属商户",
    )
    notifier = models.ForeignKey(
        Notifier,
        on_delete=models.CASCADE,
        related_name="routes",
        verbose_name="通知器",
    )
    event_key = models.CharField(
        max_length=100,
        choices=NotificationEventKeyEnum.choices,
        db_index=True,
        verbose_name="事件标识",
    )
    mission_category = models.ForeignKey(
        "mission.MissionCategory",
        on_delete=models.PROTECT,
        related_name="notifier_routes",
        null=True,
        blank=True,
        verbose_name="任务分类路由",
        help_text="为空时表示该事件的通配路由",
    )
    is_enabled = models.BooleanField(default=True, db_index=True, verbose_name="是否启用")
    description = models.TextField(blank=True, null=True, verbose_name="备注描述")

    def clean(self):
        errors = {}
        if self.notifier_id and self.merchant_id and self.notifier.merchant_id != self.merchant_id:
            errors["merchant"] = "路由所属商户必须与通知器所属商户一致"
        if self.mission_category_id and self.merchant_id and self.mission_category.merchant_id != self.merchant_id:
            errors["mission_category"] = "任务分类必须属于当前路由商户"
        if errors:
            raise ValidationError(errors)

    def __str__(self):
        category_name = self.mission_category.name if self.mission_category_id else "全部分类"
        return f"{self.notifier.name} -> {self.event_key} [{category_name}]"

    class Meta:
        verbose_name = "通知路由"
        verbose_name_plural = "通知路由"
        constraints = [
            models.UniqueConstraint(
                fields=["notifier", "event_key", "mission_category"],
                name="unique_notifier_route_per_scope",
            ),
            models.UniqueConstraint(
                fields=["notifier", "event_key"],
                condition=Q(mission_category__isnull=True),
                name="unique_notifier_route_global_scope",
            ),
        ]
        indexes = [
            models.Index(fields=["merchant", "event_key", "is_enabled"], name="notifier_no_merchan_58d463_idx"),
            models.Index(fields=["merchant", "mission_category", "is_enabled"], name="notifier_no_merchan_14b7f6_idx"),
        ]
