"""
Unit tests for ValidateEventOperator.
"""

import pytest
from unittest.mock import Mock, MagicMock
from plugins.operators.validate_event import ValidateEventOperator


class TestValidateEventOperator:
    """Test suite for ValidateEventOperator."""

    @pytest.fixture
    def mock_context(self):
        """Create a mock Airflow context."""
        context = {
            'dag_run': Mock(),
            'ti': Mock(),
        }
        context['dag_run'].conf = {}
        return context

    def test_valid_seaweedfs_webhook(self, mock_context):
        """Test SeaweedFS webhook payload validation."""
        mock_context['dag_run'].conf = {
            'Records': [{
                's3': {
                    'bucket': {'name': 'documents'},
                    'object': {
                        'key': 'test/sample.xlsx',
                        'contentType': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
                        'size': 1024,
                    }
                }
            }],
            'document_id': 'test-uuid-123',
            'EventName': 's3:ObjectCreated:Put'
        }

        op = ValidateEventOperator(task_id='test')
        result = op.execute(mock_context)

        assert result['bucket'] == 'documents'
        assert result['object_key'] == 'test/sample.xlsx'
        assert result['content_type'] == 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
        assert result['size_bytes'] == 1024
        assert result['document_id'] == 'test-uuid-123'
        assert result['event_id'] == 's3:ObjectCreated:Put'

    def test_valid_api_trigger(self, mock_context):
        """Test direct API trigger format validation."""
        mock_context['dag_run'].conf = {
            'bucket': 'my-bucket',
            'file_path': 'documents/test.pdf',
            'content_type': 'application/pdf',
            'size_bytes': 2048,
            'document_id': 'api-doc-456',
        }

        op = ValidateEventOperator(task_id='test')
        result = op.execute(mock_context)

        assert result['bucket'] == 'my-bucket'
        assert result['object_key'] == 'documents/test.pdf'
        assert result['content_type'] == 'application/pdf'
        assert result['size_bytes'] == 2048
        assert result['document_id'] == 'api-doc-456'
        assert result['event_id'] == 'api_trigger'

    def test_infer_content_type_from_extension(self, mock_context):
        """Test content type inference from file extension."""
        mock_context['dag_run'].conf = {
            'file_path': 'test/document.docx',
            'document_id': 'test-doc',
            'size_bytes': 500,
        }

        op = ValidateEventOperator(task_id='test')
        result = op.execute(mock_context)

        assert result['content_type'] == 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'

    def test_unsupported_content_type_passes_through(self, mock_context):
        """Test that unsupported file types pass through for branching to handle."""
        mock_context['dag_run'].conf = {
            'content_type': 'application/zip',
            'size_bytes': 100,
            'file_path': 'test.zip',
            'document_id': 'test-id',
        }

        op = ValidateEventOperator(task_id='test')
        result = op.execute(mock_context)

        # Unsupported types should pass through with original content_type
        # detect_format branch task will route to unsupported_format
        assert result['object_key'] == 'test.zip'
        assert result['content_type'] == 'application/zip'
        assert result['document_id'] == 'test-id'

    def test_png_file_passes_through(self, mock_context):
        """Test that PNG files pass through for branching to route to unsupported_format."""
        mock_context['dag_run'].conf = {
            'file_path': 'uploads/a3de04f8/chatbot-sidebar.png',
            'document_id': 'a3de04f8-73df-4fdd-97d0-81350d8fdfa3',
            'size_bytes': 50000,
        }

        op = ValidateEventOperator(task_id='test')
        result = op.execute(mock_context)

        # PNG should pass through with None content_type
        # detect_format branch task will route to unsupported_format
        assert result['object_key'] == 'uploads/a3de04f8/chatbot-sidebar.png'
        assert result['content_type'] is None
        assert result['document_id'] == 'a3de04f8-73df-4fdd-97d0-81350d8fdfa3'

    def test_file_too_large_raises(self, mock_context):
        """Test that files exceeding MAX_FILE_SIZE raise ValueError."""
        mock_context['dag_run'].conf = {
            'file_path': 'large/file.xlsx',
            'content_type': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
            'size_bytes': 150 * 1024 * 1024,  # 150MB > 100MB limit
            'document_id': 'large-doc',
        }

        op = ValidateEventOperator(task_id='test')

        with pytest.raises(ValueError, match='File too large'):
            op.execute(mock_context)

    def test_missing_document_id_raises(self, mock_context):
        """Test that missing document_id raises KeyError."""
        mock_context['dag_run'].conf = {
            'file_path': 'test.xlsx',
            'content_type': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
            'size_bytes': 1000,
        }

        op = ValidateEventOperator(task_id='test')

        with pytest.raises(KeyError, match='document_id'):
            op.execute(mock_context)

    def test_missing_file_path_raises(self, mock_context):
        """Test that missing file_path/object_key raises KeyError."""
        mock_context['dag_run'].conf = {
            'content_type': 'application/pdf',
            'size_bytes': 1000,
            'document_id': 'test-id',
        }

        op = ValidateEventOperator(task_id='test')

        with pytest.raises(KeyError, match='object_key'):
            op.execute(mock_context)

    def test_supported_file_extensions(self, mock_context):
        """Test all supported file extensions."""
        extensions = {
            'xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
            'xls': 'application/vnd.ms-excel',
            'docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
            'doc': 'application/msword',
            'pdf': 'application/pdf',
            'pptx': 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
        }

        op = ValidateEventOperator(task_id='test')

        for ext, expected_content_type in extensions.items():
            mock_context['dag_run'].conf = {
                'file_path': f'test/file.{ext}',
                'document_id': f'test-{ext}',
                'size_bytes': 1000,
            }

            result = op.execute(mock_context)
            assert result['content_type'] == expected_content_type

    def test_empty_conf_uses_defaults(self, mock_context):
        """Test that empty conf with defaults still validates required fields."""
        mock_context['dag_run'].conf = {}

        op = ValidateEventOperator(task_id='test')

        with pytest.raises(KeyError):
            op.execute(mock_context)
