# -*- coding: utf-8 -*-
"""
Campaigns App Tests

This module contains test cases for the campaigns app.
"""

from django.test import TestCase, Client
from django.urls import reverse
from django.contrib.auth import get_user_model
from django.utils import timezone
from decimal import Decimal
from rest_framework.test import APITestCase
from rest_framework import status

from .models import Campaign
from apps.advertisers.models import Advertiser, Agency

User = get_user_model()


class CampaignModelTest(TestCase):
    """
    Test cases for Campaign model.
    """
    
    def setUp(self):
        self.user = User.objects.create_user(
            username='testuser',
            email='test@example.com',
            password='testpass123'
        )
        
        self.agency = Agency.objects.create(
            name='Test Agency',
            email='agency@example.com'
        )
        self.agency.users.add(self.user)
        
        self.advertiser = Advertiser.objects.create(
            name='Test Advertiser',
            email='advertiser@example.com',
            agency=self.agency
        )
    
    def test_campaign_creation(self):
        """
        Test campaign creation with valid data.
        """
        campaign = Campaign.objects.create(
            name='Test Campaign',
            description='Test campaign description',
            advertiser=self.advertiser,
            budget=Decimal('1000.00'),
            start_date=timezone.now().date(),
            end_date=timezone.now().date() + timezone.timedelta(days=30)
        )
        
        self.assertEqual(campaign.name, 'Test Campaign')
        self.assertEqual(campaign.advertiser, self.advertiser)
        self.assertEqual(campaign.status, 'draft')  # Default status
        self.assertTrue(campaign.is_active)
    
    def test_campaign_str_representation(self):
        """
        Test string representation of campaign.
        """
        campaign = Campaign.objects.create(
            name='Test Campaign',
            advertiser=self.advertiser,
            budget=Decimal('1000.00')
        )
        
        self.assertEqual(str(campaign), 'Test Campaign')
    
    def test_campaign_budget_validation(self):
        """
        Test campaign budget validation.
        """
        campaign = Campaign(
            name='Test Campaign',
            advertiser=self.advertiser,
            budget=Decimal('-100.00')  # Negative budget
        )
        
        with self.assertRaises(Exception):
            campaign.full_clean()
    
    def test_campaign_date_validation(self):
        """
        Test campaign date validation.
        """
        campaign = Campaign(
            name='Test Campaign',
            advertiser=self.advertiser,
            budget=Decimal('1000.00'),
            start_date=timezone.now().date() + timezone.timedelta(days=30),
            end_date=timezone.now().date()  # End date before start date
        )
        
        with self.assertRaises(Exception):
            campaign.full_clean()


class CampaignViewTest(TestCase):
    """
    Test cases for Campaign views.
    """
    
    def setUp(self):
        self.client = Client()
        self.user = User.objects.create_user(
            username='testuser',
            email='test@example.com',
            password='testpass123'
        )
        
        self.agency = Agency.objects.create(
            name='Test Agency',
            email='agency@example.com'
        )
        self.agency.users.add(self.user)
        
        self.advertiser = Advertiser.objects.create(
            name='Test Advertiser',
            email='advertiser@example.com',
            agency=self.agency
        )
        
        self.campaign = Campaign.objects.create(
            name='Test Campaign',
            description='Test campaign description',
            advertiser=self.advertiser,
            budget=Decimal('1000.00')
        )
    
    def test_campaign_dashboard_view(self):
        """
        Test campaign dashboard view.
        """
        self.client.login(username='testuser', password='testpass123')
        response = self.client.get(reverse('campaigns:dashboard'))
        
        self.assertEqual(response.status_code, 200)
        self.assertContains(response, 'Test Campaign')
    
    def test_campaign_list_view(self):
        """
        Test campaign list view.
        """
        self.client.login(username='testuser', password='testpass123')
        response = self.client.get(reverse('campaigns:list'))
        
        self.assertEqual(response.status_code, 200)
        self.assertContains(response, 'Test Campaign')
    
    def test_campaign_detail_view(self):
        """
        Test campaign detail view.
        """
        self.client.login(username='testuser', password='testpass123')
        response = self.client.get(
            reverse('campaigns:detail', kwargs={'pk': self.campaign.pk})
        )
        
        self.assertEqual(response.status_code, 200)
        self.assertContains(response, 'Test Campaign')
    
    def test_campaign_create_view_get(self):
        """
        Test campaign create view GET request.
        """
        self.client.login(username='testuser', password='testpass123')
        response = self.client.get(reverse('campaigns:create'))
        
        self.assertEqual(response.status_code, 200)
    
    def test_campaign_create_view_post(self):
        """
        Test campaign create view POST request.
        """
        self.client.login(username='testuser', password='testpass123')
        data = {
            'name': 'New Campaign',
            'description': 'New campaign description',
            'advertiser': self.advertiser.pk,
            'budget': '2000.00',
            'status': 'draft'
        }
        
        response = self.client.post(reverse('campaigns:create'), data)
        
        self.assertEqual(response.status_code, 302)  # Redirect after creation
        self.assertTrue(Campaign.objects.filter(name='New Campaign').exists())
    
    def test_campaign_update_view(self):
        """
        Test campaign update view.
        """
        self.client.login(username='testuser', password='testpass123')
        data = {
            'name': 'Updated Campaign',
            'description': 'Updated description',
            'budget': '1500.00',
            'status': 'active'
        }
        
        response = self.client.post(
            reverse('campaigns:edit', kwargs={'pk': self.campaign.pk}),
            data
        )
        
        self.assertEqual(response.status_code, 302)
        self.campaign.refresh_from_db()
        self.assertEqual(self.campaign.name, 'Updated Campaign')
    
    def test_campaign_delete_view(self):
        """
        Test campaign delete view.
        """
        self.client.login(username='testuser', password='testpass123')
        response = self.client.post(
            reverse('campaigns:delete', kwargs={'pk': self.campaign.pk})
        )
        
        self.assertEqual(response.status_code, 302)
        self.assertFalse(Campaign.objects.filter(pk=self.campaign.pk).exists())
    
    def test_unauthorized_access(self):
        """
        Test unauthorized access to campaign views.
        """
        response = self.client.get(reverse('campaigns:dashboard'))
        self.assertEqual(response.status_code, 302)  # Redirect to login


class CampaignAPITest(APITestCase):
    """
    Test cases for Campaign API endpoints.
    """
    
    def setUp(self):
        self.user = User.objects.create_user(
            username='testuser',
            email='test@example.com',
            password='testpass123'
        )
        
        self.agency = Agency.objects.create(
            name='Test Agency',
            email='agency@example.com'
        )
        self.agency.users.add(self.user)
        
        self.advertiser = Advertiser.objects.create(
            name='Test Advertiser',
            email='advertiser@example.com',
            agency=self.agency
        )
        
        self.campaign = Campaign.objects.create(
            name='Test Campaign',
            description='Test campaign description',
            advertiser=self.advertiser,
            budget=Decimal('1000.00')
        )
    
    def test_campaign_list_api(self):
        """
        Test campaign list API endpoint.
        """
        self.client.force_authenticate(user=self.user)
        response = self.client.get('/campaigns/api/campaigns/')
        
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(response.data['results']), 1)
    
    def test_campaign_detail_api(self):
        """
        Test campaign detail API endpoint.
        """
        self.client.force_authenticate(user=self.user)
        response = self.client.get(f'/campaigns/api/campaigns/{self.campaign.pk}/')
        
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(response.data['name'], 'Test Campaign')
    
    def test_campaign_create_api(self):
        """
        Test campaign create API endpoint.
        """
        self.client.force_authenticate(user=self.user)
        data = {
            'name': 'API Campaign',
            'description': 'Created via API',
            'advertiser': self.advertiser.pk,
            'budget': '2000.00',
            'status': 'draft'
        }
        
        response = self.client.post('/campaigns/api/campaigns/', data)
        
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        self.assertTrue(Campaign.objects.filter(name='API Campaign').exists())
    
    def test_campaign_update_api(self):
        """
        Test campaign update API endpoint.
        """
        self.client.force_authenticate(user=self.user)
        data = {
            'name': 'Updated API Campaign',
            'description': 'Updated via API',
            'advertiser': self.advertiser.pk,
            'budget': '1500.00',
            'status': 'active'
        }
        
        response = self.client.put(f'/campaigns/api/campaigns/{self.campaign.pk}/', data)
        
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.campaign.refresh_from_db()
        self.assertEqual(self.campaign.name, 'Updated API Campaign')
    
    def test_campaign_delete_api(self):
        """
        Test campaign delete API endpoint.
        """
        self.client.force_authenticate(user=self.user)
        response = self.client.delete(f'/campaigns/api/campaigns/{self.campaign.pk}/')
        
        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
        self.assertFalse(Campaign.objects.filter(pk=self.campaign.pk).exists())
    
    def test_campaign_activate_api(self):
        """
        Test campaign activate API endpoint.
        """
        self.client.force_authenticate(user=self.user)
        response = self.client.post(f'/campaigns/api/campaigns/{self.campaign.pk}/activate/')
        
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.campaign.refresh_from_db()
        self.assertEqual(self.campaign.status, 'active')
    
    def test_campaign_statistics_api(self):
        """
        Test campaign statistics API endpoint.
        """
        self.client.force_authenticate(user=self.user)
        response = self.client.get('/campaigns/api/campaigns/statistics/')
        
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertIn('total_campaigns', response.data)
        self.assertEqual(response.data['total_campaigns'], 1)
    
    def test_unauthorized_api_access(self):
        """
        Test unauthorized access to API endpoints.
        """
        response = self.client.get('/campaigns/api/campaigns/')
        self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)