from django.test import Client, RequestFactory, TransactionTestCase
from django.urls import reverse

from accounts.models import BlogUser
from blog.models import Category, Article
from comments.models import Comment
from comments.templatetags.comments_tags import *
from djangoblog.utils import get_max_articleid_commentid


# Create your tests here.

# 定义一个基于事务的测试用例类，用于测试 comments 应用的相关功能
class CommentsTest(TransactionTestCase):
    def setUp(self):
        # 创建 Django 测试客户端，用于模拟用户请求
        self.client = Client()

        # 创建请求工厂，用于在视图测试中构造请求对象
        self.factory = RequestFactory()

        # 导入博客设置模型（由于导入在方法内，可能为了延迟加载或避免循环导入）
        from blog.models import BlogSettings

        # 创建一个博客全局设置实例
        value = BlogSettings()
        # 设置评论需要审核（即新评论默认不显示，需管理员启用）
        value.comment_need_review = True
        # 保存到数据库
        value.save()

        # 创建一个超级用户，用于登录和发表评论
        self.user = BlogUser.objects.create_superuser(
            email="liangliangyy1@gmail.com",
            username="liangliangyy1",
            password="liangliangyy1")

    def update_article_comment_status(self, article):
        # 获取该文章的所有评论
        comments = article.comment_set.all()
        for comment in comments:
            comment.is_enable = True  # 启用评论
            comment.save()  # 保存更改

    def test_validate_comment(self):
        # 使用测试用户登录（确保有权限发表评论）
        self.client.login(username='liangliangyy1', password='liangliangyy1')

        # 创建文章分类
        category = Category()
        category.name = "categoryccc"
        category.save()

        # 创建一篇文章
        article = Article()
        article.title = "nicetitleccc"
        article.body = "nicecontentccc"
        article.author = self.user
        article.category = category
        article.type = 'a'  # 普通文章类型
        article.status = 'p'  # 已发布状态
        article.save()

        # 反向解析获取评论提交的 URL（根据命名空间和参数）
        comment_url = reverse(
            'comments:postcomment', kwargs={
                'article_id': article.id})

        # 模拟 POST 请求发表第一条评论
        response = self.client.post(comment_url,
                                    {
                                        'body': '123ffffffffff'
                                    })

        # 断言：响应状态码应为 302（重定向），表示评论提交成功
        self.assertEqual(response.status_code, 302)

        # 重新获取文章对象（刷新数据）
        article = Article.objects.get(pk=article.pk)
        # 此时评论未审核，comment_list() 返回的可见评论数应为 0
        self.assertEqual(len(article.comment_list()), 0)

        # 手动启用该评论（模拟审核通过）
        self.update_article_comment_status(article)
        # 此时可见评论数应为 1
        self.assertEqual(len(article.comment_list()), 1)

        # 再次发表第二条评论
        response = self.client.post(comment_url,
                                    {
                                        'body': '123ffffffffff',
                                    })
        # 断言：响应成功（重定向）
        self.assertEqual(response.status_code, 302)

        # 刷新文章数据并启用新评论
        article = Article.objects.get(pk=article.pk)
        self.update_article_comment_status(article)
        # 总共应有 2 条可见评论
        self.assertEqual(len(article.comment_list()), 2)

        # 获取第一条评论的 ID，用于后续回复（作为父评论）
        parent_comment_id = article.comment_list()[0].id

        # 发表一条回复（嵌套评论），包含复杂 Markdown 内容
        response = self.client.post(comment_url,
                                    {
                                        'body': '''
                                        # Title1

        ```python
        import os
        ```

        [url](https://www.lylinux.net/)

        [ddd](http://www.baidu.com)

        ''',
                                        'parent_comment_id': parent_comment_id  # 指定父评论
                                    })

        # 断言：提交成功
        self.assertEqual(response.status_code, 302)

        # 启用新评论并刷新文章数据
        self.update_article_comment_status(article)
        article = Article.objects.get(pk=article.pk)
        # 总评论数应为 3（2 条一级 + 1 条子评论）
        self.assertEqual(len(article.comment_list()), 3)

        # 获取父评论对象
        comment = Comment.objects.get(id=parent_comment_id)
        # 解析从该父评论开始的所有子评论树
        tree = parse_commenttree(article.comment_list(), comment)
        # 子评论树中应包含 1 个子评论
        self.assertEqual(len(tree), 1)

        # 测试包含标签 show_comment_item 是否正常返回数据
        data = show_comment_item(comment, True)
        # 返回值不应为 None
        self.assertIsNotNone(data)

        # 调用工具函数获取最大文章ID和评论ID（可能是用于生成唯一标识）
        s = get_max_articleid_commentid()
        # 函数应返回有效值
        self.assertIsNotNone(s)

        # 从 utils 模块导入发送评论邮件函数
        from comments.utils import send_comment_email
        # 测试发送评论通知邮件功能
        send_comment_email(comment)