"""
Schema Registry Service.

Manages event schema registration, retrieval, and compatibility checking.
"""
import logging
from typing import Dict, List, Optional, Tuple

from django.utils import timezone

from .models import EventSchemaRegistry

logger = logging.getLogger(__name__)


class SchemaRegistry:
    """
    Service for managing event schemas and their versions.
    
    Provides schema registration, retrieval, deprecation,
    and version comparison functionality.
    
    Example:
        registry = SchemaRegistry()
        
        # Register a schema
        registry.register(
            event_type='plm.part.created',
            version='1.0.0',
            schema={
                'type': 'object',
                'properties': {
                    'part_id': {'type': 'string', 'format': 'uuid'},
                    'name': {'type': 'string'},
                },
                'required': ['part_id', 'name'],
            },
            publisher_module='plm',
        )
        
        # Get latest schema
        schema = registry.get_latest_schema('plm.part.created')
    """

    @staticmethod
    def register(
        event_type: str,
        version: str,
        schema: Dict,
        description: str = '',
        publisher_module: str = '',
        subscriber_modules: Optional[List[str]] = None,
        example_payload: Optional[Dict] = None,
        migration_notes: str = '',
        migration_script: str = '',
    ) -> EventSchemaRegistry:
        """
        Register or update an event schema version.
        
        Args:
            event_type: Dot-notated event type
            version: Semver version string
            schema: JSON Schema for the event payload
            description: Human-readable description
            publisher_module: Module that publishes this event
            subscriber_modules: List of subscribing modules
            example_payload: Example payload for documentation
            migration_notes: Notes about changes from previous version
            migration_script: Python code for version migration
            
        Returns:
            EventSchemaRegistry instance
        """
        entry, created = EventSchemaRegistry.objects.update_or_create(
            event_type=event_type,
            version=version,
            defaults={
                'schema': schema,
                'description': description,
                'publisher_module': publisher_module,
                'subscriber_modules': subscriber_modules or [],
                'example_payload': example_payload or {},
                'migration_notes': migration_notes,
                'migration_script': migration_script,
            }
        )

        action = 'Registered' if created else 'Updated'
        logger.info(f"{action} schema for {event_type} v{version}")
        return entry

    @staticmethod
    def get_schema(
        event_type: str,
        version: str,
    ) -> Optional[EventSchemaRegistry]:
        """Get a specific schema version."""
        try:
            return EventSchemaRegistry.objects.get(
                event_type=event_type,
                version=version,
            )
        except EventSchemaRegistry.DoesNotExist:
            return None

    @staticmethod
    def get_latest_schema(event_type: str) -> Optional[EventSchemaRegistry]:
        """
        Get the latest non-deprecated schema for an event type.
        Uses semver ordering (major.minor.patch).
        """
        schemas = EventSchemaRegistry.objects.filter(
            event_type=event_type,
            is_deprecated=False,
        ).order_by('-version')

        # Sort by semver (descending)
        schema_list = list(schemas)
        if not schema_list:
            return None

        def parse_version(v: str) -> Tuple[int, ...]:
            try:
                return tuple(int(x) for x in v.split('.'))
            except (ValueError, AttributeError):
                return (0, 0, 0)

        schema_list.sort(key=lambda s: parse_version(s.version), reverse=True)
        return schema_list[0]

    @staticmethod
    def get_all_versions(event_type: str) -> List[EventSchemaRegistry]:
        """Get all versions of a schema, ordered by version."""
        return list(
            EventSchemaRegistry.objects.filter(
                event_type=event_type
            ).order_by('version')
        )

    @staticmethod
    def deprecate(
        event_type: str,
        version: str,
        sunset_date=None,
    ) -> Optional[EventSchemaRegistry]:
        """
        Mark a schema version as deprecated.
        
        Args:
            event_type: Event type
            version: Version to deprecate
            sunset_date: Optional date when this version will stop being supported
        """
        try:
            entry = EventSchemaRegistry.objects.get(
                event_type=event_type,
                version=version,
            )
            entry.is_deprecated = True
            entry.deprecated_at = timezone.now()
            if sunset_date:
                entry.sunset_date = sunset_date
            entry.save(update_fields=[
                'is_deprecated', 'deprecated_at', 'sunset_date', 'updated_at'
            ])
            logger.info(f"Deprecated schema {event_type} v{version}")
            return entry
        except EventSchemaRegistry.DoesNotExist:
            return None

    @staticmethod
    def get_all_event_types() -> List[str]:
        """Get list of all registered event types."""
        return list(
            EventSchemaRegistry.objects.values_list(
                'event_type', flat=True
            ).distinct().order_by('event_type')
        )

    @staticmethod
    def get_events_by_module(module_name: str) -> List[EventSchemaRegistry]:
        """Get all events published by a specific module."""
        return list(
            EventSchemaRegistry.objects.filter(
                publisher_module=module_name,
            ).order_by('event_type', 'version')
        )
