from django.test import TestCase
from django.contrib.admin.sites import site
from django.contrib.auth import get_user_model
from django.utils import timezone
from django.test import RequestFactory
from django.contrib.messages.storage.fallback import FallbackStorage
from django.urls import reverse
from datetime import date, time
from bazi.models import Person
from bazi.admin import PersonAdmin, reset_ai_analysis
import json

User = get_user_model()

class PersonAdminTestCase(TestCase):
    """Test cases for Person admin functionality."""
    
    def setUp(self):
        """Set up test data."""
        self.user = User.objects.create_user(
            phone="1000000001",
            email="test@example.com",
            first_name="Test",
            last_name="User"
        )
        
        self.person = Person.objects.create(
            name="Test Person",
            birth_date=date(1990, 1, 1),
            birth_time=time(10, 0, 0),
            created_by=self.user
        )
        
        # Set up some AI analysis data
        self.person.ai_analysis = {
            'bazi_analysis': {
                'personality_analysis': 'Test personality analysis',
                'career_wealth': 'Test career analysis'
            },
            'provider': 'groq',
            'model': 'llama-3.3-70b-versatile',
            'prompt': 'Test prompt'
        }
        self.person.analysis_timestamp = timezone.now()
        self.person.analysis_status = 'completed'
        self.person.save()
        
        self.admin = PersonAdmin(Person, site)
        self.factory = RequestFactory()
    
    def _get_request(self):
        """Create a proper request object with messages support."""
        request = self.factory.post('/admin/')
        request.user = self.user
        # Add messages framework support
        setattr(request, 'session', {})
        messages = FallbackStorage(request)
        setattr(request, '_messages', messages)
        return request
    
    def test_reset_ai_analysis_action(self):
        """Test that the reset AI analysis action properly clears the analysis fields."""
        # Verify that the person has AI analysis data
        self.assertIsNotNone(self.person.ai_analysis)
        self.assertIsNotNone(self.person.analysis_timestamp)
        self.assertEqual(self.person.analysis_status, 'completed')
        
        # Create a queryset with the person
        queryset = Person.objects.filter(id=self.person.id)
        
        # Create a proper request object
        request = self._get_request()
        
        # Call the reset action
        reset_ai_analysis(self.admin, request, queryset)
        
        # Refresh the person from database
        self.person.refresh_from_db()
        
        # Verify that the AI analysis fields have been reset
        self.assertIsNone(self.person.ai_analysis)
        self.assertIsNone(self.person.analysis_timestamp)
        self.assertIsNone(self.person.analysis_status)
    
    def test_reset_ai_analysis_action_multiple_persons(self):
        """Test that the reset action works for multiple persons."""
        # Create another person with AI analysis
        person2 = Person.objects.create(
            name="Test Person 2",
            birth_date=date(1991, 2, 2),
            birth_time=time(11, 0, 0),
            created_by=self.user
        )
        
        person2.ai_analysis = {
            'bazi_analysis': 'Another test analysis',
            'provider': 'openai',
            'model': 'gpt-4o'
        }
        person2.analysis_timestamp = timezone.now()
        person2.analysis_status = 'completed'
        person2.save()
        
        # Create a queryset with both persons
        queryset = Person.objects.filter(id__in=[self.person.id, person2.id])
        
        # Create a proper request object
        request = self._get_request()
        
        # Call the reset action
        reset_ai_analysis(self.admin, request, queryset)
        
        # Refresh both persons from database
        self.person.refresh_from_db()
        person2.refresh_from_db()
        
        # Verify that both persons' AI analysis fields have been reset
        self.assertIsNone(self.person.ai_analysis)
        self.assertIsNone(self.person.analysis_timestamp)
        self.assertIsNone(self.person.analysis_status)
        
        self.assertIsNone(person2.ai_analysis)
        self.assertIsNone(person2.analysis_timestamp)
        self.assertIsNone(person2.analysis_status)
    
    def test_admin_actions_are_registered(self):
        """Test that the admin actions are properly registered."""
        # Check that both actions are in the admin's actions
        action_names = []
        for action in self.admin.actions:
            if hasattr(action, '__name__'):
                action_names.append(action.__name__)
            else:
                action_names.append(action)  # String references
        self.assertIn('generate_ai_analysis', action_names)
        self.assertIn('reset_ai_analysis', action_names)
    
    def test_reset_ai_analysis_button_with_analysis(self):
        """Test that the reset button appears when person has AI analysis."""
        button_html = self.admin.reset_ai_analysis_button(self.person)
        
        # Should contain a reset button
        self.assertIn('Reset AI Analysis', button_html)
        self.assertIn('🗑️', button_html)
        self.assertIn('href=', button_html)
        self.assertIn('onclick=', button_html)  # Should have confirmation dialog
        self.assertIn(self.person.name, button_html)  # Should mention person's name in confirmation
    
    def test_reset_ai_analysis_button_without_analysis(self):
        """Test that no reset button appears when person has no AI analysis."""
        # Clear the AI analysis
        self.person.ai_analysis = None
        self.person.save()
        
        button_html = self.admin.reset_ai_analysis_button(self.person)
        
        # Should show message that there's no analysis to reset
        self.assertIn('No AI analysis to reset', button_html)
        self.assertNotIn('href=', button_html)  # Should not be a link
    
    def test_reset_ai_analysis_button_new_object(self):
        """Test that reset button shows appropriate message for unsaved objects."""
        # Create a new person object that hasn't been saved yet
        new_person = Person(
            name="Unsaved Person",
            birth_date=date(1992, 3, 3),
            birth_time=time(12, 0, 0),
            created_by=self.user
        )
        
        button_html = self.admin.reset_ai_analysis_button(new_person)
        
        # Should show message to save first
        self.assertIn('Save the person first', button_html)
        self.assertNotIn('href=', button_html)  # Should not be a link
    
    def test_custom_urls_are_registered(self):
        """Test that the custom reset URL is properly registered."""
        urls = self.admin.get_urls()
        url_names = [url.name for url in urls if hasattr(url, 'name')]
        
        # Should include our custom reset URL
        self.assertIn('bazi_person_reset_ai_analysis', url_names)


