"""
Serializers for the automations app.

Provides API serialization for:
- AutomationInfo (registry metadata)
- AutomationTemplate (marketplace templates)
- AutomationInstallation (installed automations)
- EventAutomation (automations attached to events)
- GlobalEventAutomation (rules for auto-attaching to all events)

Note: Field names in the serializers match the underlying model field names
(plugin_code, plugin_installation, etc.) for backwards compatibility.
"""

from rest_framework import serializers

from .models import (
    AutomationTemplate,
    AutomationInstallation,
    EventAutomation,
    GlobalEventAutomation,
)


class AutomationInfoSerializer(serializers.Serializer):
    """Serializer for automation metadata from registry"""

    name = serializers.CharField()
    display_name = serializers.CharField()
    description = serializers.CharField()
    category = serializers.CharField()
    config_schema = serializers.DictField()


class AutomationTemplateSerializer(serializers.ModelSerializer):
    """Serializer for AutomationTemplate model (alias for PluginTemplate)"""

    author_name = serializers.CharField(read_only=True)
    approved_by_name = serializers.SerializerMethodField()
    can_publish = serializers.SerializerMethodField()
    validation_errors = serializers.SerializerMethodField()

    class Meta:
        model = AutomationTemplate
        fields = [
            'id', 'name', 'slug', 'description', 'short_description',
            'plugin_code', 'plugin_code_hash', 'template_variables', 'default_config',
            'visibility', 'category', 'tags',
            'author', 'author_name', 'version', 'license_type', 'logo_url',
            'is_approved', 'approved_by', 'approved_by_name', 'approved_at', 'rejection_reason',
            'install_count', 'rating_average', 'rating_count',
            'created_at', 'updated_at', 'published_at',
            'can_publish', 'validation_errors',
        ]
        read_only_fields = [
            'id', 'slug', 'plugin_code_hash', 'template_variables',
            'author', 'author_name', 'is_approved', 'approved_by', 'approved_by_name',
            'approved_at', 'rejection_reason', 'install_count', 'rating_average',
            'rating_count', 'created_at', 'updated_at', 'published_at',
        ]

    def get_approved_by_name(self, obj):
        """Get name of user who approved the automation"""
        if obj.approved_by:
            return obj.approved_by.get_full_name() or obj.approved_by.username
        return None

    def get_can_publish(self, obj):
        """Check if automation can be published to marketplace"""
        return obj.can_be_published()

    def get_validation_errors(self, obj):
        """Get validation errors for publishing"""
        from smoothschedule.scheduling.schedule.safe_scripting import validate_plugin_whitelist
        validation = validate_plugin_whitelist(obj.plugin_code)
        if not validation['valid']:
            return validation['errors']
        return []

    def create(self, validated_data):
        """Set author from request user"""
        request = self.context.get('request')
        if request and hasattr(request, 'user'):
            validated_data['author'] = request.user
        return super().create(validated_data)

    def validate_plugin_code(self, value):
        """Validate plugin code and extract template variables"""
        if not value or not value.strip():
            raise serializers.ValidationError("Automation code cannot be empty")

        # Extract template variables
        from smoothschedule.scheduling.schedule.template_parser import TemplateVariableParser
        try:
            template_vars = TemplateVariableParser.extract_variables(value)
        except Exception as e:
            raise serializers.ValidationError(f"Failed to parse template variables: {str(e)}")

        return value


class AutomationTemplateListSerializer(serializers.ModelSerializer):
    """Lightweight serializer for automation template listing"""

    author_name = serializers.CharField(read_only=True)

    class Meta:
        model = AutomationTemplate
        fields = [
            'id', 'name', 'slug', 'short_description', 'description',
            'visibility', 'category', 'tags',
            'author_name', 'version', 'license_type', 'logo_url', 'is_approved',
            'install_count', 'rating_average', 'rating_count',
            'created_at', 'updated_at', 'published_at',
        ]
        read_only_fields = fields  # All fields are read-only for list view


class AutomationInstallationSerializer(serializers.ModelSerializer):
    """Serializer for AutomationInstallation model (alias for PluginInstallation)"""

    template_name = serializers.CharField(source='template.name', read_only=True)
    template_slug = serializers.CharField(source='template.slug', read_only=True)
    template_description = serializers.CharField(source='template.description', read_only=True)
    category = serializers.CharField(source='template.category', read_only=True)
    version = serializers.CharField(source='template.version', read_only=True)
    author_name = serializers.CharField(source='template.author_name', read_only=True)
    logo_url = serializers.CharField(source='template.logo_url', read_only=True)
    template_variables = serializers.JSONField(source='template.template_variables', read_only=True)
    scheduled_task_name = serializers.CharField(source='scheduled_task.name', read_only=True)
    installed_by_name = serializers.SerializerMethodField()
    has_update = serializers.SerializerMethodField()

    class Meta:
        model = AutomationInstallation
        fields = [
            'id', 'template', 'template_name', 'template_slug', 'template_description',
            'category', 'version', 'author_name', 'logo_url', 'template_variables',
            'scheduled_task', 'scheduled_task_name',
            'installed_by', 'installed_by_name', 'installed_at',
            'config_values', 'template_version_hash',
            'rating', 'review', 'reviewed_at',
            'has_update',
        ]
        read_only_fields = [
            'id', 'installed_by', 'installed_by_name', 'installed_at',
            'template_version_hash', 'reviewed_at',
        ]

    def get_installed_by_name(self, obj):
        """Get name of user who installed the automation"""
        if obj.installed_by:
            return obj.installed_by.get_full_name() or obj.installed_by.username
        return None

    def get_has_update(self, obj):
        """Check if template has been updated"""
        return obj.has_update_available()

    def create(self, validated_data):
        """
        Create automation installation.

        Installation makes the automation available in "My Automations".
        Scheduling is optional and done separately.
        """
        request = self.context.get('request')
        template = validated_data.get('template')

        # Set installed_by from request user
        if request and hasattr(request, 'user') and request.user.is_authenticated:
            validated_data['installed_by'] = request.user

        # Store template version hash for update detection
        if template:
            import hashlib
            validated_data['template_version_hash'] = hashlib.sha256(
                template.plugin_code.encode('utf-8')
            ).hexdigest()

        # Don't require scheduled_task on creation
        # It can be added later when user schedules the automation
        validated_data.pop('scheduled_task', None)

        return super().create(validated_data)


class EventAutomationSerializer(serializers.ModelSerializer):
    """
    Serializer for EventAutomation - attaching automations to calendar events.

    Provides a visual-friendly representation of when automations run:
    - trigger: 'before_start', 'at_start', 'after_start', 'after_end', 'on_complete', 'on_cancel'
    - offset_minutes: 0, 5, 10, 15, 30, 60 (for time-based triggers)
    """

    automation_name = serializers.CharField(source='plugin_installation.template.name', read_only=True)
    automation_description = serializers.CharField(source='plugin_installation.template.short_description', read_only=True)
    automation_category = serializers.CharField(source='plugin_installation.template.category', read_only=True)
    automation_logo_url = serializers.CharField(source='plugin_installation.template.logo_url', read_only=True)
    trigger_display = serializers.CharField(source='get_trigger_display', read_only=True)
    execution_time = serializers.SerializerMethodField()
    timing_description = serializers.SerializerMethodField()

    class Meta:
        model = EventAutomation
        fields = [
            'id',
            'event',
            'plugin_installation',  # Field name matches model
            'automation_name',
            'automation_description',
            'automation_category',
            'automation_logo_url',
            'trigger',
            'trigger_display',
            'offset_minutes',
            'timing_description',
            'execution_time',
            'is_active',
            'execution_order',
            'created_at',
        ]
        read_only_fields = ['id', 'created_at']

    def get_execution_time(self, obj):
        """Get the calculated execution time"""
        exec_time = obj.get_execution_time()
        return exec_time.isoformat() if exec_time else None

    def get_timing_description(self, obj):
        """
        Generate a human-readable description of when the automation runs.
        Examples: "At start", "10 minutes before start", "30 minutes after end"
        """
        trigger = obj.trigger
        offset = obj.offset_minutes

        if trigger == EventAutomation.Trigger.BEFORE_START:
            if offset == 0:
                return "At start"
            return f"{offset} min before start"
        elif trigger == EventAutomation.Trigger.AT_START:
            if offset == 0:
                return "At start"
            return f"{offset} min after start"
        elif trigger == EventAutomation.Trigger.AFTER_START:
            if offset == 0:
                return "At start"
            return f"{offset} min after start"
        elif trigger == EventAutomation.Trigger.AFTER_END:
            if offset == 0:
                return "At end"
            return f"{offset} min after end"
        elif trigger == EventAutomation.Trigger.ON_COMPLETE:
            return "When completed"
        elif trigger == EventAutomation.Trigger.ON_CANCEL:
            return "When canceled"
        return "Unknown"

    def validate(self, attrs):
        """Validate that offset makes sense for the trigger type"""
        trigger = attrs.get('trigger', EventAutomation.Trigger.AT_START)
        offset = attrs.get('offset_minutes', 0)

        # Event-driven triggers don't use offset
        if trigger in [EventAutomation.Trigger.ON_COMPLETE, EventAutomation.Trigger.ON_CANCEL]:
            if offset != 0:
                attrs['offset_minutes'] = 0  # Auto-correct instead of error

        return attrs


class GlobalEventAutomationSerializer(serializers.ModelSerializer):
    """
    Serializer for GlobalEventAutomation - rules for auto-attaching automations to ALL events.

    When created, automatically applies to:
    1. All existing events
    2. All future events as they are created
    """

    automation_name = serializers.CharField(source='plugin_installation.template.name', read_only=True)
    automation_description = serializers.CharField(source='plugin_installation.template.short_description', read_only=True)
    automation_category = serializers.CharField(source='plugin_installation.template.category', read_only=True)
    automation_logo_url = serializers.CharField(source='plugin_installation.template.logo_url', read_only=True)
    trigger_display = serializers.CharField(source='get_trigger_display', read_only=True)
    timing_description = serializers.SerializerMethodField()
    events_count = serializers.SerializerMethodField()

    class Meta:
        model = GlobalEventAutomation
        fields = [
            'id',
            'plugin_installation',  # Field name matches model
            'automation_name',
            'automation_description',
            'automation_category',
            'automation_logo_url',
            'trigger',
            'trigger_display',
            'offset_minutes',
            'timing_description',
            'is_active',
            'apply_to_existing',
            'execution_order',
            'events_count',
            'created_at',
            'updated_at',
            'created_by',
        ]
        read_only_fields = ['id', 'created_at', 'updated_at', 'created_by']

    def get_timing_description(self, obj):
        """Generate a human-readable description of when the automation runs."""
        trigger = obj.trigger
        offset = obj.offset_minutes

        if trigger == 'before_start':
            if offset == 0:
                return "At start"
            return f"{offset} min before start"
        elif trigger == 'at_start':
            if offset == 0:
                return "At start"
            return f"{offset} min after start"
        elif trigger == 'after_start':
            if offset == 0:
                return "At start"
            return f"{offset} min after start"
        elif trigger == 'after_end':
            if offset == 0:
                return "At end"
            return f"{offset} min after end"
        elif trigger == 'on_complete':
            return "When completed"
        elif trigger == 'on_cancel':
            return "When canceled"
        return "Unknown"

    def get_events_count(self, obj):
        """Get the count of events this rule applies to."""
        return EventAutomation.objects.filter(
            plugin_installation=obj.plugin_installation,
            trigger=obj.trigger,
            offset_minutes=obj.offset_minutes,
        ).count()

    def validate(self, attrs):
        """Validate the global event automation configuration."""
        trigger = attrs.get('trigger', 'at_start')
        offset = attrs.get('offset_minutes', 0)

        # Event-driven triggers don't use offset
        if trigger in ['on_complete', 'on_cancel']:
            if offset != 0:
                attrs['offset_minutes'] = 0

        return attrs

    def create(self, validated_data):
        """Create the global rule and apply to existing events."""
        # Set the created_by from request context
        request = self.context.get('request')
        if request and hasattr(request, 'user'):
            validated_data['created_by'] = request.user

        return super().create(validated_data)
