from rest_framework import serializers, status, permissions
from rest_framework.response import Response
from rest_framework.views import APIView
from django.core.exceptions import FieldDoesNotExist
from django.db import transaction

from stateflow import models as stateflow_models
from stateflow import services as stateflow_services


class BusinessObjectCloneRequestSerializer(serializers.Serializer):
    business_object_id = serializers.IntegerField(min_value=1)
    # 调用方必须显式传入 content_type 与 object_id：
    # - content_type：仅用于校验与源对象一致（不做额外校验）
    # - object_id：克隆后的新业务对象 ID（必须与源对象不同）
    content_type = serializers.IntegerField(min_value=1, allow_null=True)
    object_id = serializers.IntegerField(min_value=1, allow_null=True)


class BusinessObjectCloneView(APIView):
    """
    克隆 BusinessObject（含所有状态流转记录与工艺参数记录）

    POST /api/v2/stateflow/business-objects/clone/

    请求体:
    {
      "business_object_id": 123,
      "content_type": 9,
      "object_id": 456
    }

    返回:
    {
      "business_object_id": 456
    }
    """

    permission_classes = [permissions.IsAuthenticated]

    def post(self, request):
        srz = BusinessObjectCloneRequestSerializer(data=request.data)
        srz.is_valid(raise_exception=True)

        bo_id = srz.validated_data['business_object_id']
        expected_content_type_id = srz.validated_data.get('content_type')
        new_object_id = srz.validated_data.get('object_id')
        try:
            bo = stateflow_models.BusinessObject.objects.get(id=bo_id)
        except stateflow_models.BusinessObject.DoesNotExist:
            return Response({'detail': 'business_object 不存在'}, status=status.HTTP_404_NOT_FOUND)

        try:
            with transaction.atomic():
                cloned = stateflow_services.clone_business_object(
                    bo,
                    new_object_id=new_object_id,
                    expected_content_type_id=expected_content_type_id,
                )

                # 兼容 printing 的“克隆=新建后复制流程进度”工作流：
                # 目标业务对象（PlateOrder/PrintingJob）本身持有 business_object 字段，
                # 需要把克隆后的 BusinessObject 回写到目标对象上，否则前端看不到节点/参数历史。
                try:
                    target_obj = cloned.content_type.get_object_for_this_type(pk=cloned.object_id)
                except Exception:
                    target_obj = None

                if target_obj is not None:
                    try:
                        bo_field = target_obj._meta.get_field('business_object')
                    except FieldDoesNotExist:
                        bo_field = None

                    if bo_field is not None and bo_field.related_model is stateflow_models.BusinessObject:
                        old_bo_id = getattr(target_obj, 'business_object_id', None)
                        target_obj.business_object = cloned
                        target_obj.save(update_fields=['business_object'])

                        # 如果目标对象在创建时自动生成了一个“空 business_object”，这里做安全清理，
                        # 避免同一个业务对象存在多个 BusinessObject 绑定导致后续审计/排查混乱。
                        if old_bo_id and old_bo_id != cloned.id:
                            old_bo = (
                                stateflow_models.BusinessObject.objects
                                .filter(id=old_bo_id)
                                .select_related('content_type')
                                .first()
                            )
                            if (
                                old_bo
                                and old_bo.state_logs.count() == 0
                                and old_bo.content_type_id == cloned.content_type_id
                                and old_bo.object_id == cloned.object_id
                            ):
                                old_bo.delete()
        except ValueError as e:
            return Response({'detail': str(e)}, status=status.HTTP_400_BAD_REQUEST)

        return Response({'business_object_id': cloned.id})


