"""
Workflow Serializers.

Django REST Framework serializers for workflow models.
"""
from rest_framework import serializers
from django.contrib.auth import get_user_model
from django.contrib.auth.models import Group

from .models import (
    ProcessDefinition,
    ProcessInstance,
    Task,
    TaskAssignment,
    ProcessVariable,
    ProcessHistory,
    SLADefinition,
    SLAViolation,
    InstanceStatus,
    TaskStatus,
    TaskType,
    AssignmentType,
    HistoryEventType,
)


User = get_user_model()


# =============================================================================
# Nested/Helper Serializers
# =============================================================================

class UserMinimalSerializer(serializers.ModelSerializer):
    """Minimal user serializer for nested representation."""
    
    class Meta:
        model = User
        fields = ('id', 'email', 'first_name', 'last_name')
        read_only_fields = fields


class GroupMinimalSerializer(serializers.ModelSerializer):
    """Minimal group serializer for nested representation."""
    
    class Meta:
        model = Group
        fields = ('id', 'name')
        read_only_fields = fields


# =============================================================================
# Process Definition Serializers
# =============================================================================

class ProcessDefinitionListSerializer(serializers.ModelSerializer):
    """Serializer for listing process definitions."""
    created_by = UserMinimalSerializer(read_only=True)
    instances_count = serializers.IntegerField(read_only=True, default=0)
    
    class Meta:
        model = ProcessDefinition
        fields = (
            'id',
            'slug',
            'name',
            'description',
            'version',
            'is_deployed',
            'is_active',
            'deployed_at',
            'created_by',
            'created_at',
            'updated_at',
            'instances_count',
        )
        read_only_fields = fields


class ProcessDefinitionDetailSerializer(serializers.ModelSerializer):
    """Serializer for process definition details."""
    created_by = UserMinimalSerializer(read_only=True)
    sla_definitions = serializers.SerializerMethodField()
    
    class Meta:
        model = ProcessDefinition
        fields = (
            'id',
            'slug',
            'name',
            'description',
            'bpmn_xml',
            'metadata',
            'version',
            'is_deployed',
            'is_active',
            'deployed_at',
            'created_by',
            'created_at',
            'updated_at',
            'sla_definitions',
        )
        read_only_fields = (
            'id',
            'version',
            'deployed_at',
            'created_by',
            'created_at',
            'updated_at',
        )

    def get_sla_definitions(self, obj):
        slas = obj.sla_definitions.filter(is_active=True)
        return SLADefinitionSerializer(slas, many=True).data


class ProcessDefinitionCreateSerializer(serializers.ModelSerializer):
    """Serializer for creating process definitions."""
    
    class Meta:
        model = ProcessDefinition
        fields = (
            'slug',
            'name',
            'description',
            'bpmn_xml',
            'metadata',
        )

    def validate_slug(self, value):
        """Validate slug uniqueness within tenant for the same version."""
        tenant = self.context['request'].user.tenant
        if ProcessDefinition.objects.filter(
            tenant=tenant,
            slug=value,
            version=1  # New definitions always start at version 1
        ).exists():
            raise serializers.ValidationError(
                "A process definition with this slug already exists."
            )
        return value

    def create(self, validated_data):
        request = self.context['request']
        validated_data['tenant'] = request.user.tenant
        validated_data['created_by'] = request.user
        validated_data['version'] = 1
        return super().create(validated_data)


class ProcessDefinitionUpdateSerializer(serializers.ModelSerializer):
    """Serializer for updating process definitions (draft only)."""
    
    class Meta:
        model = ProcessDefinition
        fields = (
            'name',
            'description',
            'bpmn_xml',
            'metadata',
        )

    def validate(self, attrs):
        if self.instance.is_deployed:
            raise serializers.ValidationError(
                "Cannot edit a deployed process definition. Create a new version instead."
            )
        return attrs


class ProcessDefinitionDeploySerializer(serializers.Serializer):
    """Serializer for deploying a process definition."""
    
    def validate(self, attrs):
        if self.instance.is_deployed:
            raise serializers.ValidationError(
                "This process definition is already deployed."
            )
        if not self.instance.bpmn_xml:
            raise serializers.ValidationError(
                "Cannot deploy a process definition without BPMN XML."
            )
        return attrs


class ProcessDefinitionVersionSerializer(serializers.Serializer):
    """Serializer for creating a new version of a process definition."""
    copy_sla = serializers.BooleanField(default=True)


# =============================================================================
# Process Instance Serializers
# =============================================================================

class ProcessInstanceListSerializer(serializers.ModelSerializer):
    """Serializer for listing process instances."""
    definition_name = serializers.CharField(source='definition.name', read_only=True)
    definition_slug = serializers.CharField(source='definition.slug', read_only=True)
    started_by = UserMinimalSerializer(read_only=True)
    status_display = serializers.CharField(source='get_status_display', read_only=True)
    active_tasks_count = serializers.SerializerMethodField()
    
    class Meta:
        model = ProcessInstance
        fields = (
            'id',
            'definition',
            'definition_name',
            'definition_slug',
            'business_key',
            'status',
            'status_display',
            'started_by',
            'started_at',
            'completed_at',
            'active_tasks_count',
        )
        read_only_fields = fields

    def get_active_tasks_count(self, obj):
        if hasattr(obj, 'active_tasks'):
            return len(obj.active_tasks)
        return obj.tasks.active().count()


class ProcessInstanceDetailSerializer(serializers.ModelSerializer):
    """Serializer for process instance details."""
    definition = ProcessDefinitionListSerializer(read_only=True)
    started_by = UserMinimalSerializer(read_only=True)
    status_display = serializers.CharField(source='get_status_display', read_only=True)
    variables = serializers.SerializerMethodField()
    active_tasks = serializers.SerializerMethodField()
    
    class Meta:
        model = ProcessInstance
        fields = (
            'id',
            'definition',
            'business_key',
            'status',
            'status_display',
            'context',
            'current_element_ids',
            'started_by',
            'started_at',
            'completed_at',
            'cancelled_at',
            'error_message',
            'variables',
            'active_tasks',
        )
        read_only_fields = fields

    def get_variables(self, obj):
        variables = obj.variables.all()
        return ProcessVariableSerializer(variables, many=True).data

    def get_active_tasks(self, obj):
        tasks = obj.tasks.active().select_related('assignee')
        return TaskListSerializer(tasks, many=True).data


class ProcessInstanceStartSerializer(serializers.Serializer):
    """Serializer for starting a process instance."""
    definition_slug = serializers.SlugField()
    business_key = serializers.CharField(max_length=255, required=False, allow_blank=True)
    variables = serializers.JSONField(required=False, default=dict)

    def validate_definition_slug(self, value):
        request = self.context['request']
        definition = ProcessDefinition.objects.filter(
            tenant=request.user.tenant,
            slug=value,
            is_deployed=True,
            is_active=True
        ).order_by('-version').first()
        
        if not definition:
            raise serializers.ValidationError(
                f"No active deployed process definition found with slug '{value}'."
            )
        
        self.validated_definition = definition
        return value

    def create(self, validated_data):
        request = self.context['request']
        instance = ProcessInstance.objects.create(
            tenant=request.user.tenant,
            definition=self.validated_definition,
            business_key=validated_data.get('business_key', ''),
            started_by=request.user,
            context=validated_data.get('variables', {}),
            status=InstanceStatus.RUNNING
        )
        return instance


class ProcessInstanceCancelSerializer(serializers.Serializer):
    """Serializer for cancelling a process instance."""
    reason = serializers.CharField(required=False, allow_blank=True)

    def validate(self, attrs):
        if self.instance.status != InstanceStatus.RUNNING:
            raise serializers.ValidationError(
                "Only running process instances can be cancelled."
            )
        return attrs


class ProcessInstanceSuspendSerializer(serializers.Serializer):
    """Serializer for suspending a process instance."""
    
    def validate(self, attrs):
        if self.instance.status != InstanceStatus.RUNNING:
            raise serializers.ValidationError(
                "Only running process instances can be suspended."
            )
        return attrs


class ProcessInstanceResumeSerializer(serializers.Serializer):
    """Serializer for resuming a suspended process instance."""
    
    def validate(self, attrs):
        if self.instance.status != InstanceStatus.SUSPENDED:
            raise serializers.ValidationError(
                "Only suspended process instances can be resumed."
            )
        return attrs


# =============================================================================
# Task Serializers
# =============================================================================

class TaskListSerializer(serializers.ModelSerializer):
    """Serializer for listing tasks."""
    instance_business_key = serializers.CharField(
        source='instance.business_key', read_only=True
    )
    definition_name = serializers.CharField(
        source='instance.definition.name', read_only=True
    )
    assignee = UserMinimalSerializer(read_only=True)
    status_display = serializers.CharField(source='get_status_display', read_only=True)
    task_type_display = serializers.CharField(source='get_task_type_display', read_only=True)
    is_overdue = serializers.SerializerMethodField()
    
    class Meta:
        model = Task
        fields = (
            'id',
            'name',
            'description',
            'task_type',
            'task_type_display',
            'status',
            'status_display',
            'priority',
            'assignee',
            'due_date',
            'is_overdue',
            'instance',
            'instance_business_key',
            'definition_name',
            'created_at',
        )
        read_only_fields = fields

    def get_is_overdue(self, obj):
        from django.utils import timezone
        if obj.due_date and obj.status in [TaskStatus.CREATED, TaskStatus.ASSIGNED, TaskStatus.CLAIMED]:
            return obj.due_date < timezone.now()
        return False


class TaskDetailSerializer(serializers.ModelSerializer):
    """Serializer for task details."""
    instance = ProcessInstanceListSerializer(read_only=True)
    assignee = UserMinimalSerializer(read_only=True)
    assignments = serializers.SerializerMethodField()
    status_display = serializers.CharField(source='get_status_display', read_only=True)
    task_type_display = serializers.CharField(source='get_task_type_display', read_only=True)
    can_claim = serializers.SerializerMethodField()
    can_complete = serializers.SerializerMethodField()
    
    class Meta:
        model = Task
        fields = (
            'id',
            'name',
            'description',
            'task_definition_key',
            'element_id',
            'task_type',
            'task_type_display',
            'status',
            'status_display',
            'priority',
            'form_data',
            'input_variables',
            'output_variables',
            'assignee',
            'assignments',
            'due_date',
            'instance',
            'created_at',
            'claimed_at',
            'completed_at',
            'error_message',
            'can_claim',
            'can_complete',
        )
        read_only_fields = fields

    def get_assignments(self, obj):
        assignments = obj.assignments.filter(is_active=True).select_related('user', 'group')
        return TaskAssignmentSerializer(assignments, many=True).data

    def get_can_claim(self, obj):
        request = self.context.get('request')
        if request and request.user.is_authenticated:
            return obj.can_claim(request.user)
        return False

    def get_can_complete(self, obj):
        request = self.context.get('request')
        if request and request.user.is_authenticated:
            return obj.can_complete(request.user)
        return False


class TaskClaimSerializer(serializers.Serializer):
    """Serializer for claiming a task."""
    
    def validate(self, attrs):
        request = self.context['request']
        if not self.instance.can_claim(request.user):
            raise serializers.ValidationError(
                "You cannot claim this task."
            )
        return attrs


class TaskUnclaimSerializer(serializers.Serializer):
    """Serializer for unclaiming a task."""
    
    def validate(self, attrs):
        request = self.context['request']
        if self.instance.status != TaskStatus.CLAIMED:
            raise serializers.ValidationError(
                "This task is not claimed."
            )
        if self.instance.assignee != request.user:
            raise serializers.ValidationError(
                "You can only unclaim tasks you have claimed."
            )
        return attrs


class TaskCompleteSerializer(serializers.Serializer):
    """Serializer for completing a task."""
    variables = serializers.JSONField(required=False, default=dict)
    
    def validate(self, attrs):
        request = self.context['request']
        if not self.instance.can_complete(request.user):
            raise serializers.ValidationError(
                "You cannot complete this task."
            )
        return attrs


class TaskDelegateSerializer(serializers.Serializer):
    """Serializer for delegating a task."""
    user_id = serializers.UUIDField()
    
    def validate_user_id(self, value):
        try:
            user = User.objects.get(pk=value)
            self.validated_user = user
            return value
        except User.DoesNotExist:
            raise serializers.ValidationError("User not found.")

    def validate(self, attrs):
        request = self.context['request']
        if self.instance.assignee != request.user:
            raise serializers.ValidationError(
                "You can only delegate tasks assigned to you."
            )
        if self.instance.status != TaskStatus.CLAIMED:
            raise serializers.ValidationError(
                "Only claimed tasks can be delegated."
            )
        return attrs


class TaskReassignSerializer(serializers.Serializer):
    """Serializer for reassigning a task (admin action)."""
    user_id = serializers.UUIDField(required=False, allow_null=True)
    group_id = serializers.IntegerField(required=False, allow_null=True)
    
    def validate(self, attrs):
        if not attrs.get('user_id') and not attrs.get('group_id'):
            raise serializers.ValidationError(
                "Either user_id or group_id must be provided."
            )
        return attrs


# =============================================================================
# Task Assignment Serializers
# =============================================================================

class TaskAssignmentSerializer(serializers.ModelSerializer):
    """Serializer for task assignments."""
    user = UserMinimalSerializer(read_only=True)
    group = GroupMinimalSerializer(read_only=True)
    assignment_type_display = serializers.CharField(
        source='get_assignment_type_display', read_only=True
    )
    
    class Meta:
        model = TaskAssignment
        fields = (
            'id',
            'user',
            'group',
            'assignment_type',
            'assignment_type_display',
            'is_active',
            'assigned_at',
        )
        read_only_fields = fields


class TaskAssignmentCreateSerializer(serializers.ModelSerializer):
    """Serializer for creating task assignments."""
    user_id = serializers.UUIDField(required=False, allow_null=True)
    group_id = serializers.IntegerField(required=False, allow_null=True)
    
    class Meta:
        model = TaskAssignment
        fields = (
            'user_id',
            'group_id',
            'assignment_type',
        )

    def validate(self, attrs):
        if not attrs.get('user_id') and not attrs.get('group_id'):
            raise serializers.ValidationError(
                "Either user_id or group_id must be provided."
            )
        return attrs


# =============================================================================
# Process Variable Serializers
# =============================================================================

class ProcessVariableSerializer(serializers.ModelSerializer):
    """Serializer for process variables."""
    
    class Meta:
        model = ProcessVariable
        fields = (
            'id',
            'name',
            'type',
            'value',
            'scope',
            'created_at',
            'updated_at',
        )
        read_only_fields = ('id', 'created_at', 'updated_at')


class ProcessVariableUpdateSerializer(serializers.ModelSerializer):
    """Serializer for updating process variables."""
    
    class Meta:
        model = ProcessVariable
        fields = ('value',)


# =============================================================================
# Process History Serializers
# =============================================================================

class ProcessHistorySerializer(serializers.ModelSerializer):
    """Serializer for process history."""
    user = UserMinimalSerializer(read_only=True)
    event_type_display = serializers.CharField(
        source='get_event_type_display', read_only=True
    )
    task_name = serializers.CharField(source='task.name', read_only=True, allow_null=True)
    
    class Meta:
        model = ProcessHistory
        fields = (
            'id',
            'event_type',
            'event_type_display',
            'element_id',
            'task',
            'task_name',
            'user',
            'old_value',
            'new_value',
            'comment',
            'created_at',
        )
        read_only_fields = fields


# =============================================================================
# SLA Serializers
# =============================================================================

class SLADefinitionSerializer(serializers.ModelSerializer):
    """Serializer for SLA definitions."""
    duration_unit_display = serializers.CharField(
        source='get_duration_unit_display', read_only=True
    )
    action_display = serializers.CharField(
        source='get_action_on_violation_display', read_only=True
    )
    duration_minutes = serializers.IntegerField(read_only=True)
    
    class Meta:
        model = SLADefinition
        fields = (
            'id',
            'task_definition_key',
            'duration_value',
            'duration_unit',
            'duration_unit_display',
            'duration_minutes',
            'action_on_violation',
            'action_display',
            'escalation_config',
            'is_active',
        )
        read_only_fields = ('id', 'duration_minutes')


class SLADefinitionCreateSerializer(serializers.ModelSerializer):
    """Serializer for creating SLA definitions."""
    
    class Meta:
        model = SLADefinition
        fields = (
            'task_definition_key',
            'duration_value',
            'duration_unit',
            'action_on_violation',
            'escalation_config',
            'is_active',
        )


class SLAViolationSerializer(serializers.ModelSerializer):
    """Serializer for SLA violations."""
    task = TaskListSerializer(read_only=True)
    sla_definition = SLADefinitionSerializer(read_only=True)
    
    class Meta:
        model = SLAViolation
        fields = (
            'id',
            'task',
            'sla_definition',
            'expected_completion',
            'violation_time',
            'is_resolved',
            'resolved_at',
        )
        read_only_fields = fields
