"""
Tests for file upload security enhancements
"""

from unittest.mock import patch

from django.test import TestCase, override_settings
from django.core.files.uploadedfile import SimpleUploadedFile
from django.contrib.auth.models import User

from ivatar.file_security import (
    FileValidator,
    validate_uploaded_file,
    get_file_security_report,
)
from ivatar.ivataraccount.forms import UploadPhotoForm


class FileSecurityTestCase(TestCase):
    """Test cases for file upload security"""

    def setUp(self):
        """Set up test data"""
        self.user = User.objects.create_user(
            username="testuser", email="test@example.com", password="testpass123"
        )

        # Create test image data
        self.valid_jpeg_data = b"\xff\xd8\xff\xe0\x00\x10JFIF\x00\x01\x01\x01\x00H\x00H\x00\x00\xff\xdb\x00C\x00\x08\x06\x06\x07\x06\x05\x08\x07\x07\x07\t\t\x08\n\x0c\x14\r\x0c\x0b\x0b\x0c\x19\x12\x13\x0f\x14\x1d\x1a\x1f\x1e\x1d\x1a\x1c\x1c $.' \",#\x1c\x1c(7),01444\x1f'9=82<.342\xff\xc0\x00\x11\x08\x00\x01\x00\x01\x01\x01\x11\x00\x02\x11\x01\x03\x11\x01\xff\xc4\x00\x1f\x00\x00\x01\x05\x01\x01\x01\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\xff\xc4\x00\xb5\x10\x00\x02\x01\x03\x03\x02\x04\x03\x05\x05\x04\x04\x00\x00\x01}\x01\x02\x03\x00\x04\x11\x05\x12!1A\x06\x13Qa\x07\"q\x142\x81\x91\xa1\x08#B\xb1\xc1\x15R\xd1\xf0$3br\x82\t\n\x16\x17\x18\x19\x1a%&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz\x83\x84\x85\x86\x87\x88\x89\x8a\x92\x93\x94\x95\x96\x97\x98\x99\x9a\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xff\xda\x00\x0c\x03\x01\x00\x02\x11\x03\x11\x00\x3f\x00\xf9\xff\xd9"

        self.malicious_data = b'GIF89a<script>alert("xss")</script>'
        self.large_data = b"x" * (10 * 1024 * 1024)  # 10MB

    def tearDown(self):
        """Clean up after tests"""
        pass

    def test_valid_jpeg_validation(self):
        """Test validation of valid JPEG file"""
        validator = FileValidator(self.valid_jpeg_data, "test.jpg")

        # Mock PIL validation to avoid issues with test data
        with patch.object(validator, "validate_pil_image") as mock_pil:
            mock_pil.return_value = {
                "valid": True,
                "image_info": {
                    "format": "JPEG",
                    "mode": "RGB",
                    "size": (100, 100),
                    "width": 100,
                    "height": 100,
                    "has_transparency": False,
                },
                "errors": [],
                "warnings": [],
            }

            results = validator.comprehensive_validation()

            self.assertTrue(results["valid"])
            self.assertEqual(results["file_info"]["detected_type"], "image/jpeg")
            self.assertGreaterEqual(results["security_score"], 80)

    def test_magic_bytes_validation(self):
        """Test magic bytes validation"""
        validator = FileValidator(self.valid_jpeg_data, "test.jpg")
        results = validator.validate_magic_bytes()

        self.assertTrue(results["valid"])
        self.assertEqual(results["detected_type"], "image/jpeg")

    def test_malicious_content_detection(self):
        """Test detection of malicious content"""
        validator = FileValidator(self.malicious_data, "malicious.gif")
        results = validator.scan_for_malicious_content()

        self.assertTrue(results["suspicious"])
        self.assertGreater(len(results["threats"]), 0)

    def test_file_size_validation(self):
        """Test file size validation"""
        validator = FileValidator(self.large_data, "large.jpg")
        results = validator.validate_basic()

        self.assertFalse(results["valid"])
        self.assertIn("File too large", results["errors"][0])

    def test_invalid_extension_validation(self):
        """Test invalid file extension validation"""
        validator = FileValidator(self.valid_jpeg_data, "test.exe")
        results = validator.validate_basic()

        self.assertFalse(results["valid"])
        self.assertIn("File extension not allowed", results["errors"][0])

    def test_exif_sanitization(self):
        """Test EXIF data sanitization"""
        validator = FileValidator(self.valid_jpeg_data, "test.jpg")
        sanitized_data = validator.sanitize_exif_data()

        # Should return data (may be same or sanitized)
        self.assertIsInstance(sanitized_data, bytes)
        self.assertGreater(len(sanitized_data), 0)

    def test_comprehensive_validation_function(self):
        """Test the main validation function"""
        # Mock PIL validation to avoid issues with test data
        with patch("ivatar.file_security.FileValidator.validate_pil_image") as mock_pil:
            mock_pil.return_value = {
                "valid": True,
                "image_info": {"format": "JPEG", "size": (100, 100)},
                "errors": [],
                "warnings": [],
            }

            is_valid, results, sanitized_data = validate_uploaded_file(
                self.valid_jpeg_data, "test.jpg"
            )

            self.assertTrue(is_valid)
            self.assertIsInstance(results, dict)
            self.assertIsInstance(sanitized_data, bytes)

    def test_security_report_generation(self):
        """Test security report generation"""
        # Mock PIL validation to avoid issues with test data
        with patch("ivatar.file_security.FileValidator.validate_pil_image") as mock_pil:
            mock_pil.return_value = {
                "valid": True,
                "image_info": {"format": "JPEG", "size": (100, 100)},
                "errors": [],
                "warnings": [],
            }

            report = get_file_security_report(self.valid_jpeg_data, "test.jpg")

            self.assertIn("valid", report)
            self.assertIn("security_score", report)
            self.assertIn("file_info", report)

    @patch("ivatar.file_security.magic.from_buffer")
    def test_mime_type_validation(self, mock_magic):
        """Test MIME type validation with mocked magic"""
        mock_magic.return_value = "image/jpeg"

        validator = FileValidator(self.valid_jpeg_data, "test.jpg")
        results = validator.validate_mime_type()

        self.assertTrue(results["valid"])
        self.assertEqual(results["detected_mime"], "image/jpeg")

    def test_polyglot_attack_detection(self):
        """Test detection of polyglot attacks"""
        polyglot_data = b'GIF89a<script>alert("xss")</script>'
        validator = FileValidator(polyglot_data, "polyglot.gif")
        results = validator.scan_for_malicious_content()

        self.assertTrue(results["suspicious"])
        # Check for either polyglot attack or suspicious script pattern
        threats_text = " ".join(results["threats"]).lower()
        self.assertTrue(
            "polyglot attack" in threats_text or "suspicious pattern" in threats_text,
            f"Expected polyglot attack or suspicious pattern, got: {results['threats']}",
        )


class UploadPhotoFormSecurityTestCase(TestCase):
    """Test cases for UploadPhotoForm security enhancements"""

    def setUp(self):
        """Set up test data"""
        self.user = User.objects.create_user(
            username="testuser", email="test@example.com", password="testpass123"
        )

    def test_form_validation_with_valid_file(self):
        """Test form validation with valid file"""
        valid_jpeg_data = b"\xff\xd8\xff\xe0\x00\x10JFIF\x00\x01\x01\x01\x00H\x00H\x00\x00\xff\xdb\x00C\x00\x08\x06\x06\x07\x06\x05\x08\x07\x07\x07\t\t\x08\n\x0c\x14\r\x0c\x0b\x0b\x0c\x19\x12\x13\x0f\x14\x1d\x1a\x1f\x1e\x1d\x1a\x1c\x1c $.' \",#\x1c\x1c(7),01444\x1f'9=82<.342\xff\xc0\x00\x11\x08\x00\x01\x00\x01\x01\x01\x11\x00\x02\x11\x01\x03\x11\x01\xff\xc4\x00\x1f\x00\x00\x01\x05\x01\x01\x01\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\xff\xc4\x00\xb5\x10\x00\x02\x01\x03\x03\x02\x04\x03\x05\x05\x04\x04\x00\x00\x01}\x01\x02\x03\x00\x04\x11\x05\x12!1A\x06\x13Qa\x07\"q\x142\x81\x91\xa1\x08#B\xb1\xc1\x15R\xd1\xf0$3br\x82\t\n\x16\x17\x18\x19\x1a%&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz\x83\x84\x85\x86\x87\x88\x89\x8a\x92\x93\x94\x95\x96\x97\x98\x99\x9a\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xff\xda\x00\x0c\x03\x01\x00\x02\x11\x03\x11\x00\x3f\x00\xf9\xff\xd9"

        uploaded_file = SimpleUploadedFile(
            "test.jpg", valid_jpeg_data, content_type="image/jpeg"
        )

        form_data = {"photo": uploaded_file, "not_porn": True, "can_distribute": True}

        form = UploadPhotoForm(data=form_data, files={"photo": uploaded_file})

        # Mock the validation to avoid PIL issues in tests
        with patch(
            "ivatar.ivataraccount.forms.validate_uploaded_file"
        ) as mock_validate:
            mock_validate.return_value = (
                True,
                {"security_score": 95, "errors": [], "warnings": []},
                valid_jpeg_data,
            )

            self.assertTrue(form.is_valid())

    def test_form_validation_with_malicious_file(self):
        """Test form validation with malicious file"""
        malicious_data = b'GIF89a<script>alert("xss")</script>'

        uploaded_file = SimpleUploadedFile(
            "malicious.gif", malicious_data, content_type="image/gif"
        )

        form_data = {"photo": uploaded_file, "not_porn": True, "can_distribute": True}

        form = UploadPhotoForm(data=form_data, files={"photo": uploaded_file})

        # Mock the validation to return malicious file detection
        with patch(
            "ivatar.ivataraccount.forms.validate_uploaded_file"
        ) as mock_validate:
            mock_validate.return_value = (
                False,
                {
                    "security_score": 20,
                    "errors": ["Malicious content detected"],
                    "warnings": [],
                },
                malicious_data,
            )

            self.assertFalse(form.is_valid())
            # Check for any error message indicating validation failure
            error_text = str(form.errors["photo"]).lower()
            self.assertTrue(
                "malicious" in error_text or "validation failed" in error_text,
                f"Expected malicious or validation failed message, got: {form.errors['photo']}",
            )


class UploadPhotoViewSecurityTestCase(TestCase):
    """Test cases for UploadPhotoView security enhancements"""

    def setUp(self):
        """Set up test data"""
        self.user = User.objects.create_user(
            username="testuser", email="test@example.com", password="testpass123"
        )

    def tearDown(self):
        """Clean up after tests"""
        pass


@override_settings(
    ENABLE_FILE_SECURITY_VALIDATION=True,
    ENABLE_EXIF_SANITIZATION=True,
    ENABLE_MALICIOUS_CONTENT_SCAN=True,
    ENABLE_RATE_LIMITING=True,
)
class FileSecurityIntegrationTestCase(TestCase):
    """Integration tests for file upload security"""

    def setUp(self):
        """Set up test data"""
        self.user = User.objects.create_user(
            username="testuser", email="test@example.com", password="testpass123"
        )

    def test_end_to_end_security_validation(self):
        """Test end-to-end security validation"""
        # This would test the complete flow from upload to storage
        # with all security checks enabled
        pass

    def test_security_logging(self):
        """Test that security events are properly logged"""
        # This would test that security events are logged
        # when malicious files are uploaded
        pass
