"""
Analytics API Tests

Tests for permission gating and endpoint functionality.
"""
import pytest
from django.contrib.auth import get_user_model
from django.utils import timezone
from rest_framework.test import APIClient
from rest_framework.authtoken.models import Token
from datetime import timedelta

from core.models import Tenant
from schedule.models import Event, Resource, Service
from platform_admin.models import SubscriptionPlan

User = get_user_model()


@pytest.mark.django_db
class TestAnalyticsPermissions:
    """Test permission gating for analytics endpoints"""

    def setup_method(self):
        """Setup test data"""
        self.client = APIClient()

        # Create a tenant
        self.tenant = Tenant.objects.create(
            name="Test Business",
            schema_name="test_business"
        )

        # Create a user for this tenant
        self.user = User.objects.create_user(
            email="test@example.com",
            password="testpass123",
            role=User.Role.TENANT_OWNER,
            tenant=self.tenant
        )

        # Create auth token
        self.token = Token.objects.create(user=self.user)

        # Create subscription plan with advanced_analytics permission
        self.plan_with_analytics = SubscriptionPlan.objects.create(
            name="Professional",
            business_tier="PROFESSIONAL",
            permissions={"advanced_analytics": True}
        )

        # Create subscription plan WITHOUT advanced_analytics permission
        self.plan_without_analytics = SubscriptionPlan.objects.create(
            name="Starter",
            business_tier="STARTER",
            permissions={}
        )

    def test_analytics_requires_authentication(self):
        """Test that analytics endpoints require authentication"""
        response = self.client.get("/api/analytics/analytics/dashboard/")
        assert response.status_code == 401
        assert "Authentication credentials were not provided" in str(response.data)

    def test_analytics_denied_without_permission(self):
        """Test that analytics is denied without advanced_analytics permission"""
        # Assign plan without permission
        self.tenant.subscription_plan = self.plan_without_analytics
        self.tenant.save()

        self.client.credentials(HTTP_AUTHORIZATION=f"Token {self.token.key}")
        response = self.client.get("/api/analytics/analytics/dashboard/")

        assert response.status_code == 403
        assert "Advanced Analytics" in str(response.data)
        assert "upgrade your subscription" in str(response.data).lower()

    def test_analytics_allowed_with_permission(self):
        """Test that analytics is allowed with advanced_analytics permission"""
        # Assign plan with permission
        self.tenant.subscription_plan = self.plan_with_analytics
        self.tenant.save()

        self.client.credentials(HTTP_AUTHORIZATION=f"Token {self.token.key}")
        response = self.client.get("/api/analytics/analytics/dashboard/")

        assert response.status_code == 200
        assert "total_appointments_this_month" in response.data

    def test_dashboard_endpoint_structure(self):
        """Test dashboard endpoint returns correct data structure"""
        # Setup permission
        self.tenant.subscription_plan = self.plan_with_analytics
        self.tenant.save()

        self.client.credentials(HTTP_AUTHORIZATION=f"Token {self.token.key}")
        response = self.client.get("/api/analytics/analytics/dashboard/")

        assert response.status_code == 200

        # Check required fields
        required_fields = [
            'total_appointments_this_month',
            'total_appointments_all_time',
            'active_resources_count',
            'active_services_count',
            'upcoming_appointments_count',
            'average_appointment_duration_minutes',
            'peak_booking_day',
            'peak_booking_hour',
            'period'
        ]

        for field in required_fields:
            assert field in response.data, f"Missing field: {field}"

    def test_appointments_endpoint_with_filters(self):
        """Test appointments endpoint with query parameters"""
        self.tenant.subscription_plan = self.plan_with_analytics
        self.tenant.save()

        # Create test service and resource
        service = Service.objects.create(
            name="Haircut",
            business=self.tenant
        )

        resource = Resource.objects.create(
            name="Chair 1",
            business=self.tenant
        )

        # Create a test appointment
        now = timezone.now()
        Event.objects.create(
            title="Test Appointment",
            start_time=now,
            end_time=now + timedelta(hours=1),
            status="confirmed",
            service=service,
            business=self.tenant
        )

        self.client.credentials(HTTP_AUTHORIZATION=f"Token {self.token.key}")

        # Test without filters
        response = self.client.get("/api/analytics/analytics/appointments/")
        assert response.status_code == 200
        assert response.data['total'] >= 1

        # Test with days filter
        response = self.client.get("/api/analytics/analytics/appointments/?days=7")
        assert response.status_code == 200

        # Test with service filter
        response = self.client.get(f"/api/analytics/analytics/appointments/?service_id={service.id}")
        assert response.status_code == 200

    def test_revenue_requires_payments_permission(self):
        """Test that revenue analytics requires both permissions"""
        self.tenant.subscription_plan = self.plan_with_analytics
        self.tenant.save()

        self.client.credentials(HTTP_AUTHORIZATION=f"Token {self.token.key}")
        response = self.client.get("/api/analytics/analytics/revenue/")

        # Should be denied because tenant doesn't have can_accept_payments
        assert response.status_code == 403
        assert "Payment analytics not available" in str(response.data)

    def test_multiple_permission_check(self):
        """Test that both IsAuthenticated and HasFeaturePermission are checked"""
        self.tenant.subscription_plan = self.plan_with_analytics
        self.tenant.save()

        # No auth token = 401
        response = self.client.get("/api/analytics/analytics/dashboard/")
        assert response.status_code == 401

        # With auth but no permission = 403
        self.tenant.subscription_plan = self.plan_without_analytics
        self.tenant.save()

        self.client.credentials(HTTP_AUTHORIZATION=f"Token {self.token.key}")
        response = self.client.get("/api/analytics/analytics/dashboard/")
        assert response.status_code == 403


@pytest.mark.django_db
class TestAnalyticsData:
    """Test analytics data calculation"""

    def setup_method(self):
        """Setup test data"""
        self.client = APIClient()

        self.tenant = Tenant.objects.create(
            name="Test Business",
            schema_name="test_business"
        )

        self.user = User.objects.create_user(
            email="test@example.com",
            password="testpass123",
            role=User.Role.TENANT_OWNER,
            tenant=self.tenant
        )

        self.token = Token.objects.create(user=self.user)

        self.plan = SubscriptionPlan.objects.create(
            name="Professional",
            business_tier="PROFESSIONAL",
            permissions={"advanced_analytics": True}
        )

        self.tenant.subscription_plan = self.plan
        self.tenant.save()

        self.client.credentials(HTTP_AUTHORIZATION=f"Token {self.token.key}")

    def test_dashboard_counts_appointments_correctly(self):
        """Test that dashboard counts appointments accurately"""
        now = timezone.now()

        # Create appointments in current month
        for i in range(5):
            Event.objects.create(
                title=f"Appointment {i}",
                start_time=now + timedelta(hours=i),
                end_time=now + timedelta(hours=i+1),
                status="confirmed",
                business=self.tenant
            )

        # Create appointment in previous month
        last_month = now - timedelta(days=40)
        Event.objects.create(
            title="Old Appointment",
            start_time=last_month,
            end_time=last_month + timedelta(hours=1),
            status="confirmed",
            business=self.tenant
        )

        response = self.client.get("/api/analytics/analytics/dashboard/")

        assert response.status_code == 200
        assert response.data['total_appointments_this_month'] == 5
        assert response.data['total_appointments_all_time'] == 6

    def test_appointments_counts_by_status(self):
        """Test that appointments are counted by status"""
        now = timezone.now()

        # Create appointments with different statuses
        Event.objects.create(
            title="Confirmed",
            start_time=now,
            end_time=now + timedelta(hours=1),
            status="confirmed",
            business=self.tenant
        )

        Event.objects.create(
            title="Cancelled",
            start_time=now,
            end_time=now + timedelta(hours=1),
            status="cancelled",
            business=self.tenant
        )

        Event.objects.create(
            title="No Show",
            start_time=now,
            end_time=now + timedelta(hours=1),
            status="no_show",
            business=self.tenant
        )

        response = self.client.get("/api/analytics/analytics/appointments/")

        assert response.status_code == 200
        assert response.data['by_status']['confirmed'] == 1
        assert response.data['by_status']['cancelled'] == 1
        assert response.data['by_status']['no_show'] == 1
        assert response.data['total'] == 3

    def test_cancellation_rate_calculation(self):
        """Test cancellation rate is calculated correctly"""
        now = timezone.now()

        # Create 100 total appointments: 80 confirmed, 20 cancelled
        for i in range(80):
            Event.objects.create(
                title=f"Confirmed {i}",
                start_time=now,
                end_time=now + timedelta(hours=1),
                status="confirmed",
                business=self.tenant
            )

        for i in range(20):
            Event.objects.create(
                title=f"Cancelled {i}",
                start_time=now,
                end_time=now + timedelta(hours=1),
                status="cancelled",
                business=self.tenant
            )

        response = self.client.get("/api/analytics/analytics/appointments/")

        assert response.status_code == 200
        # 20 cancelled / 100 total = 20%
        assert response.data['cancellation_rate_percent'] == 20.0
