#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
报警通知模块
功能：
1. 多通道报警通知（邮件/企业微信/飞书）
2. 分级报警策略
3. 失败重试机制
"""

import smtplib
import json
import requests
from email.mime.text import MIMEText
from typing import Optional, Dict, List
import logging
from dataclasses import dataclass
from tenacity import retry, stop_after_attempt, wait_exponential

# 日志配置
logger = logging.getLogger('alert')
logger.setLevel(logging.INFO)

@dataclass
class AlertConfig:
    """报警配置数据类"""
    email: Dict[str, str] = None       # SMTP配置
    wecom: Dict[str, str] = None       # 企业微信机器人配置
    feishu: Dict[str, str] = None      # 飞书机器人配置
    min_level: str = 'WARNING'        # 默认最低报警级别

class AlertService:
    def __init__(self, config: AlertConfig):
        """
        初始化报警服务
        参数：
            config: AlertConfig对象
        """
        self.config = config
        self.levels = {
            'DEBUG': 0,
            'INFO': 1,
            'WARNING': 2,
            'ERROR': 3,
            'CRITICAL': 4
        }

    @retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=4, max=10))
    def send_email(self, subject: str, content: str, to_addrs: List[str]) -> bool:
        """
        发送邮件报警
        参数：
            subject: 邮件主题
            content: 邮件内容(支持HTML)
            to_addrs: 收件人列表
        返回：
            发送是否成功
        """
        if not self.config.email:
            logger.warning("邮件配置未启用")
            return False

        try:
            msg = MIMEText(content, 'html', 'utf-8')
            msg['From'] = self.config.email['from_addr']
            msg['To'] = ','.join(to_addrs)
            msg['Subject'] = subject

            with smtplib.SMTP_SSL(
                    host=self.config.email['smtp_server'],
                    port=self.config.email['smtp_port']
            ) as server:
                server.login(
                    user=self.config.email['username'],
                    password=self.config.email['password']
                )
                server.send_message(msg)

            logger.info(f"邮件报警发送成功 -> {to_addrs}")
            return True
        except Exception as e:
            logger.error(f"邮件发送失败: {str(e)}")
            raise

    @retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=4, max=10))
    def send_wecom(self, content: str, mentioned_list: List[str] = None) -> bool:
        """
        发送企业微信机器人通知
        参数：
            content: 消息内容(支持Markdown)
            mentioned_list: 要@的成员手机号列表
        返回：
            发送是否成功
        """
        if not self.config.wecom:
            logger.warning("企业微信配置未启用")
            return False

        try:
            payload = {
                "msgtype": "markdown",
                "markdown": {
                    "content": content,
                }
            }
            if mentioned_list:
                payload["mentioned_mobile_list"] = mentioned_list

            resp = requests.post(
                url=self.config.wecom['webhook_url'],
                headers={'Content-Type': 'application/json'},
                data=json.dumps(payload),
                timeout=5
            )
            resp.raise_for_status()

            logger.info("企业微信报警发送成功")
            return True
        except Exception as e:
            logger.error(f"企业微信发送失败: {str(e)}")
            raise

    @retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=4, max=10))
    def send_feishu(self, title: str, content: str) -> bool:
        """
        发送飞书机器人通知
        参数：
            title: 消息标题
            content: 消息内容(支持Markdown)
        返回：
            发送是否成功
        """
        if not self.config.feishu:
            logger.warning("飞书配置未启用")
            return False

        try:
            payload = {
                "msg_type": "interactive",
                "card": {
                    "header": {
                        "title": {
                            "tag": "plain_text",
                            "content": title
                        },
                        "template": "red"  # 红色标题表示报警
                    },
                    "elements": [{
                        "tag": "markdown",
                        "content": content
                    }]
                }
            }

            resp = requests.post(
                url=self.config.feishu['webhook_url'],
                headers={'Content-Type': 'application/json'},
                data=json.dumps(payload),
                timeout=5
            )
            resp.raise_for_status()

            logger.info("飞书报警发送成功")
            return True
        except Exception as e:
            logger.error(f"飞书发送失败: {str(e)}")
            raise

    def send_alert(self, level: str, title: str, content: str) -> bool:
        """
        分级发送报警通知
        参数：
            level: 报警级别(DEBUG/INFO/WARNING/ERROR/CRITICAL)
            title: 报警标题
            content: 报警详情
        返回：
            是否发送成功(至少一个通道成功)
        """
        if self.levels[level] < self.levels[self.config.min_level]:
            logger.debug(f"忽略低于阈值的报警: {level} < {self.config.min_level}")
            return False

        results = []
        if self.config.email:
            email_content = f"""
            <h2>{title}</h2>
            <p>报警级别: <strong>{level}</strong></p>
            <pre>{content}</pre>
            """
            results.append(
                self.send_email(
                    subject=f"[{level}] {title}",
                    content=email_content,
                    to_addrs=self.config.email['receivers']
                )
            )

        if self.config.wecom:
            wecom_content = f"## {title}\n**级别**: {level}\n```\n{content}\n```"
            results.append(self.send_wecom(wecom_content))

        if self.config.feishu:
            feishu_content = f"**级别**: {level}\n\n{content}"
            results.append(self.send_feishu(title, feishu_content))

        return any(results)

# 配置示例
if __name__ == "__main__":
    # 初始化配置
    config = AlertConfig(
        email={
            'smtp_server': 'smtp.example.com',
            'smtp_port': 465,
            'username': 'alert@example.com',
            'password': 'your_password',
            'from_addr': 'alert@example.com',
            'receivers': ['admin@example.com']
        },
        wecom={
            'webhook_url': 'https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=your_key'
        },
        feishu={
            'webhook_url': 'https://open.feishu.cn/open-apis/bot/v2/hook/your_token'
        },
        min_level='ERROR'
    )

    # 使用示例
    alert = AlertService(config)

    # 发送测试报警
    alert.send_alert(
        level='ERROR',
        title='数据库连接失败',
        content='无法连接到MySQL服务器，已重试3次\n主机: 192.168.1.100:3306'
    )