from django.test import TestCase
from django.urls import reverse
from rest_framework import status
from rest_framework.test import APIClient
from main.user.user import User
from bazi.models import Person
from liuyao.models import liuyao
from accounts.utils import create_temporary_user


class SingleRecordCreationTestCase(TestCase):
    """Test that single API calls create only one record each"""
    
    def setUp(self):
        """Set up test data"""
        self.api_client = APIClient()
        
        # Test data for BaZi API
        self.bazi_api_data = {
            'name': 'API Test Person',
            'gender': 'M',
            'birth_date': '1990-01-01',
            'birth_time': '12:00:00',
            'notes': 'API test notes'
        }
        
        # Test data for LiuYao API
        self.liuyao_data = {
            'qdate': '2024-01-01T12:00:00Z',  # Required field
            'question': 'Test question for API',
            'y1': '0',
            'y2': '0', 
            'y3': '0',
            'y4': '000',
            'y5': '0',
            'y6': '1'
        }
        
        # Test data for LiuYao Calculator API
        self.liuyao_calc_data = {
            'year': 2024,
            'month': 1,
            'day': 1,
            'time': '12:00',
            'question': 'Test question for calculator API',
            'y1': '0',
            'y2': '0',
            'y3': '0',
            'y4': '000',
            'y5': '0',
            'y6': '1'
        }
    
    def test_single_bazi_api_call_creates_single_record(self):
        """Test that one BaZi API call creates exactly one User and one Person record"""
        # Check initial state
        initial_user_count = User.objects.count()
        initial_person_count = Person.objects.count()
        
        # Manually create temp user (simulating middleware)
        temp_user = create_temporary_user()
        
        # Authenticate with the temp user
        self.api_client.force_authenticate(user=temp_user)
        
        # Make single API call
        response = self.api_client.post(
            reverse('api:bazi-list'),
            self.bazi_api_data,
            format='json'
        )
        
        # Verify successful response
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        response_data = response.json()
        self.assertIn('message', response_data)
        self.assertIn('id', response_data)  # Should have record ID
        
        # Verify exactly one new user created (should be the same temp user we created)
        final_user_count = User.objects.count()
        self.assertEqual(final_user_count, initial_user_count + 1, "Should create exactly one user")
        
        # Verify exactly one new Person record created
        final_person_count = Person.objects.count()
        self.assertEqual(final_person_count, initial_person_count + 1, "Should create exactly one Person record")
        
        # Verify the record has complete data
        person_record = Person.objects.filter(created_by=temp_user).first()
        self.assertIsNotNone(person_record)
        self.assertEqual(person_record.name, 'API Test Person')
        self.assertIsNotNone(person_record.birth_time)  # Should have complete data (not None from signal)
        self.assertTrue(person_record.created_by_temp_user)
    
    def test_single_liuyao_api_call_creates_single_record(self):
        """Test that one LiuYao API call creates exactly one User and one LiuYao record"""
        # Check initial state
        initial_user_count = User.objects.count()
        initial_liuyao_count = liuyao.objects.count()
        
        # Manually create temp user (simulating middleware)
        temp_user = create_temporary_user()
        
        # Authenticate with the temp user
        self.api_client.force_authenticate(user=temp_user)
        
        # Make single API call
        response = self.api_client.post(
            '/api/liuyao/liuyao/',
            self.liuyao_data,
            format='json'
        )
        
        # Verify successful response
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        response_data = response.json()
        
        # Verify exactly one new user created (should be the same temp user we created)
        final_user_count = User.objects.count()
        self.assertEqual(final_user_count, initial_user_count + 1, "Should create exactly one user")
        
        # Verify exactly one new LiuYao record created
        final_liuyao_count = liuyao.objects.count()
        self.assertEqual(final_liuyao_count, initial_liuyao_count + 1, "Should create exactly one LiuYao record")
        
        # Verify the record has complete data
        liuyao_record = liuyao.objects.filter(user=temp_user).first()
        self.assertIsNotNone(liuyao_record)
        self.assertEqual(liuyao_record.question, 'Test question for API')
        self.assertTrue(liuyao_record.created_by_temp_user)
    
    def test_multiple_api_calls_single_temp_user(self):
        """Test that multiple API calls from same session use the same temp user"""
        # Check initial state
        initial_user_count = User.objects.count()
        initial_person_count = Person.objects.count()
        initial_liuyao_count = liuyao.objects.count()
        
        # Manually create temp user (simulating middleware)
        temp_user = create_temporary_user()
        
        # Authenticate with the temp user for all calls
        self.api_client.force_authenticate(user=temp_user)
        
        # First API call - BaZi
        bazi_response = self.api_client.post(
            reverse('api:bazi-list'),
            self.bazi_api_data,
            format='json'
        )
        self.assertEqual(bazi_response.status_code, status.HTTP_201_CREATED)
        
        # Second API call - LiuYao
        liuyao_response = self.api_client.post(
            '/api/liuyao/liuyao/',
            self.liuyao_data,
            format='json'
        )
        self.assertEqual(liuyao_response.status_code, status.HTTP_201_CREATED)
        
        # Verify only one temp user was created total
        final_user_count = User.objects.count()
        self.assertEqual(final_user_count, initial_user_count + 1, "Should reuse the same temp user")
        
        # Verify both records were created
        final_person_count = Person.objects.count()
        final_liuyao_count = liuyao.objects.count()
        self.assertEqual(final_person_count, initial_person_count + 1)
        self.assertEqual(final_liuyao_count, initial_liuyao_count + 1)
        
        # Verify both records belong to the same temp user
        self.assertEqual(Person.objects.filter(created_by=temp_user).count(), 1)
        self.assertEqual(liuyao.objects.filter(user=temp_user).count(), 1)
    
    def test_single_liuyao_calculator_api_call_calculation_only(self):
        """Test that unauthenticated LiuYao Calculator API call only performs calculation (no saving)"""
        # Check initial state
        initial_user_count = User.objects.count()
        initial_liuyao_count = liuyao.objects.count()
        
        # Make single API call to calculator endpoint (unauthenticated)
        response = self.api_client.post(
            '/api/liuyao/calc/',
            self.liuyao_calc_data,
            format='json'
        )
        
        # Verify successful response (calculation only)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        response_data = response.json()
        
        # Should contain calculation results
        self.assertIn('gua', response_data)
        self.assertIn('question', response_data)
        self.assertIn('yao', response_data)
        
        # Should NOT contain save-related fields or temp user info
        self.assertNotIn('temp_user', response_data)
        self.assertNotIn('id', response_data)
        self.assertNotIn('created_by', response_data)
        
        # Verify no new user or record created (calculation only)
        final_user_count = User.objects.count()
        final_liuyao_count = liuyao.objects.count()
        self.assertEqual(final_user_count, initial_user_count, "Should not create any users")
        self.assertEqual(final_liuyao_count, initial_liuyao_count, "Should not create any LiuYao records") 