"""
ValidateEventOperator - Validate incoming webhook/API events.

This operator validates incoming document events from SeaweedFS webhooks
or direct API calls, extracting and validating metadata before processing.
"""

from airflow.models import BaseOperator
from uuid import UUID
from typing import Dict


class ValidateEventOperator(BaseOperator):
    """
    Validate incoming webhook/API event and extract metadata.

    Input: dag_run.conf with event payload
    Output: ValidatedEvent dict via XCom

    Supports two event formats:
    1. SeaweedFS webhook format (S3-compatible event notifications)
    2. Direct API trigger format (custom event structure)
    """

    # Issue #10 fix: Single source of truth for content types and extensions
    EXTENSION_TO_CONTENT_TYPE = {
        'xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
        'xls': 'application/vnd.ms-excel',
        'xlsm': 'application/vnd.ms-excel.sheet.macroEnabled.12',
        'docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
        'doc': 'application/msword',
        'docm': 'application/vnd.ms-word.document.macroEnabled.12',
        'pdf': 'application/pdf',
        'pptx': 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
        'ppt': 'application/vnd.ms-powerpoint',
        'pptm': 'application/vnd.ms-powerpoint.presentation.macroEnabled.12',
    }

    ALLOWED_CONTENT_TYPES = set(EXTENSION_TO_CONTENT_TYPE.values())
    MAX_FILE_SIZE = 100 * 1024 * 1024  # 100MB

    # Issue #13 fix: Magic string constants
    API_TRIGGER_EVENT_ID = 'api_trigger'
    DEFAULT_BUCKET = 'documents'

    def __init__(self, **kwargs):
        super().__init__(**kwargs)

    def execute(self, context) -> Dict:
        """
        Validate and extract event metadata.

        Args:
            context: Airflow task context containing dag_run.conf

        Returns:
            Dict: ValidatedEvent containing:
                - bucket: Storage bucket name
                - object_key: File path/key in storage
                - content_type: MIME type of the document
                - size_bytes: File size in bytes
                - document_id: Unique document identifier
                - event_id: Event identifier

        Raises:
            ValueError: If content type is unsupported or file is too large
            KeyError: If required fields are missing
        """
        print("CONTEXT HERE:", context)
        conf = context['dag_run'].conf or {}

        # Extract from SeaweedFS webhook format or direct API call
        if 'Records' in conf:
            # SeaweedFS webhook format
            self.log.info("Processing SeaweedFS webhook event")
            record = conf['Records'][0]['s3']
            event = {
                'bucket': record['bucket']['name'],
                'object_key': record['object']['key'],
                'content_type': record['object'].get('contentType'),
                'size_bytes': record['object'].get('size', 0),
                'document_id': conf.get('document_id'),
                'event_id': conf.get('EventName', 'direct'),
                # Tenant isolation context (data-isolation-spec Section 6.2)
                'tenant_id': conf.get('tenant_id', ''),
                'node_id': conf.get('node_id', ''),
            }
        else:
            # Direct API trigger format
            self.log.info("Processing direct API trigger event")
            event = {
                'bucket': conf.get('bucket', self.DEFAULT_BUCKET),
                'object_key': conf.get('object_key', conf.get('file_path', '')),
                'content_type': conf.get('content_type'),
                'size_bytes': conf.get('size_bytes', 0),
                'document_id': conf.get('document_id'),
                'event_id': self.API_TRIGGER_EVENT_ID,
                # Tenant isolation context (data-isolation-spec Section 6.2)
                'tenant_id': conf.get('tenant_id', ''),
                'node_id': conf.get('node_id', ''),
            }

        # Validate required fields
        if not event.get('object_key'):
            raise KeyError("Missing required field: object_key")
        if not event.get('document_id'):
            raise KeyError("Missing required field: document_id")

        # Validate content type (Issue #10 fix: use single mapping)
        # Note: Don't raise an exception for unsupported types - let detect_format
        # branch task route to unsupported_format instead
        if event.get('content_type') not in self.ALLOWED_CONTENT_TYPES:
            # Try to infer from file extension
            ext = event['object_key'].lower().split('.')[-1]
            if ext in self.EXTENSION_TO_CONTENT_TYPE:
                self.log.info(f"Inferred content type from extension: {ext}")
                event['content_type'] = self.EXTENSION_TO_CONTENT_TYPE[ext]
            else:
                self.log.warning(
                    f"Unsupported content type: {event.get('content_type')} "
                    f"(extension: {ext}). Will route to unsupported_format."
                )
                # Keep the original content_type (or None) - detect_format will handle routing

        # Validate file size
        if event.get('size_bytes', 0) > self.MAX_FILE_SIZE:
            raise ValueError(
                f"File too large: {event.get('size_bytes')} bytes "
                f"(max: {self.MAX_FILE_SIZE} bytes)"
            )

        # Validate document_id is UUID format
        try:
            UUID(str(event['document_id']))
        except (ValueError, AttributeError):
            self.log.warning(
                f"document_id is not a valid UUID: {event['document_id']}, continuing anyway"
            )

        self.log.info(
            f"Validated event for document: {event['document_id']}, "
            f"file: {event['object_key']}, "
            f"type: {event['content_type']}, "
            f"size: {event['size_bytes']} bytes"
        )

        return event
