# 评论反垃圾和邮件通知工具
# 提供评论垃圾检测、频率限制和邮件通知功能

import hashlib
import logging
from datetime import timedelta
from django.core.cache import cache
from django.core.mail import send_mail, EmailMultiAlternatives
from django.template.loader import render_to_string
from django.utils.timezone import now
from django.conf import settings

logger = logging.getLogger(__name__)


# ==================== 反垃圾评论功能 ====================

class CommentSpamChecker:
    """评论垃圾检测器"""

    # 垃圾关键词列表（可从数据库或配置文件加载）
    SPAM_KEYWORDS = [
        '赌博', '博彩', '色情', '黄色', '成人',
        '代开发票', '办证', '贷款', '信用卡套现',
        '私服', '外挂', '刷钻', '代刷',
        '六合彩', '时时彩', '北京赛车',
        '免费领取', '点击领取', '加QQ', '加微信',
        'viagra', 'casino', 'poker', 'cialis',
    ]

    # 允许重复评论的最小间隔时间（秒）
    MIN_COMMENT_INTERVAL = 10

    # 单个用户每小时最大评论数
    MAX_COMMENTS_PER_HOUR = 20

    # 单个IP每小时最大评论数
    MAX_COMMENTS_PER_IP_HOUR = 30

    @classmethod
    def check_spam_keywords(cls, content):
        """
        检查评论内容是否包含垃圾关键词

        Args:
            content: 评论内容

        Returns:
            (bool, str): (是否包含垃圾词, 匹配到的关键词)
        """
        content_lower = content.lower()
        for keyword in cls.SPAM_KEYWORDS:
            if keyword.lower() in content_lower:
                return True, keyword
        return False, None

    @classmethod
    def check_duplicate(cls, user, content, article_id):
        """
        检查是否为重复评论

        Args:
            user: 用户对象
            content: 评论内容
            article_id: 文章ID

        Returns:
            bool: 是否为重复评论
        """
        # 生成内容哈希
        content_hash = hashlib.md5(content.encode('utf-8')).hexdigest()
        cache_key = f'comment_hash_{user.id}_{article_id}_{content_hash}'

        # 检查缓存中是否存在（5分钟内）
        if cache.get(cache_key):
            return True

        # 设置缓存标记（5分钟过期）
        cache.set(cache_key, '1', 300)
        return False

    @classmethod
    def check_rate_limit_user(cls, user):
        """
        检查用户评论频率限制

        Args:
            user: 用户对象

        Returns:
            (bool, str): (是否超过限制, 错误信息)
        """
        from comments.models import Comment

        # 检查最近一条评论的时间
        last_comment_key = f'user_last_comment_{user.id}'
        last_comment_time = cache.get(last_comment_key)

        if last_comment_time:
            time_diff = (now() - last_comment_time).total_seconds()
            if time_diff < cls.MIN_COMMENT_INTERVAL:
                wait_time = int(cls.MIN_COMMENT_INTERVAL - time_diff)
                return True, f'评论太频繁，请等待 {wait_time} 秒后再试'

        # 检查每小时评论数
        one_hour_ago = now() - timedelta(hours=1)
        hour_count = Comment.objects.filter(
            author=user,
            creation_time__gte=one_hour_ago
        ).count()

        if hour_count >= cls.MAX_COMMENTS_PER_HOUR:
            return True, f'您在1小时内发表评论过多，请稍后再试'

        # 更新最后评论时间
        cache.set(last_comment_key, now(), 3600)

        return False, None

    @classmethod
    def check_rate_limit_ip(cls, ip_address):
        """
        检查IP评论频率限制

        Args:
            ip_address: IP地址

        Returns:
            (bool, str): (是否超过限制, 错误信息)
        """
        # 检查IP是否在黑名单
        blacklist_key = f'ip_blacklist_{ip_address}'
        if cache.get(blacklist_key):
            return True, '您的IP已被限制评论'

        # 检查IP每小时评论数
        ip_count_key = f'ip_comment_count_{ip_address}'
        ip_count = cache.get(ip_count_key, 0)

        if ip_count >= cls.MAX_COMMENTS_PER_IP_HOUR:
            # 将IP加入黑名单（1小时）
            cache.set(blacklist_key, '1', 3600)
            return True, '该IP地址评论过于频繁，已被暂时限制'

        # 增加计数
        cache.set(ip_count_key, ip_count + 1, 3600)

        return False, None

    @classmethod
    def is_spam(cls, user, content, article_id, ip_address):
        """
        综合检查评论是否为垃圾评论

        Args:
            user: 用户对象
            content: 评论内容
            article_id: 文章ID
            ip_address: IP地址

        Returns:
            (bool, str): (是否为垃圾评论, 原因)
        """
        # 检查垃圾关键词
        has_spam, keyword = cls.check_spam_keywords(content)
        if has_spam:
            return True, f'评论包含敏感词: {keyword}'

        # 检查重复评论
        if cls.check_duplicate(user, content, article_id):
            return True, '请不要发表重复评论'

        # 检查用户频率限制
        is_limited, msg = cls.check_rate_limit_user(user)
        if is_limited:
            return True, msg

        # 检查IP频率限制
        is_limited, msg = cls.check_rate_limit_ip(ip_address)
        if is_limited:
            return True, msg

        return False, None


# ==================== 邮件通知功能 ====================

class CommentNotifier:
    """评论邮件通知器"""

    @classmethod
    def get_client_ip(cls, request):
        """获取客户端IP地址"""
        x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
        if x_forwarded_for:
            ip = x_forwarded_for.split(',')[0]
        else:
            ip = request.META.get('REMOTE_ADDR')
        return ip

    @classmethod
    def send_comment_notification(cls, comment, site_url=''):
        """
        发送评论通知邮件

        Args:
            comment: 评论对象
            site_url: 网站URL（可选）
        """
        try:
            # 通知文章作者
            if comment.article.author.email:
                cls._notify_article_author(comment, site_url)

            # 如果是回复评论，通知被回复者
            if comment.parent_comment and comment.parent_comment.author.email:
                cls._notify_parent_comment_author(comment, site_url)

            # 如果需要审核，通知管理员
            if not comment.is_enable:
                cls._notify_admin_for_review(comment, site_url)

        except Exception as e:
            logger.error(f"发送评论通知失败: {e}", exc_info=True)

    @classmethod
    def _notify_article_author(cls, comment, site_url):
        """通知文章作者有新评论"""
        # 不要通知自己
        if comment.author == comment.article.author:
            return

        subject = f'您的文章《{comment.article.title}》有新评论'
        article_url = site_url + comment.article.get_absolute_url()

        # 构建邮件内容
        context = {
            'comment': comment,
            'article': comment.article,
            'article_url': article_url,
            'site_url': site_url,
        }

        # 纯文本版本
        text_content = f"""
您好 {comment.article.author.username}，

您的文章《{comment.article.title}》收到了新评论：

评论者：{comment.author.username}
评论内容：
{comment.body}

查看评论：{article_url}#div-comment-{comment.id}

---
此邮件由系统自动发送，请勿回复。
        """.strip()

        # HTML版本（可以更美观）
        html_content = f"""
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <style>
        body {{ font-family: Arial, sans-serif; line-height: 1.6; color: #333; }}
        .container {{ max-width: 600px; margin: 0 auto; padding: 20px; }}
        .header {{ background-color: #4CAF50; color: white; padding: 10px 20px; border-radius: 5px; }}
        .content {{ background-color: #f9f9f9; padding: 20px; margin: 20px 0; border-left: 4px solid #4CAF50; }}
        .footer {{ color: #666; font-size: 12px; margin-top: 20px; }}
        a {{ color: #4CAF50; text-decoration: none; }}
        a:hover {{ text-decoration: underline; }}
    </style>
</head>
<body>
    <div class="container">
        <div class="header">
            <h2>新评论通知</h2>
        </div>
        <p>您好 {comment.article.author.username}，</p>
        <p>您的文章《<strong>{comment.article.title}</strong>》收到了新评论：</p>
        <div class="content">
            <p><strong>评论者：</strong>{comment.author.username}</p>
            <p><strong>评论内容：</strong></p>
            <p>{comment.body}</p>
        </div>
        <p><a href="{article_url}#div-comment-{comment.id}">点击查看评论</a></p>
        <div class="footer">
            <p>此邮件由系统自动发送，请勿回复。</p>
        </div>
    </div>
</body>
</html>
        """.strip()

        # 发送邮件
        msg = EmailMultiAlternatives(
            subject,
            text_content,
            settings.DEFAULT_FROM_EMAIL,
            [comment.article.author.email]
        )
        msg.attach_alternative(html_content, "text/html")
        msg.send(fail_silently=True)

        logger.info(f"已向文章作者 {comment.article.author.username} 发送评论通知")

    @classmethod
    def _notify_parent_comment_author(cls, comment, site_url):
        """通知被回复的评论作者"""
        # 不要通知自己
        if comment.author == comment.parent_comment.author:
            return

        # 如果父评论作者就是文章作者，已经通知过了
        if comment.parent_comment.author == comment.article.author:
            return

        subject = f'{comment.author.username} 回复了您的评论'
        article_url = site_url + comment.article.get_absolute_url()

        text_content = f"""
您好 {comment.parent_comment.author.username}，

{comment.author.username} 回复了您在文章《{comment.article.title}》中的评论：

您的评论：
{comment.parent_comment.body}

回复内容：
{comment.body}

查看回复：{article_url}#div-comment-{comment.id}

---
此邮件由系统自动发送，请勿回复。
        """.strip()

        html_content = f"""
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <style>
        body {{ font-family: Arial, sans-serif; line-height: 1.6; color: #333; }}
        .container {{ max-width: 600px; margin: 0 auto; padding: 20px; }}
        .header {{ background-color: #2196F3; color: white; padding: 10px 20px; border-radius: 5px; }}
        .content {{ background-color: #f9f9f9; padding: 20px; margin: 20px 0; border-left: 4px solid #2196F3; }}
        .reply {{ background-color: #e3f2fd; padding: 15px; margin-top: 10px; border-left: 4px solid #2196F3; }}
        .footer {{ color: #666; font-size: 12px; margin-top: 20px; }}
        a {{ color: #2196F3; text-decoration: none; }}
        a:hover {{ text-decoration: underline; }}
    </style>
</head>
<body>
    <div class="container">
        <div class="header">
            <h2>评论回复通知</h2>
        </div>
        <p>您好 {comment.parent_comment.author.username}，</p>
        <p><strong>{comment.author.username}</strong> 回复了您在文章《{comment.article.title}》中的评论：</p>
        <div class="content">
            <p><strong>您的评论：</strong></p>
            <p>{comment.parent_comment.body}</p>
        </div>
        <div class="reply">
            <p><strong>回复内容：</strong></p>
            <p>{comment.body}</p>
        </div>
        <p><a href="{article_url}#div-comment-{comment.id}">点击查看回复</a></p>
        <div class="footer">
            <p>此邮件由系统自动发送，请勿回复。</p>
        </div>
    </div>
</body>
</html>
        """.strip()

        msg = EmailMultiAlternatives(
            subject,
            text_content,
            settings.DEFAULT_FROM_EMAIL,
            [comment.parent_comment.author.email]
        )
        msg.attach_alternative(html_content, "text/html")
        msg.send(fail_silently=True)

        logger.info(f"已向评论者 {comment.parent_comment.author.username} 发送回复通知")

    @classmethod
    def _notify_admin_for_review(cls, comment, site_url):
        """通知管理员审核评论"""
        # 获取所有管理员邮箱
        from django.contrib.auth import get_user_model
        User = get_user_model()
        admin_emails = list(User.objects.filter(
            is_staff=True,
            is_active=True,
            email__isnull=False
        ).exclude(email='').values_list('email', flat=True))

        if not admin_emails:
            return

        subject = f'新评论待审核 - {comment.article.title}'
        article_url = site_url + comment.article.get_absolute_url()
        admin_url = site_url + '/admin/comments/comment/'

        text_content = f"""
管理员您好，

有新评论需要审核：

文章：《{comment.article.title}》
评论者：{comment.author.username}
评论时间：{comment.creation_time.strftime('%Y-%m-%d %H:%M:%S')}
评论内容：
{comment.body}

审核评论：{admin_url}{comment.id}/change/
查看文章：{article_url}

---
此邮件由系统自动发送，请勿回复。
        """.strip()

        html_content = f"""
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <style>
        body {{ font-family: Arial, sans-serif; line-height: 1.6; color: #333; }}
        .container {{ max-width: 600px; margin: 0 auto; padding: 20px; }}
        .header {{ background-color: #FF9800; color: white; padding: 10px 20px; border-radius: 5px; }}
        .content {{ background-color: #fff3e0; padding: 20px; margin: 20px 0; border-left: 4px solid #FF9800; }}
        .footer {{ color: #666; font-size: 12px; margin-top: 20px; }}
        a {{ color: #FF9800; text-decoration: none; }}
        a:hover {{ text-decoration: underline; }}
        .button {{ display: inline-block; padding: 10px 20px; background-color: #FF9800; color: white; border-radius: 5px; margin: 10px 5px; }}
    </style>
</head>
<body>
    <div class="container">
        <div class="header">
            <h2>新评论待审核</h2>
        </div>
        <p>管理员您好，</p>
        <p>有新评论需要审核：</p>
        <div class="content">
            <p><strong>文章：</strong>《{comment.article.title}》</p>
            <p><strong>评论者：</strong>{comment.author.username}</p>
            <p><strong>评论时间：</strong>{comment.creation_time.strftime('%Y-%m-%d %H:%M:%S')}</p>
            <p><strong>评论内容：</strong></p>
            <p>{comment.body}</p>
        </div>
        <p>
            <a href="{admin_url}{comment.id}/change/" class="button">审核评论</a>
            <a href="{article_url}" class="button">查看文章</a>
        </p>
        <div class="footer">
            <p>此邮件由系统自动发送，请勿回复。</p>
        </div>
    </div>
</body>
</html>
        """.strip()

        msg = EmailMultiAlternatives(
            subject,
            text_content,
            settings.DEFAULT_FROM_EMAIL,
            admin_emails
        )
        msg.attach_alternative(html_content, "text/html")
        msg.send(fail_silently=True)

        logger.info(f"已向 {len(admin_emails)} 位管理员发送审核通知")
