import _thread
import logging

import django.dispatch
from django.conf import settings
from django.contrib.admin.models import LogEntry
from django.contrib.auth.signals import user_logged_in, user_logged_out
from django.core.mail import EmailMultiAlternatives
from django.db.models.signals import post_save
from django.dispatch import receiver

from ..comments.models import Comment
from ..comments.utils import send_comment_email
from ..djangoblog.spider_notify import SpiderNotify
from ..djangoblog.utils import cache, expire_view_cache, delete_sidebar_cache, delete_view_cache
from ..djangoblog.utils import get_current_site
from ..oauth.models import OAuthUser

# 获取当前模块的日志记录器，用于记录信号处理过程中的运行信息和错误
logger = logging.getLogger(__name__)

# 自定义信号：OAuth 用户登录信号
# 用于在 OAuth 用户登录成功后触发特定逻辑（如头像处理、缓存清理）
# 参数：id - OAuthUser 对象的数据库 ID
oauth_user_login_signal = django.dispatch.Signal(['id'])

# 自定义信号：发送邮件信号
# 用于解耦邮件发送逻辑，其他模块可通过触发此信号来请求发送邮件
# 参数：
#   - emailto: 收件人邮箱列表
#   - title: 邮件标题
#   - content: 邮件正文（HTML）
send_email_signal = django.dispatch.Signal(['emailto', 'title', 'content'])

#wwc
@receiver(send_email_signal)
def send_email_signal_handler(sender, **kwargs):
    """
    处理「发送邮件」信号的回调函数。

    当系统中触发 send_email_signal 时，Django 会调用此函数发送实际邮件，
    并将发送结果记录到数据库日志中。

    参数:
        sender: 发送信号的对象（通常不使用）
        **kwargs: 信号传递的参数，包含 emailto, title, content

    流程:
        1. 从 kwargs 中提取邮件信息
        2. 创建 EmailMultiAlternatives 对象（支持 HTML 邮件）
        3. 记录邮件发送日志（EmailSendLog）
        4. 尝试发送邮件，捕获异常并记录结果
        5. 保存日志到数据库
    """
    emailto = kwargs['emailto']
    title = kwargs['title']
    content = kwargs['content']

    # 创建支持 HTML 内容的邮件对象
    msg = EmailMultiAlternatives(
        title,
        content,
        from_email=settings.DEFAULT_FROM_EMAIL,
        to=emailto)
    msg.content_subtype = "html"  # 设置内容类型为 HTML

    # 创建邮件发送日志对象
    from ..servermanager.models import EmailSendLog
    log = EmailSendLog()
    log.title = title
    log.content = content
    log.emailto = ','.join(emailto)  # 将邮箱列表转为逗号分隔字符串

    try:
        # 发送邮件，返回值为成功发送的邮件数量
        result = msg.send()
        log.send_result = result > 0  # 成功发送至少一封即为成功
    except Exception as e:
        # 发送失败时记录错误日志，并标记发送结果为失败
        logger.error(f"失败邮箱号: {emailto}, {e}")
        log.send_result = False
    # 无论成功或失败，都保存日志记录
    log.save()

#wwc
@receiver(oauth_user_login_signal)
def oauth_user_login_signal_handler(sender, **kwargs):
    """
    处理「OAuth 用户登录」信号的回调函数。

    当 OAuth 用户登录成功后触发，主要执行：
        1. 检查并处理用户头像 URL（确保为本站域名）
        2. 清理侧边栏缓存（确保显示最新信息）

    参数:
        sender: 发送信号的对象
        **kwargs: 包含 id（OAuthUser 的主键）
    """
    id = kwargs['id']
    oauthuser = OAuthUser.objects.get(id=id)
    site = get_current_site().domain

    # 如果用户头像 URL 不包含当前站点域名，则重新保存头像
    # 防止外链失效，提升稳定性
    if oauthuser.picture and not oauthuser.picture.find(site) >= 0:
        from djangoblog.utils import save_user_avatar
        oauthuser.picture = save_user_avatar(oauthuser.picture)
        oauthuser.save()

    # 登录后清理侧边栏缓存，确保用户信息等显示最新状态
    delete_sidebar_cache()

#wwc
@receiver(post_save)
def model_post_save_callback(
        sender,
        instance,
        created,
        raw,
        using,
        update_fields,
        **kwargs):
    """
    全局模型保存后信号处理器。
    监听所有模型的 post_save 信号，根据保存的模型类型执行相应逻辑。

    主要功能：
        1. 文章/页面更新时通知搜索引擎（百度主动推送）
        2. 评论发布时清理相关缓存并发送邮件通知
        3. 特定模型更新后清理缓存

    参数:
        sender: 保存的模型类
        instance: 保存的模型实例
        created: 是否为新建对象（True=新增，False=更新）
        raw: 是否为原始数据导入（如 loaddata）
        using: 使用的数据库别名
        update_fields: 本次保存更新的字段集合（可选）
        **kwargs: 其他参数

    注意：LogEntry 的保存不触发此逻辑，避免无限循环。
    """
    clearcache = False  # 标记是否需要清理缓存

    # 如果保存的是管理日志（LogEntry），直接返回，避免性能问题或循环触发
    if isinstance(instance, LogEntry):
        return

    # 如果该模型实现了 get_full_url 方法（如文章、页面等）
    if 'get_full_url' in dir(instance):
        # 检查是否仅更新了 'views' 字段（阅读量）
        is_update_views = update_fields == {'views'}
        # 非测试环境且非阅读量更新时，向百度推送 URL
        if not settings.TESTING and not is_update_views:
            try:
                notify_url = instance.get_full_url()
                SpiderNotify.baidu_notify([notify_url])
            except Exception as ex:
                logger.error("notify spider", ex)
        # 除非是更新阅读量，否则标记需要清理缓存
        if not is_update_views:
            clearcache = True

    # 如果保存的是评论模型，且评论已启用
    if isinstance(instance, Comment):
        if instance.is_enable:
            path = instance.article.get_absolute_url()
            site = get_current_site().domain
            if site.find(':') > 0:
                site = site[0:site.find(':')]  # 去除端口号

            # 清理文章详情页缓存
            expire_view_cache(
                path,
                servername=site,
                serverport=80,
                key_prefix='blogdetail')

            # 清理 SEO 缓存
            if cache.get('seo_processor'):
                cache.delete('seo_processor')

            # 清理文章评论缓存
            comment_cache_key = 'article_comments_{id}'.format(id=instance.article.id)
            cache.delete(comment_cache_key)

            # 清理侧边栏缓存
            delete_sidebar_cache()

            # 清理评论列表视图缓存
            delete_view_cache('article_comments', [str(instance.article.pk)])

            # 在新线程中发送评论通知邮件，避免阻塞主线程
            _thread.start_new_thread(send_comment_email, (instance,))

    # 如果标记需要清理缓存，则执行全站缓存清理
    if clearcache:
        cache.clear()

#wwc
@receiver(user_logged_in)
@receiver(user_logged_out)
def user_auth_callback(sender, request, user, **kwargs):
    """
    用户登录/登出信号处理器。
    当用户登录或登出时触发，用于清理与用户状态相关的缓存。

    目前主要功能：
        - 清理侧边栏缓存（如登录状态、用户信息等）

    参数:
        sender: User 模型
        request: 当前请求对象
        user: 用户对象
        **kwargs: 其他参数
    """
    if user and user.username:
        logger.info(user)  # 记录登录/登出的用户名
        delete_sidebar_cache()  # 清理侧边栏缓存，确保显示正确的登录状态
        # cache.clear()  # 当前注释，避免过度清理