"""
Comprehensive integration tests for AI analysis reporting system.

Tests cover:
- End-to-end reporting workflows
- Cross-component integration
- Real-world scenarios and user journeys
- Performance and scalability edge cases
"""

from django.test import TestCase, TransactionTestCase, override_settings
from django.contrib.auth import get_user_model
from django.contrib.auth.models import Permission
from django.contrib.contenttypes.models import ContentType
from django.core import mail
from django.utils import timezone
from django.test import Client
from django.urls import reverse
from rest_framework.test import APIClient
from rest_framework import status
from datetime import date, time
from unittest.mock import patch
from bazi.models import Person
from liuyao.models import liuyao
from api.utils import send_admin_report_notification, send_user_resolution_notification

User = get_user_model()


class EndToEndReportingWorkflowTests(TransactionTestCase):
    """Test complete end-to-end reporting workflows"""
    
    def setUp(self):
        """Set up test data"""
        # Create users
        self.user = User.objects.create_user(
            phone='13800138000',
            email='user@example.com',
            first_name='测试',
            last_name='用户'
        )
        
        # Use the fixed admin creation utility
        from tests.test_utils import create_admin_with_management_permissions
        self.admin = create_admin_with_management_permissions(
            phone='13800138001',
            email='admin@example.com',
            first_name='管理员',
            last_name='用户'
        )
        
        # Create analysis data
        self.person = Person.objects.create(
            name='端到端测试',
            birth_date=date(1990, 1, 1),
            birth_time=time(12, 0),
            created_by=self.user,
            analysis_status='completed',
            ai_analysis={'bazi_analysis': '完整的八字分析内容'},
            number_analysis_status='completed',
            number_ai_analysis={'number_analysis': '完整的数字分析内容'}
        )
        
        self.liuyao_entry = liuyao.objects.create(
            question='端到端六爻测试问题',
            user=self.user,
            qdate=timezone.now(),
            y1='1', y2='0', y3='1', y4='0', y5='1', y6='0',
            analysis_status='completed',
            ai_analysis={'response': '完整的六爻分析内容'}
        )
        
        self.api_client = APIClient()
        self.web_client = Client()
    
    def tearDown(self):
        """Clean up test data"""
        from tests.test_utils import cleanup_test_permissions
        cleanup_test_permissions()
    
    @override_settings(EMAIL_BACKEND='django.core.mail.backends.locmem.EmailBackend')
    def test_complete_bazi_reporting_workflow(self):
        """Test complete BaZi reporting workflow from report to resolution"""
        
        # Step 1: User reports analysis via API
        self.api_client.force_authenticate(user=self.user)
        
        report_url = reverse('api:bazi_report', kwargs={'pk': self.person.id})
        report_data = {
            'category': 'inappropriate_content',
            'message': '这个分析包含不当内容，请审核。'
        }
        
        response = self.api_client.post(report_url, report_data, format='json')
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        self.assertTrue(response.data['success'])
        
        # Verify database state after report
        self.person.refresh_from_db()
        self.assertTrue(self.person.bazi_analysis_reported)
        self.assertEqual(self.person.bazi_report_category, 'inappropriate_content')
        self.assertEqual(self.person.bazi_report_message, '这个分析包含不当内容，请审核。')
        self.assertEqual(self.person.bazi_report_status, 'pending')
        self.assertIsNotNone(self.person.bazi_report_timestamp)
        
        # Verify admin notification email was sent
        self.assertEqual(len(mail.outbox), 1)
        admin_email = mail.outbox[0]
        self.assertEqual(admin_email.to, ['admin@example.com'])
        self.assertIn('新的AI分析举报', admin_email.subject)
        self.assertIn('BAZI', admin_email.subject)
        self.assertIn('这个分析包含不当内容', admin_email.body)
        
        # Step 2: Admin reviews and resolves the report
        # Simulate admin action via Django admin
        self.person.bazi_report_status = 'resolved'
        self.person.bazi_report_resolved_by = self.admin
        self.person.bazi_report_resolved_at = timezone.now()
        self.person.bazi_report_admin_notes = '我们已经审核并处理了此问题'
        self.person.save(update_fields=[
            'bazi_report_status', 'bazi_report_resolved_by',
            'bazi_report_resolved_at', 'bazi_report_admin_notes'
        ])
        
        # Send resolution notification
        result = send_user_resolution_notification(
            self.user, self.person, 'bazi', 'resolved', 
            '我们已经审核并处理了此问题'
        )
        self.assertTrue(result)
        
        # Verify user notification email was sent
        self.assertEqual(len(mail.outbox), 2)
        user_email = mail.outbox[1]
        self.assertEqual(user_email.to, ['user@example.com'])
        self.assertIn('举报处理结果', user_email.subject)
        self.assertIn('测试 用户', user_email.body)
        self.assertIn('我们已经审核并处理了此问题', user_email.body)
        
        # Step 3: Verify user can re-report the same analysis (new behavior)
        response = self.api_client.post(report_url, report_data, format='json')
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        
        # Verify final database state (re-reporting resets to pending)
        self.person.refresh_from_db()
        self.assertEqual(self.person.bazi_report_status, 'pending')
        self.assertIsNone(self.person.bazi_report_resolved_by)
        self.assertIsNone(self.person.bazi_report_resolved_at)
    
    @override_settings(EMAIL_BACKEND='django.core.mail.backends.locmem.EmailBackend')
    def test_complete_liuyao_reporting_workflow(self):
        """Test complete LiuYao reporting workflow"""
        
        # Step 1: User reports LiuYao analysis
        self.api_client.force_authenticate(user=self.user)
        
        report_url = reverse('api:liuyao_report', kwargs={'pk': self.liuyao_entry.id})
        report_data = {
            'category': 'inaccurate_analysis',
            'message': '卦象解释不准确，与传统解释相违背。'
        }
        
        response = self.api_client.post(report_url, report_data, format='json')
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        
        # Verify database and email
        self.liuyao_entry.refresh_from_db()
        self.assertTrue(self.liuyao_entry.analysis_reported)
        self.assertEqual(self.liuyao_entry.report_category, 'inaccurate_analysis')
        self.assertEqual(len(mail.outbox), 1)
        
        # Step 2: Admin resolves with regenerate action
        self.liuyao_entry.report_status = 'resolved'
        self.liuyao_entry.report_resolved_by = self.admin
        self.liuyao_entry.report_resolved_at = timezone.now()
        self.liuyao_entry.report_admin_notes = '已重新生成更准确的分析'
        self.liuyao_entry.save()
        
        # Send resolution notification
        send_user_resolution_notification(
            self.user, self.liuyao_entry, 'liuyao', 'resolved',
            '已重新生成更准确的分析'
        )
        
        # Verify resolution email
        self.assertEqual(len(mail.outbox), 2)
        user_email = mail.outbox[1]
        self.assertIn('举报处理结果', user_email.subject)
        self.assertIn('已重新生成更准确的分析', user_email.body)
    
    def test_multiple_analysis_types_same_user(self):
        """Test user reporting multiple analysis types"""
        self.api_client.force_authenticate(user=self.user)
        
        # Report BaZi analysis
        bazi_url = reverse('api:bazi_report', kwargs={'pk': self.person.id})
        bazi_data = {'category': 'inappropriate_content', 'message': 'BaZi报告'}
        response1 = self.api_client.post(bazi_url, bazi_data, format='json')
        self.assertEqual(response1.status_code, status.HTTP_201_CREATED)
        
        # Report Number analysis on same person
        number_url = reverse('api:number_report', kwargs={'pk': self.person.id})
        number_data = {'category': 'technical_error', 'message': '数字分析报告'}
        response2 = self.api_client.post(number_url, number_data, format='json')
        self.assertEqual(response2.status_code, status.HTTP_201_CREATED)
        
        # Report LiuYao analysis
        liuyao_url = reverse('api:liuyao_report', kwargs={'pk': self.liuyao_entry.id})
        liuyao_data = {'category': 'inaccurate_analysis', 'message': '六爻分析报告'}
        response3 = self.api_client.post(liuyao_url, liuyao_data, format='json')
        self.assertEqual(response3.status_code, status.HTTP_201_CREATED)
        
        # Verify all reports exist independently
        self.person.refresh_from_db()
        self.liuyao_entry.refresh_from_db()
        
        self.assertTrue(self.person.bazi_analysis_reported)
        self.assertTrue(self.person.number_analysis_reported)
        self.assertTrue(self.liuyao_entry.analysis_reported)
        
        self.assertEqual(self.person.bazi_report_message, 'BaZi报告')
        self.assertEqual(self.person.number_report_message, '数字分析报告')
        self.assertEqual(self.liuyao_entry.report_message, '六爻分析报告')
    
    def test_cross_user_isolation(self):
        """Test that users cannot access each other's analyses for reporting"""
        # Create second user and their analysis
        other_user = User.objects.create_user(
            phone='13800138002',
            email='other@example.com',
            first_name='其他',
            last_name='用户'
        )
        
        other_person = Person.objects.create(
            name='其他用户分析',
            birth_date=date(1985, 5, 15),
            created_by=other_user,
            analysis_status='completed',
            ai_analysis={'bazi_analysis': '其他用户的分析'}
        )
        
        # Try to report other user's analysis
        self.api_client.force_authenticate(user=self.user)
        
        report_url = reverse('api:bazi_report', kwargs={'pk': other_person.id})
        report_data = {'category': 'inappropriate_content', 'message': '尝试报告他人分析'}
        
        response = self.api_client.post(report_url, report_data, format='json')
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertIn('not found', response.data['error'].lower())
        
        # Verify no report was created
        other_person.refresh_from_db()
        self.assertFalse(other_person.bazi_analysis_reported)


class PerformanceAndScalabilityTests(TestCase):
    """Test performance and scalability aspects of reporting system"""
    
    def setUp(self):
        """Set up test data"""
        self.user = User.objects.create_user(
            phone='13800138000',
            email='user@example.com'
        )
        
        # Use the fixed admin creation utility
        from tests.test_utils import create_admin_with_report_permissions
        self.admin = create_admin_with_report_permissions(
            phone='13800138001',
            email='admin@example.com'
        )
    
    def tearDown(self):
        """Clean up test data"""
        from tests.test_utils import cleanup_test_permissions
        cleanup_test_permissions()
    
    def test_bulk_report_processing(self):
        """Test handling of bulk report operations"""
        # Create multiple analyses
        persons = []
        for i in range(10):
            person = Person.objects.create(
                name=f'批量测试 {i}',
                birth_date=date(1990, 1, 1),
                created_by=self.user,
                analysis_status='completed',
                ai_analysis={'bazi_analysis': f'批量分析内容 {i}'}
            )
            persons.append(person)
        
        # Report all analyses
        api_client = APIClient()
        api_client.force_authenticate(user=self.user)
        
        for person in persons:
            url = reverse('api:bazi_report', kwargs={'pk': person.id})
            data = {'category': 'other', 'message': f'批量报告 {person.id}'}
            
            response = api_client.post(url, data, format='json')
            self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        
        # Verify all reports were created
        reported_count = Person.objects.filter(
            id__in=[p.id for p in persons],
            bazi_analysis_reported=True
        ).count()
        self.assertEqual(reported_count, 10)
    
    @override_settings(EMAIL_BACKEND='django.core.mail.backends.locmem.EmailBackend')
    def test_concurrent_admin_resolution(self):
        """Test concurrent admin resolution of multiple reports"""
        # Create multiple reported analyses
        persons = []
        for i in range(5):
            person = Person.objects.create(
                name=f'并发测试 {i}',
                birth_date=date(1990, 1, 1),
                created_by=self.user,
                analysis_status='completed',
                ai_analysis={'bazi_analysis': f'并发分析 {i}'},
                bazi_analysis_reported=True,
                bazi_report_status='pending',
                bazi_report_category='technical_error'
            )
            persons.append(person)
        
        # Simulate concurrent resolution
        for person in persons:
            person.bazi_report_status = 'resolved'
            person.bazi_report_resolved_by = self.admin
            person.bazi_report_resolved_at = timezone.now()
            person.save()
            
            # Send notification
            send_user_resolution_notification(
                self.user, person, 'bazi', 'resolved', f'问题已解决 {person.id}'
            )
        
        # Verify all resolved
        resolved_count = Person.objects.filter(
            id__in=[p.id for p in persons],
            bazi_report_status='resolved'
        ).count()
        self.assertEqual(resolved_count, 5)
        
        # Verify all emails sent
        self.assertEqual(len(mail.outbox), 5)
    
    def test_large_report_message_handling(self):
        """Test handling of large report messages"""
        person = Person.objects.create(
            name='大消息测试',
            birth_date=date(1990, 1, 1),
            created_by=self.user,
            analysis_status='completed',
            ai_analysis={'bazi_analysis': '大消息分析内容'}
        )
        
        # Create very large message (approaching limit)
        large_message = '这是一个非常详细的举报消息。' * 50  # ~1000 characters
        
        api_client = APIClient()
        api_client.force_authenticate(user=self.user)
        
        url = reverse('api:bazi_report', kwargs={'pk': person.id})
        data = {'category': 'other', 'message': large_message}
        
        response = api_client.post(url, data, format='json')
        
        # Should handle gracefully (succeed or fail with proper error)
        self.assertIn(response.status_code, [
            status.HTTP_201_CREATED,
            status.HTTP_400_BAD_REQUEST
        ])
        
        if response.status_code == status.HTTP_201_CREATED:
            person.refresh_from_db()
            self.assertTrue(person.bazi_analysis_reported)
    
    def test_unicode_content_performance(self):
        """Test performance with Unicode content"""
        person = Person.objects.create(
            name='Unicode性能测试🚀',
            birth_date=date(1990, 1, 1),
            created_by=self.user,
            analysis_status='completed',
            ai_analysis={'bazi_analysis': 'Unicode分析内容💫'}
        )
        
        unicode_message = '这个分析包含大量的中文字符、特殊符号！@#$%^&*()、以及emoji表情🎯🔮✨🌟💎🎪🎨🎭🎪'
        
        api_client = APIClient()
        api_client.force_authenticate(user=self.user)
        
        url = reverse('api:bazi_report', kwargs={'pk': person.id})
        data = {'category': 'other', 'message': unicode_message}
        
        response = api_client.post(url, data, format='json')
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        
        person.refresh_from_db()
        self.assertEqual(person.bazi_report_message, unicode_message)


class ErrorHandlingAndRecoveryTests(TestCase):
    """Test error handling and system recovery scenarios"""
    
    def setUp(self):
        """Set up test data"""
        # Add admin for report notifications
        from tests.test_utils import create_admin_with_report_permissions
        self.admin = create_admin_with_report_permissions(
            email='admin_error_handling@example.com'
        )
        
        self.user = User.objects.create_user(
            phone='13800138000',
            email='user@example.com'
        )
        
        self.person = Person.objects.create(
            name='错误处理测试',
            birth_date=date(1990, 1, 1),
            created_by=self.user,
            analysis_status='completed',
            ai_analysis={'bazi_analysis': '错误处理分析内容'}
        )
    
    def tearDown(self):
        """Clean up test data"""
        from tests.test_utils import cleanup_test_permissions
        cleanup_test_permissions()
    
    @patch('api.utils.send_admin_report_notification')
    def test_report_with_email_failure(self, mock_email):
        """Test reporting when email notification fails"""
        mock_email.return_value = False  # Email function returns False on failure
        
        api_client = APIClient()
        api_client.force_authenticate(user=self.user)
        
        url = reverse('api:bazi_report', kwargs={'pk': self.person.id})
        data = {'category': 'technical_error', 'message': '邮件失败测试'}
        
        # Report should still succeed even if email fails
        response = api_client.post(url, data, format='json')
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        
        # Verify report was saved despite email failure
        self.person.refresh_from_db()
        self.assertTrue(self.person.bazi_analysis_reported)
        self.assertEqual(self.person.bazi_report_message, '邮件失败测试')
    
    def test_report_invalid_analysis_id(self):
        """Test reporting with invalid analysis ID"""
        api_client = APIClient()
        api_client.force_authenticate(user=self.user)
        
        url = reverse('api:bazi_report', kwargs={'pk': 99999})
        data = {'category': 'technical_error', 'message': '无效ID测试'}
        
        response = api_client.post(url, data, format='json')
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertIn('not found', response.data['error'].lower())
    
    def test_report_incomplete_analysis(self):
        """Test reporting analysis that is not completed"""
        incomplete_person = Person.objects.create(
            name='未完成分析',
            birth_date=date(1990, 1, 1),
            created_by=self.user,
            analysis_status='pending',  # Not completed
            ai_analysis=None
        )
        
        api_client = APIClient()
        api_client.force_authenticate(user=self.user)
        
        url = reverse('api:bazi_report', kwargs={'pk': incomplete_person.id})
        data = {'category': 'technical_error', 'message': '未完成分析测试'}
        
        response = api_client.post(url, data, format='json')
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertIn('cannot be reported', response.data['error'])
    
    def test_report_malformed_request_data(self):
        """Test reporting with malformed request data"""
        api_client = APIClient()
        api_client.force_authenticate(user=self.user)
        
        url = reverse('api:bazi_report', kwargs={'pk': self.person.id})
        
        # Test missing required field
        response = api_client.post(url, {'message': '缺少类别'}, format='json')
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        
        # Test invalid category
        response = api_client.post(url, {
            'category': 'invalid_category',
            'message': '无效类别'
        }, format='json')
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
    
    def test_database_integrity_under_stress(self):
        """Test database integrity under stress conditions"""
        # Create multiple persons and try to report rapidly
        persons = []
        for i in range(5):
            person = Person.objects.create(
                name=f'压力测试 {i}',
                birth_date=date(1990, 1, 1),
                created_by=self.user,
                analysis_status='completed',
                ai_analysis={'bazi_analysis': f'压力测试内容 {i}'}
            )
            persons.append(person)
        
        api_client = APIClient()
        api_client.force_authenticate(user=self.user)
        
        # Submit reports rapidly
        for person in persons:
            url = reverse('api:bazi_report', kwargs={'pk': person.id})
            data = {'category': 'other', 'message': f'压力测试 {person.id}'}
            
            response = api_client.post(url, data, format='json')
            self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        
        # Verify database consistency
        for person in persons:
            person.refresh_from_db()
            self.assertTrue(person.bazi_analysis_reported)
            self.assertEqual(person.bazi_report_status, 'pending')
            self.assertIsNotNone(person.bazi_report_timestamp)


class RealWorldScenarioTests(TestCase):
    """Test real-world usage scenarios and user journeys"""
    
    def setUp(self):
        """Set up realistic test data"""
        # Create multiple users representing different user types
        self.regular_user = User.objects.create_user(
            phone='13800138000',
            email='regular@example.com',
            first_name='普通',
            last_name='用户'
        )
        
        self.premium_user = User.objects.create_user(
            phone='13800138001',
            email='premium@example.com',
            first_name='高级',
            last_name='用户'
        )
        
        # Use the fixed admin creation utility
        from tests.test_utils import create_admin_with_report_permissions
        self.admin_user = create_admin_with_report_permissions(
            phone='13800138002',
            email='admin@example.com',
            first_name='管理',
            last_name='员'
        )
    
    def tearDown(self):
        """Clean up test data"""
        from tests.test_utils import cleanup_test_permissions
        cleanup_test_permissions()
    
    @override_settings(EMAIL_BACKEND='django.core.mail.backends.locmem.EmailBackend')
    def test_typical_user_report_journey(self):
        """Test typical user reporting journey"""
        # User creates multiple analyses
        person1 = Person.objects.create(
            name='张三',
            birth_date=date(1985, 3, 15),
            birth_time=time(8, 30),
            created_by=self.regular_user,
            analysis_status='completed',
            ai_analysis={'bazi_analysis': '张三的八字分析结果'},
            number_analysis_status='completed',
            number_ai_analysis={'number_analysis': '张三的数字分析结果'}
        )
        
        liuyao1 = liuyao.objects.create(
            question='今年事业发展如何？',
            user=self.regular_user,
            qdate=timezone.now(),
            y1='1', y2='0', y3='1', y4='0', y5='1', y6='0',
            analysis_status='completed',
            ai_analysis={'response': '事业发展六爻分析结果'}
        )
        
        # User finds issues and reports them
        api_client = APIClient()
        api_client.force_authenticate(user=self.regular_user)
        
        # Report BaZi as inaccurate
        bazi_url = reverse('api:bazi_report', kwargs={'pk': person1.id})
        response = api_client.post(bazi_url, {
            'category': 'inaccurate_analysis',
            'message': '分析结果与我的实际情况差距很大，希望能重新分析。'
        }, format='json')
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        
        # Report Number analysis as having technical errors
        number_url = reverse('api:number_report', kwargs={'pk': person1.id})
        response = api_client.post(number_url, {
            'category': 'technical_error',
            'message': '数字计算似乎有误，请检查算法。'
        }, format='json')
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        
        # Report LiuYao as inappropriate
        liuyao_url = reverse('api:liuyao_report', kwargs={'pk': liuyao1.id})
        response = api_client.post(liuyao_url, {
            'category': 'inappropriate_content',
            'message': '解释内容包含不当建议。'
        }, format='json')
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        
        # Verify all reports were created and emails sent
        person1.refresh_from_db()
        liuyao1.refresh_from_db()
        
        self.assertTrue(person1.bazi_analysis_reported)
        self.assertTrue(person1.number_analysis_reported)
        self.assertTrue(liuyao1.analysis_reported)
        
        # Should have 3 admin notification emails
        self.assertEqual(len(mail.outbox), 3)
        
        # Admin processes reports with different actions
        # Resolve BaZi with regeneration
        person1.bazi_report_status = 'resolved'
        person1.bazi_report_resolved_by = self.admin_user
        person1.bazi_report_resolved_at = timezone.now()
        person1.bazi_report_admin_notes = '已重新生成更准确的分析'
        person1.save()
        
        send_user_resolution_notification(
            self.regular_user, person1, 'bazi', 'resolved',
            '已重新生成更准确的分析'
        )
        
        # Dismiss Number report as false positive
        person1.number_report_status = 'dismissed'
        person1.number_report_resolved_by = self.admin_user
        person1.number_report_resolved_at = timezone.now()
        person1.number_report_admin_notes = '经检查算法无误，可能是理解差异'
        person1.save()
        
        send_user_resolution_notification(
            self.regular_user, person1, 'number', 'dismissed',
            '经检查算法无误，可能是理解差异'
        )
        
        # Escalate LiuYao report for further review
        liuyao1.report_status = 'resolved'
        liuyao1.report_resolved_by = self.admin_user
        liuyao1.report_resolved_at = timezone.now()
        liuyao1.report_admin_notes = '已上报给高级审核员进一步处理'
        liuyao1.save()
        
        send_user_resolution_notification(
            self.regular_user, liuyao1, 'liuyao', 'resolved',
            '已上报给高级审核员进一步处理'
        )
        
        # Verify resolution emails sent (BaZi and LiuYao; Number dismissed sends none)
        self.assertEqual(len(mail.outbox), 5)
        
        # Verify user can re-report resolved analyses (new behavior)
        response = api_client.post(bazi_url, {
            'category': 'other',
            'message': '再次举报'
        }, format='json')
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
    
    def test_admin_bulk_resolution_scenario(self):
        """Test admin handling multiple reports efficiently"""
        # Create multiple users with reported analyses
        users_and_reports = []
        for i in range(5):
            user = User.objects.create_user(
                phone=f'1380013810{i}',
                email=f'user{i}@example.com',
                first_name=f'用户{i}',
                last_name='测试'
            )
            
            person = Person.objects.create(
                name=f'批量处理测试{i}',
                birth_date=date(1990, 1, 1),
                created_by=user,
                analysis_status='completed',
                ai_analysis={'bazi_analysis': f'批量分析{i}'},
                bazi_analysis_reported=True,
                bazi_report_status='pending',
                bazi_report_category='technical_error',
                bazi_report_message=f'批量报告{i}'
            )
            
            users_and_reports.append((user, person))
        
        # Admin resolves all reports in bulk
        for user, person in users_and_reports:
            person.bazi_report_status = 'resolved'
            person.bazi_report_resolved_by = self.admin_user
            person.bazi_report_resolved_at = timezone.now()
            person.save()
        
        # Verify all resolved
        resolved_count = Person.objects.filter(
            bazi_report_status='resolved',
            bazi_report_resolved_by=self.admin_user
        ).count()
        self.assertEqual(resolved_count, 5) 


class ReReportingFunctionalityTests(TestCase):
    """Test re-reporting functionality after resolution"""
    
    def setUp(self):
        """Set up test data"""
        self.user = User.objects.create_user(
            phone='13800138000',
            email='user@example.com',
            first_name='测试',
            last_name='用户'
        )
        
        self.admin = User.objects.create_user(
            phone='13800138001',
            email='admin@example.com',
            first_name='管理员',
            last_name='用户',
            is_staff=True
        )
        
        # Create test data
        self.person = Person.objects.create(
            name='Re-reporting Test',
            birth_date=date(1990, 1, 1),
            created_by=self.user,
            analysis_status='completed',
            ai_analysis={'bazi_analysis': 'Test BaZi analysis content'},
            number_analysis_status='completed',
            number_ai_analysis={'number_analysis': 'Test Number analysis content'}
        )
        
        self.liuyao_entry = liuyao.objects.create(
            question='Re-reporting test question',
            user=self.user,
            qdate=timezone.now(),
            y1='1', y2='0', y3='1', y4='0', y5='1', y6='0',
            analysis_status='completed',
            ai_analysis={'liuyao_analysis': 'Test LiuYao analysis content'}
        )
        
        self.api_client = APIClient()
    
    def test_bazi_re_reporting_after_resolution(self):
        """Test that users can re-report BaZi analysis after resolution"""
        # Step 1: Initial report
        self.api_client.force_authenticate(user=self.user)
        report_url = reverse('api:bazi_report', kwargs={'pk': self.person.id})
        report_data = {
            'category': 'inaccurate_analysis',
            'message': 'Initial BaZi report'
        }
        
        response = self.api_client.post(report_url, report_data, format='json')
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        
        # Step 2: Admin resolves the report
        self.person.refresh_from_db()
        self.person.bazi_report_status = 'resolved'
        self.person.bazi_report_resolved_by = self.admin
        self.person.bazi_report_resolved_at = timezone.now()
        self.person.bazi_report_admin_notes = 'Admin resolved this BaZi report'
        self.person.save()
        
        # Step 3: User can re-report after resolution
        new_report_data = {
            'category': 'inappropriate_content',
            'message': 'Re-reporting BaZi analysis after resolution'
        }
        
        response = self.api_client.post(report_url, new_report_data, format='json')
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        
        # Verify the report was reset and new data was set
        self.person.refresh_from_db()
        self.assertEqual(self.person.bazi_report_status, 'pending')
        self.assertEqual(self.person.bazi_report_category, 'inappropriate_content')
        self.assertEqual(self.person.bazi_report_message, 'Re-reporting BaZi analysis after resolution')
        self.assertIsNone(self.person.bazi_report_resolved_by)
        self.assertIsNone(self.person.bazi_report_resolved_at)
        self.assertIsNone(self.person.bazi_report_admin_notes)
    
    def test_number_re_reporting_after_resolution(self):
        """Test that users can re-report Number analysis after resolution"""
        # Step 1: Initial report
        self.api_client.force_authenticate(user=self.user)
        report_url = reverse('api:number_report', kwargs={'pk': self.person.id})
        report_data = {
            'category': 'technical_error',
            'message': 'Initial Number report'
        }
        
        response = self.api_client.post(report_url, report_data, format='json')
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        
        # Step 2: Admin resolves the report
        self.person.refresh_from_db()
        self.person.number_report_status = 'resolved'
        self.person.number_report_resolved_by = self.admin
        self.person.number_report_resolved_at = timezone.now()
        self.person.number_report_admin_notes = 'Admin resolved this Number report'
        self.person.save()
        
        # Step 3: User can re-report after resolution
        new_report_data = {
            'category': 'inappropriate_content',
            'message': 'Re-reporting Number analysis after resolution'
        }
        
        response = self.api_client.post(report_url, new_report_data, format='json')
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        
        # Verify the report was reset and new data was set
        self.person.refresh_from_db()
        self.assertEqual(self.person.number_report_status, 'pending')
        self.assertEqual(self.person.number_report_category, 'inappropriate_content')
        self.assertEqual(self.person.number_report_message, 'Re-reporting Number analysis after resolution')
        self.assertIsNone(self.person.number_report_resolved_by)
        self.assertIsNone(self.person.number_report_resolved_at)
        self.assertIsNone(self.person.number_report_admin_notes)
    
    def test_liuyao_re_reporting_after_resolution(self):
        """Test that users can re-report LiuYao analysis after resolution"""
        # Step 1: Initial report
        self.api_client.force_authenticate(user=self.user)
        report_url = reverse('api:liuyao_report', kwargs={'pk': self.liuyao_entry.id})
        report_data = {
            'category': 'inaccurate_analysis',
            'message': 'Initial LiuYao report'
        }
        
        response = self.api_client.post(report_url, report_data, format='json')
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        
        # Step 2: Admin resolves the report
        self.liuyao_entry.refresh_from_db()
        self.liuyao_entry.report_status = 'resolved'
        self.liuyao_entry.report_resolved_by = self.admin
        self.liuyao_entry.report_resolved_at = timezone.now()
        self.liuyao_entry.report_admin_notes = 'Admin resolved this LiuYao report'
        self.liuyao_entry.save()
        
        # Step 3: User can re-report after resolution
        new_report_data = {
            'category': 'inappropriate_content',
            'message': 'Re-reporting LiuYao analysis after resolution'
        }
        
        response = self.api_client.post(report_url, new_report_data, format='json')
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        
        # Verify the report was reset and new data was set
        self.liuyao_entry.refresh_from_db()
        self.assertEqual(self.liuyao_entry.report_status, 'pending')
        self.assertEqual(self.liuyao_entry.report_category, 'inappropriate_content')
        self.assertEqual(self.liuyao_entry.report_message, 'Re-reporting LiuYao analysis after resolution')
        self.assertIsNone(self.liuyao_entry.report_resolved_by)
        self.assertIsNone(self.liuyao_entry.report_resolved_at)
        self.assertIsNone(self.liuyao_entry.report_admin_notes)
    
    def test_cannot_re_report_after_ai_reset(self):
        """Test that users cannot re-report after admin resets AI analysis"""
        # Step 1: Initial report
        self.api_client.force_authenticate(user=self.user)
        report_url = reverse('api:bazi_report', kwargs={'pk': self.person.id})
        report_data = {
            'category': 'inaccurate_analysis',
            'message': 'Initial BaZi report'
        }
        
        response = self.api_client.post(report_url, report_data, format='json')
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        
        # Step 2: Admin resolves the report
        self.person.refresh_from_db()
        self.person.bazi_report_status = 'resolved'
        self.person.bazi_report_resolved_by = self.admin
        self.person.bazi_report_resolved_at = timezone.now()
        self.person.bazi_report_admin_notes = 'Admin resolved this BaZi report'
        self.person.save()
        
        # Step 3: Admin resets AI analysis
        self.person.reset_bazi_analysis()
        self.person.save()
        
        # Step 4: User cannot re-report after AI reset
        new_report_data = {
            'category': 'inappropriate_content',
            'message': 'Trying to re-report after AI reset'
        }
        
        response = self.api_client.post(report_url, new_report_data, format='json')
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertIn('cannot be reported', response.data['error'])
    
    def test_cannot_re_report_after_dismissal(self):
        """Test that users can re-report after dismissal (same as resolution)"""
        # Step 1: Initial report
        self.api_client.force_authenticate(user=self.user)
        report_url = reverse('api:bazi_report', kwargs={'pk': self.person.id})
        report_data = {
            'category': 'inaccurate_analysis',
            'message': 'Initial BaZi report'
        }
        
        response = self.api_client.post(report_url, report_data, format='json')
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        
        # Step 2: Admin dismisses the report
        self.person.refresh_from_db()
        self.person.bazi_report_status = 'dismissed'
        self.person.bazi_report_resolved_by = self.admin
        self.person.bazi_report_resolved_at = timezone.now()
        self.person.bazi_report_admin_notes = 'Admin dismissed this BaZi report'
        self.person.save()
        
        # Step 3: User can re-report after dismissal
        new_report_data = {
            'category': 'inappropriate_content',
            'message': 'Re-reporting BaZi analysis after dismissal'
        }
        
        response = self.api_client.post(report_url, new_report_data, format='json')
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        
        # Verify the report was reset and new data was set
        self.person.refresh_from_db()
        self.assertEqual(self.person.bazi_report_status, 'pending')
        self.assertEqual(self.person.bazi_report_category, 'inappropriate_content')
        self.assertEqual(self.person.bazi_report_message, 'Re-reporting BaZi analysis after dismissal')


class UserSiteDisplayTests(TestCase):
    """Test that report details are properly displayed on user site"""
    
    def setUp(self):
        """Set up test data"""
        self.user = User.objects.create_user(
            phone='13800138000',
            email='user@example.com',
            first_name='测试',
            last_name='用户'
        )
        
        self.admin = User.objects.create_user(
            phone='13800138001',
            email='admin@example.com',
            first_name='管理员',
            last_name='用户',
            is_staff=True
        )
        
        # Create test data
        self.person = Person.objects.create(
            name='Display Test',
            birth_date=date(1990, 1, 1),
            created_by=self.user,
            analysis_status='completed',
            ai_analysis={'bazi_analysis': 'Test BaZi analysis content'},
            number_analysis_status='completed',
            number_ai_analysis={'number_analysis': 'Test Number analysis content'}
        )
        
        self.liuyao_entry = liuyao.objects.create(
            question='Display test question',
            user=self.user,
            qdate=timezone.now(),
            y1='1', y2='0', y3='1', y4='0', y5='1', y6='0',
            analysis_status='completed',
            ai_analysis={'liuyao_analysis': 'Test LiuYao analysis content'}
        )
    
    def test_bazi_report_details_display_pending(self):
        """Test that BaZi report details are displayed when pending"""
        # Create a pending report
        self.person.report_bazi_analysis('inaccurate_analysis', 'Test BaZi report message')
        
        # Simulate API response that user site would receive
        api_client = APIClient()
        api_client.force_authenticate(user=self.user)
        
        url = reverse('api:bazi-analysis', kwargs={'pk': self.person.id})
        response = api_client.get(url)
        
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        data = response.json()
        
        # Verify report details are included
        self.assertTrue(data['bazi_analysis_reported'])
        self.assertEqual(data['bazi_report_status'], 'pending')
        self.assertEqual(data['bazi_report_category'], 'inaccurate_analysis')
        self.assertEqual(data['bazi_report_message'], 'Test BaZi report message')
        self.assertIsNotNone(data['bazi_report_timestamp'])
        self.assertIsNone(data['bazi_report_admin_notes'])
        self.assertIsNone(data['bazi_report_resolved_at'])
    
    def test_bazi_report_details_display_resolved(self):
        """Test that BaZi report details with admin remarks are displayed when resolved"""
        # Create a resolved report
        self.person.report_bazi_analysis('inaccurate_analysis', 'Test BaZi report message')
        self.person.bazi_report_status = 'resolved'
        self.person.bazi_report_resolved_by = self.admin
        self.person.bazi_report_resolved_at = timezone.now()
        self.person.bazi_report_admin_notes = 'Admin resolved this BaZi report with detailed remarks'
        self.person.save()
        
        # Simulate API response that user site would receive
        api_client = APIClient()
        api_client.force_authenticate(user=self.user)
        
        url = reverse('api:bazi-analysis', kwargs={'pk': self.person.id})
        response = api_client.get(url)
        
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        data = response.json()
        
        # Verify report details are included
        self.assertTrue(data['bazi_analysis_reported'])
        self.assertEqual(data['bazi_report_status'], 'resolved')
        self.assertEqual(data['bazi_report_category'], 'inaccurate_analysis')
        self.assertEqual(data['bazi_report_message'], 'Test BaZi report message')
        self.assertIsNotNone(data['bazi_report_timestamp'])
        self.assertEqual(data['bazi_report_admin_notes'], 'Admin resolved this BaZi report with detailed remarks')
        self.assertIsNotNone(data['bazi_report_resolved_at'])
    
    def test_number_report_details_display_pending(self):
        """Test that Number report details are displayed when pending"""
        # Create a pending report
        self.person.report_number_analysis('technical_error', 'Test Number report message')
        
        # Simulate API response that user site would receive
        api_client = APIClient()
        api_client.force_authenticate(user=self.user)
        
        url = reverse('api:number_analysis', kwargs={'person_id': self.person.id})
        response = api_client.get(url)
        
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        data = response.json()
        
        # Verify report details are included
        self.assertTrue(data['number_analysis_reported'])
        self.assertEqual(data['number_report_status'], 'pending')
        self.assertEqual(data['number_report_category'], 'technical_error')
        self.assertEqual(data['number_report_message'], 'Test Number report message')
        self.assertIsNotNone(data['number_report_timestamp'])
        self.assertIsNone(data['number_report_admin_notes'])
        self.assertIsNone(data['number_report_resolved_at'])
    
    def test_number_report_details_display_resolved(self):
        """Test that Number report details with admin remarks are displayed when resolved"""
        # Create a resolved report
        self.person.report_number_analysis('technical_error', 'Test Number report message')
        self.person.number_report_status = 'resolved'
        self.person.number_report_resolved_by = self.admin
        self.person.number_report_resolved_at = timezone.now()
        self.person.number_report_admin_notes = 'Admin resolved this Number report with detailed remarks'
        self.person.save()
        
        # Simulate API response that user site would receive
        api_client = APIClient()
        api_client.force_authenticate(user=self.user)
        
        url = reverse('api:number_analysis', kwargs={'person_id': self.person.id})
        response = api_client.get(url)
        
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        data = response.json()
        
        # Verify report details are included
        self.assertTrue(data['number_analysis_reported'])
        self.assertEqual(data['number_report_status'], 'resolved')
        self.assertEqual(data['number_report_category'], 'technical_error')
        self.assertEqual(data['number_report_message'], 'Test Number report message')
        self.assertIsNotNone(data['number_report_timestamp'])
        self.assertEqual(data['number_report_admin_notes'], 'Admin resolved this Number report with detailed remarks')
        self.assertIsNotNone(data['number_report_resolved_at'])
    
    def test_liuyao_report_details_display_pending(self):
        """Test that LiuYao report details are displayed when pending"""
        # Create a pending report
        self.liuyao_entry.report_analysis('inaccurate_analysis', 'Test LiuYao report message')
        
        # Simulate API response that user site would receive
        api_client = APIClient()
        api_client.force_authenticate(user=self.user)
        
        url = reverse('api:liuyao-analysis', kwargs={'pk': self.liuyao_entry.id})
        response = api_client.get(url)
        
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        data = response.json()
        
        # Verify report details are included
        self.assertTrue(data['analysis_reported'])
        self.assertEqual(data['report_status'], 'pending')
        self.assertEqual(data['report_category'], 'inaccurate_analysis')
        self.assertEqual(data['report_message'], 'Test LiuYao report message')
        self.assertIsNotNone(data['report_timestamp'])
        self.assertIsNone(data['report_admin_notes'])
        self.assertIsNone(data['report_resolved_at'])
    
    def test_liuyao_report_details_display_resolved(self):
        """Test that LiuYao report details with admin remarks are displayed when resolved"""
        # Create a resolved report
        self.liuyao_entry.report_analysis('inaccurate_analysis', 'Test LiuYao report message')
        self.liuyao_entry.report_status = 'resolved'
        self.liuyao_entry.report_resolved_by = self.admin
        self.liuyao_entry.report_resolved_at = timezone.now()
        self.liuyao_entry.report_admin_notes = 'Admin resolved this LiuYao report with detailed remarks'
        self.liuyao_entry.save()
        
        # Simulate API response that user site would receive
        api_client = APIClient()
        api_client.force_authenticate(user=self.user)
        
        url = reverse('api:liuyao-analysis', kwargs={'pk': self.liuyao_entry.id})
        response = api_client.get(url)
        
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        data = response.json()
        
        # Verify report details are included
        self.assertTrue(data['analysis_reported'])
        self.assertEqual(data['report_status'], 'resolved')
        self.assertEqual(data['report_category'], 'inaccurate_analysis')
        self.assertEqual(data['report_message'], 'Test LiuYao report message')
        self.assertIsNotNone(data['report_timestamp'])
        self.assertEqual(data['report_admin_notes'], 'Admin resolved this LiuYao report with detailed remarks')
        self.assertIsNotNone(data['report_resolved_at'])


class EmailNotificationTests(TestCase):
    """Test email notification behavior"""
    
    def setUp(self):
        """Set up test data"""
        self.user = User.objects.create_user(
            phone='13800138000',
            email='user@example.com',
            first_name='测试',
            last_name='用户'
        )
        
        self.admin = User.objects.create_user(
            phone='13800138001',
            email='admin@example.com',
            first_name='管理员',
            last_name='用户',
            is_staff=True
        )
        
        # Create test data
        self.person = Person.objects.create(
            name='Email Test',
            birth_date=date(1990, 1, 1),
            created_by=self.user,
            analysis_status='completed',
            ai_analysis={'bazi_analysis': 'Test BaZi analysis content'}
        )
    
    @override_settings(EMAIL_BACKEND='django.core.mail.backends.locmem.EmailBackend')
    def test_email_sent_only_once_per_resolution(self):
        """Test that email is sent only once per resolution cycle"""
        # Step 1: Create initial report
        self.person.report_bazi_analysis('inaccurate_analysis', 'Test report message')
        
        # Step 2: Admin resolves (should send email)
        self.person.bazi_report_status = 'resolved'
        self.person.bazi_report_resolved_by = self.admin
        self.person.bazi_report_resolved_at = timezone.now()
        self.person.bazi_report_admin_notes = 'Admin resolved this report'
        self.person.save()
        
        # Send resolution notification
        from api.utils import send_user_resolution_notification
        result = send_user_resolution_notification(
            self.user, self.person, 'bazi', 'resolved', 'Admin resolved this report'
        )
        
        self.assertTrue(result)
        self.assertEqual(len(mail.outbox), 1)
        
        # Step 3: Admin changes status again (should NOT send email)
        self.person.bazi_report_status = 'dismissed'
        self.person.bazi_report_admin_notes = 'Admin dismissed this report'
        self.person.save()
        
        result = send_user_resolution_notification(
            self.user, self.person, 'bazi', 'dismissed', 'Admin dismissed this report'
        )
        
        # Should not send email for dismissed status
        self.assertFalse(result)
        self.assertEqual(len(mail.outbox), 1)  # Still only 1 email
        
        # Step 4: Admin changes back to resolved (should NOT send email again)
        self.person.bazi_report_status = 'resolved'
        self.person.bazi_report_admin_notes = 'Admin resolved this report again'
        self.person.save()
        
        result = send_user_resolution_notification(
            self.user, self.person, 'bazi', 'resolved', 'Admin resolved this report again'
        )
        
        # Should not send email again since it was already sent for this resolution cycle
        self.assertFalse(result)
        self.assertEqual(len(mail.outbox), 1)  # Still only 1 email
    
    @override_settings(EMAIL_BACKEND='django.core.mail.backends.locmem.EmailBackend')
    def test_email_reset_when_user_re_reports(self):
        """Test that email flag is reset when user re-reports"""
        # Step 1: Create initial report
        self.person.report_bazi_analysis('inaccurate_analysis', 'Test report message')
        
        # Step 2: Admin resolves (should send email)
        self.person.bazi_report_status = 'resolved'
        self.person.bazi_report_resolved_by = self.admin
        self.person.bazi_report_resolved_at = timezone.now()
        self.person.bazi_report_admin_notes = 'Admin resolved this report'
        self.person.bazi_report_resolution_email_sent = True  # Simulate email sent
        self.person.save()
        
        # Step 3: User re-reports (should reset email flag)
        self.person.report_bazi_analysis('inappropriate_content', 'Re-reporting after resolution')
        
        # Verify email flag was reset
        self.person.refresh_from_db()
        self.assertFalse(self.person.bazi_report_resolution_email_sent)
        
        # Step 4: Admin resolves again (should send email again)
        self.person.bazi_report_status = 'resolved'
        self.person.bazi_report_admin_notes = 'Admin resolved the re-report'
        self.person.save()
        
        from api.utils import send_user_resolution_notification
        result = send_user_resolution_notification(
            self.user, self.person, 'bazi', 'resolved', 'Admin resolved the re-report'
        )
        
        self.assertTrue(result)
        self.assertEqual(len(mail.outbox), 1)  # New email sent
    
    @override_settings(EMAIL_BACKEND='django.core.mail.backends.locmem.EmailBackend')
    def test_email_reset_when_admin_unchecks_reported(self):
        """Test that email flag is reset when admin unchecks reported checkbox"""
        # Step 1: Create initial report
        self.person.report_bazi_analysis('inaccurate_analysis', 'Test report message')
        
        # Step 2: Admin resolves (should send email)
        self.person.bazi_report_status = 'resolved'
        self.person.bazi_report_resolved_by = self.admin
        self.person.bazi_report_resolved_at = timezone.now()
        self.person.bazi_report_admin_notes = 'Admin resolved this report'
        self.person.bazi_report_resolution_email_sent = True  # Simulate email sent
        self.person.save()
        
        # Step 3: Admin unchecks reported checkbox (should reset email flag)
        self.person.bazi_analysis_reported = False
        self.person.bazi_report_resolution_email_sent = False  # Directly reset the flag
        self.person.save()
        
        # Verify email flag was reset
        self.person.refresh_from_db()
        self.assertFalse(self.person.bazi_report_resolution_email_sent)
        
        # Step 4: Admin checks reported again and resolves (should send email)
        self.person.bazi_analysis_reported = True
        self.person.bazi_report_status = 'resolved'
        self.person.bazi_report_admin_notes = 'Admin resolved after unchecking'
        self.person.save()
        
        from api.utils import send_user_resolution_notification
        result = send_user_resolution_notification(
            self.user, self.person, 'bazi', 'resolved', 'Admin resolved after unchecking'
        )
        
        self.assertTrue(result)
        self.assertEqual(len(mail.outbox), 1)  # New email sent


class AdminRemarksDisplayTests(TestCase):
    """Test that admin remarks are properly displayed to users"""
    
    def setUp(self):
        """Set up test data"""
        self.user = User.objects.create_user(
            phone='13800138000',
            email='user@example.com',
            first_name='测试',
            last_name='用户'
        )
        
        self.admin = User.objects.create_user(
            phone='13800138001',
            email='admin@example.com',
            first_name='管理员',
            last_name='用户',
            is_staff=True
        )
        
        # Create test data
        self.person = Person.objects.create(
            name='Admin Remarks Test',
            birth_date=date(1990, 1, 1),
            created_by=self.user,
            analysis_status='completed',
            ai_analysis={'bazi_analysis': 'Test BaZi analysis content'}
        )
    
    def test_admin_remarks_with_line_breaks(self):
        """Test that admin remarks with line breaks are preserved"""
        # Create a resolved report with multi-line admin remarks
        self.person.report_bazi_analysis('inaccurate_analysis', 'Test report message')
        self.person.bazi_report_status = 'resolved'
        self.person.bazi_report_resolved_by = self.admin
        self.person.bazi_report_resolved_at = timezone.now()
        self.person.bazi_report_admin_notes = 'Admin resolved this report\n\nWith multiple lines\nAnd line breaks'
        self.person.save()
        
        # Simulate API response that user site would receive
        api_client = APIClient()
        api_client.force_authenticate(user=self.user)
        
        url = reverse('api:bazi-analysis', kwargs={'pk': self.person.id})
        response = api_client.get(url)
        
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        data = response.json()
        
        # Verify admin remarks are preserved with line breaks
        self.assertEqual(data['bazi_report_admin_notes'], 'Admin resolved this report\n\nWith multiple lines\nAnd line breaks')
    
    def test_admin_remarks_with_special_characters(self):
        """Test that admin remarks with special characters are preserved"""
        # Create a resolved report with special characters
        self.person.report_bazi_analysis('inappropriate_content', 'Test report message')
        self.person.bazi_report_status = 'resolved'
        self.person.bazi_report_resolved_by = self.admin
        self.person.bazi_report_resolved_at = timezone.now()
        self.person.bazi_report_admin_notes = 'Admin remarks with special chars: 中文 🎯 <script>alert("test")</script> & "quotes"'
        self.person.save()
        
        # Simulate API response that user site would receive
        api_client = APIClient()
        api_client.force_authenticate(user=self.user)
        
        url = reverse('api:bazi-analysis', kwargs={'pk': self.person.id})
        response = api_client.get(url)
        
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        data = response.json()
        
        # Verify admin remarks are preserved with special characters
        self.assertEqual(data['bazi_report_admin_notes'], 'Admin remarks with special chars: 中文 🎯 <script>alert("test")</script> & "quotes"')


class DismissedReportDisplayTests(TestCase):
    """Test that dismissed reports show as pending to users"""
    
    def setUp(self):
        """Set up test data"""
        self.user = User.objects.create_user(
            phone='13800138000',
            email='user@example.com',
            first_name='测试',
            last_name='用户'
        )
        
        self.admin = User.objects.create_user(
            phone='13800138001',
            email='admin@example.com',
            first_name='管理员',
            last_name='用户',
            is_staff=True
        )
        
        # Create test data
        self.person = Person.objects.create(
            name='Dismissed Test',
            birth_date=date(1990, 1, 1),
            created_by=self.user,
            analysis_status='completed',
            ai_analysis={'bazi_analysis': 'Test BaZi analysis content'}
        )
    
    def test_dismissed_report_shows_as_pending_to_user(self):
        """Test that dismissed reports appear as pending to users"""
        # Create a dismissed report
        self.person.report_bazi_analysis('inaccurate_analysis', 'Test report message')
        self.person.bazi_report_status = 'dismissed'
        self.person.bazi_report_resolved_by = self.admin
        self.person.bazi_report_resolved_at = timezone.now()
        self.person.bazi_report_admin_notes = 'Admin dismissed this report'
        self.person.save()
        
        # Simulate API response that user site would receive
        api_client = APIClient()
        api_client.force_authenticate(user=self.user)
        
        url = reverse('api:bazi-analysis', kwargs={'pk': self.person.id})
        response = api_client.get(url)
        
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        data = response.json()
        
        # Verify that the report shows as pending to the user
        # (The frontend logic should handle this, but the API still returns the actual status)
        self.assertTrue(data['bazi_analysis_reported'])
        self.assertEqual(data['bazi_report_status'], 'dismissed')  # API returns actual status
        self.assertEqual(data['bazi_report_category'], 'inaccurate_analysis')
        self.assertEqual(data['bazi_report_message'], 'Test report message')
        self.assertIsNotNone(data['bazi_report_timestamp'])
        # Note: Frontend should hide admin notes for dismissed reports
        self.assertEqual(data['bazi_report_admin_notes'], 'Admin dismissed this report')
        self.assertIsNotNone(data['bazi_report_resolved_at'])


class ReportStatusTransitionTests(TestCase):
    """Test report status transitions and edge cases"""
    
    def setUp(self):
        """Set up test data"""
        self.user = User.objects.create_user(
            phone='13800138000',
            email='user@example.com',
            first_name='测试',
            last_name='用户'
        )
        
        self.admin = User.objects.create_user(
            phone='13800138001',
            email='admin@example.com',
            first_name='管理员',
            last_name='用户',
            is_staff=True
        )
        
        # Create test data
        self.person = Person.objects.create(
            name='Status Transition Test',
            birth_date=date(1990, 1, 1),
            created_by=self.user,
            analysis_status='completed',
            ai_analysis={'bazi_analysis': 'Test BaZi analysis content'}
        )
    
    def test_report_status_transitions(self):
        """Test all valid report status transitions"""
        # Step 1: Initial pending report
        self.person.report_bazi_analysis('inaccurate_analysis', 'Test report message')
        self.assertEqual(self.person.bazi_report_status, 'pending')
        
        # Step 2: Admin resolves
        self.person.bazi_report_status = 'resolved'
        self.person.bazi_report_resolved_by = self.admin
        self.person.bazi_report_resolved_at = timezone.now()
        self.person.bazi_report_admin_notes = 'Admin resolved this report'
        self.person.save()
        
        self.assertEqual(self.person.bazi_report_status, 'resolved')
        self.assertIsNotNone(self.person.bazi_report_resolved_by)
        self.assertIsNotNone(self.person.bazi_report_resolved_at)
        
        # Step 3: User re-reports (should reset to pending)
        self.person.report_bazi_analysis('inappropriate_content', 'Re-reporting after resolution')
        
        self.assertEqual(self.person.bazi_report_status, 'pending')
        self.assertIsNone(self.person.bazi_report_resolved_by)
        self.assertIsNone(self.person.bazi_report_resolved_at)
        self.assertIsNone(self.person.bazi_report_admin_notes)
        
        # Step 4: Admin dismisses
        self.person.bazi_report_status = 'dismissed'
        self.person.bazi_report_resolved_by = self.admin
        self.person.bazi_report_resolved_at = timezone.now()
        self.person.bazi_report_admin_notes = 'Admin dismissed this report'
        self.person.save()
        
        self.assertEqual(self.person.bazi_report_status, 'dismissed')
        
        # Step 5: User can re-report after dismissal
        self.person.report_bazi_analysis('technical_error', 'Re-reporting after dismissal')
        
        self.assertEqual(self.person.bazi_report_status, 'pending')
        self.assertIsNone(self.person.bazi_report_resolved_by)
        self.assertIsNone(self.person.bazi_report_resolved_at)
        self.assertIsNone(self.person.bazi_report_admin_notes)
    
    def test_email_flag_behavior(self):
        """Test email flag behavior during status transitions"""
        # Step 1: Initial report
        self.person.report_bazi_analysis('inaccurate_analysis', 'Test report message')
        self.assertFalse(self.person.bazi_report_resolution_email_sent)
        
        # Step 2: Admin resolves (should set email flag)
        self.person.bazi_report_status = 'resolved'
        self.person.bazi_report_resolved_by = self.admin
        self.person.bazi_report_resolved_at = timezone.now()
        self.person.bazi_report_admin_notes = 'Admin resolved this report'
        self.person.bazi_report_resolution_email_sent = True  # Simulate email sent
        self.person.save()
        
        self.assertTrue(self.person.bazi_report_resolution_email_sent)
        
        # Step 3: User re-reports (should reset email flag)
        self.person.report_bazi_analysis('inappropriate_content', 'Re-reporting after resolution')
        
        self.assertFalse(self.person.bazi_report_resolution_email_sent)
        
        # Step 4: Admin resolves again (should allow email to be sent)
        self.person.bazi_report_status = 'resolved'
        self.person.bazi_report_resolved_by = self.admin
        self.person.bazi_report_resolved_at = timezone.now()
        self.person.bazi_report_admin_notes = 'Admin resolved the re-report'
        self.person.save()
        
        self.assertFalse(self.person.bazi_report_resolution_email_sent)  # Ready for email to be sent 