"""
Unit tests for puck_data validation and security sanitization.

Tests size limits, structure validation, and XSS/injection prevention.
"""
from unittest.mock import Mock, patch
import pytest
import json


class TestPuckDataStructureValidation:
    """Test puck_data structure validation."""

    def test_valid_puck_data_passes(self):
        """Should accept valid Puck data structure."""
        from smoothschedule.platform.tenant_sites.serializers import PageSerializer

        valid_data = {
            'title': 'Test Page',
            'puck_data': {
                'content': [
                    {
                        'type': 'Hero',
                        'props': {
                            'id': 'hero-1',
                            'title': 'Welcome',
                            'subtitle': 'Subtitle',
                            'align': 'center'
                        }
                    }
                ],
                'root': {}
            }
        }

        serializer = PageSerializer(data=valid_data)
        is_valid = serializer.is_valid()

        # If validation passes, errors should be empty or puck_data should not have errors
        if not is_valid:
            assert 'puck_data' not in serializer.errors

    def test_rejects_missing_content_array(self):
        """Should reject puck_data without content array."""
        from smoothschedule.platform.tenant_sites.serializers import PageSerializer

        invalid_data = {
            'title': 'Test Page',
            'puck_data': {
                'root': {}
            }
        }

        serializer = PageSerializer(data=invalid_data)
        serializer.is_valid()

        # Validation should fail for invalid structure
        assert 'puck_data' in serializer.errors or not serializer.is_valid()

    def test_rejects_non_list_content(self):
        """Should reject puck_data with non-list content."""
        from smoothschedule.platform.tenant_sites.serializers import PageSerializer

        invalid_data = {
            'title': 'Test Page',
            'puck_data': {
                'content': 'not a list',
                'root': {}
            }
        }

        serializer = PageSerializer(data=invalid_data)
        is_valid = serializer.is_valid()

        # Should either not validate or have puck_data error
        if is_valid:
            # If it passes basic validation, detailed check should fail
            pass  # Will test in actual implementation


class TestPuckDataSizeLimit:
    """Test puck_data size limit validation."""

    def test_accepts_data_under_limit(self):
        """Should accept puck_data under 5MB."""
        from smoothschedule.platform.tenant_sites.serializers import PageSerializer

        # Create data well under limit
        small_data = {
            'title': 'Test Page',
            'puck_data': {
                'content': [{'type': 'Hero', 'props': {'title': 'Test'}}],
                'root': {}
            }
        }

        serializer = PageSerializer(data=small_data)
        is_valid = serializer.is_valid()

        # Should not have size-related errors
        if not is_valid:
            error_str = str(serializer.errors.get('puck_data', ''))
            assert 'too large' not in error_str.lower()

    def test_rejects_data_over_limit(self):
        """Should reject puck_data over 5MB."""
        from smoothschedule.platform.tenant_sites.serializers import PageSerializer

        # Create data over 5MB
        large_content = 'x' * (5 * 1024 * 1024 + 1)  # Just over 5MB
        oversized_data = {
            'title': 'Test Page',
            'puck_data': {
                'content': [{'type': 'Hero', 'props': {'title': large_content}}],
                'root': {}
            }
        }

        serializer = PageSerializer(data=oversized_data)
        is_valid = serializer.is_valid()

        # Should fail validation
        assert is_valid is False or 'puck_data' in serializer.errors


class TestPuckDataXssPrevention:
    """Test puck_data XSS/script injection prevention."""

    def test_rejects_script_tags(self):
        """Should reject puck_data containing script tags."""
        from smoothschedule.platform.tenant_sites.serializers import PageSerializer

        malicious_data = {
            'title': 'Test Page',
            'puck_data': {
                'content': [
                    {
                        'type': 'TextSection',
                        'props': {
                            'heading': 'Normal',
                            'body': '<script>alert("xss")</script>'
                        }
                    }
                ],
                'root': {}
            }
        }

        serializer = PageSerializer(data=malicious_data)
        is_valid = serializer.is_valid()

        # Should fail validation for script tags
        assert is_valid is False

    def test_rejects_javascript_urls(self):
        """Should reject puck_data containing javascript: URLs."""
        from smoothschedule.platform.tenant_sites.serializers import PageSerializer

        malicious_data = {
            'title': 'Test Page',
            'puck_data': {
                'content': [
                    {
                        'type': 'Hero',
                        'props': {
                            'title': 'Click me',
                            'ctaLink': 'javascript:alert("xss")'
                        }
                    }
                ],
                'root': {}
            }
        }

        serializer = PageSerializer(data=malicious_data)
        is_valid = serializer.is_valid()

        # Should fail validation for javascript: URLs
        assert is_valid is False

    def test_rejects_onerror_attributes(self):
        """Should reject puck_data containing onerror handlers."""
        from smoothschedule.platform.tenant_sites.serializers import PageSerializer

        malicious_data = {
            'title': 'Test Page',
            'puck_data': {
                'content': [
                    {
                        'type': 'Image',
                        'props': {
                            'src': 'x',
                            'alt': 'onerror=alert("xss")'
                        }
                    }
                ],
                'root': {}
            }
        }

        serializer = PageSerializer(data=malicious_data)
        is_valid = serializer.is_valid()

        # Should fail validation for onerror handlers
        assert is_valid is False

    def test_rejects_onload_attributes(self):
        """Should reject puck_data containing onload handlers."""
        from smoothschedule.platform.tenant_sites.serializers import PageSerializer

        malicious_data = {
            'title': 'Test Page',
            'puck_data': {
                'content': [
                    {
                        'type': 'Image',
                        'props': {
                            'src': 'x',
                            'onload': 'alert("xss")'
                        }
                    }
                ],
                'root': {}
            }
        }

        serializer = PageSerializer(data=malicious_data)
        is_valid = serializer.is_valid()

        # Should fail validation for onload handlers
        assert is_valid is False

    def test_accepts_safe_content(self):
        """Should accept safe content without XSS patterns."""
        from smoothschedule.platform.tenant_sites.serializers import PageSerializer

        safe_data = {
            'title': 'Test Page',
            'puck_data': {
                'content': [
                    {
                        'type': 'Hero',
                        'props': {
                            'id': 'hero-1',
                            'title': 'Welcome to our site',
                            'subtitle': 'We offer great services',
                            'align': 'center',
                            'ctaText': 'Book Now',
                            'ctaLink': '/book'
                        }
                    }
                ],
                'root': {}
            }
        }

        serializer = PageSerializer(data=safe_data)
        is_valid = serializer.is_valid()

        # Should pass validation
        if not is_valid:
            # If it fails, it should not be due to XSS detection
            error_str = str(serializer.errors.get('puck_data', ''))
            assert 'disallowed' not in error_str.lower()


class TestPuckDataEmbedAllowlist:
    """Test embed URL allowlist validation."""

    def test_accepts_google_maps_embed(self):
        """Should accept Google Maps embed URLs."""
        from smoothschedule.platform.tenant_sites.validators import validate_embed_url

        valid_url = 'https://www.google.com/maps/embed?pb=...'

        # Should not raise
        result = validate_embed_url(valid_url)
        assert result is True

    def test_accepts_openstreetmap_embed(self):
        """Should accept OpenStreetMap embed URLs."""
        from smoothschedule.platform.tenant_sites.validators import validate_embed_url

        valid_url = 'https://www.openstreetmap.org/export/embed.html?...'

        # Should not raise
        result = validate_embed_url(valid_url)
        assert result is True

    def test_rejects_arbitrary_embed(self):
        """Should reject non-allowlisted embed URLs."""
        from smoothschedule.platform.tenant_sites.validators import validate_embed_url

        invalid_url = 'https://evil-site.com/embed'

        # Should return False or raise
        result = validate_embed_url(invalid_url)
        assert result is False

    def test_rejects_data_uri(self):
        """Should reject data: URIs in embeds."""
        from smoothschedule.platform.tenant_sites.validators import validate_embed_url

        data_uri = 'data:text/html,<script>alert("xss")</script>'

        result = validate_embed_url(data_uri)
        assert result is False


class TestPuckDataValidatorFunction:
    """Test the validate_puck_data validator function."""

    def test_validator_exists(self):
        """Should have validate_puck_data function."""
        from smoothschedule.platform.tenant_sites.validators import validate_puck_data

        assert callable(validate_puck_data)

    def test_validator_returns_cleaned_data(self):
        """Should return the puck_data if valid."""
        from smoothschedule.platform.tenant_sites.validators import validate_puck_data

        valid_data = {
            'content': [{'type': 'Hero', 'props': {'title': 'Test'}}],
            'root': {}
        }

        result = validate_puck_data(valid_data)

        assert result == valid_data

    def test_validator_raises_for_invalid(self):
        """Should raise ValidationError for invalid data."""
        from smoothschedule.platform.tenant_sites.validators import validate_puck_data
        from rest_framework.exceptions import ValidationError

        invalid_data = {
            'content': [{'type': 'Hero', 'props': {'title': '<script>bad</script>'}}],
            'root': {}
        }

        with pytest.raises(ValidationError):
            validate_puck_data(invalid_data)
