#!/usr/bin/env python
# @Project ：django_base_ai
# @File    : dept.py
# @Author  : cx
# @Time    : 11/2/2025
# @Desc    : 部门 CRUD、懒加载树、导出等。
import logging

import numpy as np
import pandas as pd
from django.db.models import Q
from rest_framework import serializers
from rest_framework.decorators import action
from rest_framework.permissions import IsAdminUser, IsAuthenticated

from django_base_ai.system.models import Dept, Users
from django_base_ai.utils.filters import LazyLoadFilter
from django_base_ai.utils.json_response import DetailResponse, ErrorResponse, SuccessResponse
from django_base_ai.utils.permission import AnonymousUserPermission, OpenApiPermission
from django_base_ai.utils.serializers import CustomModelSerializer
from django_base_ai.utils.viewset import CustomModelViewSet

logger = logging.getLogger(__name__)


class DeptSerializer(CustomModelSerializer):
    """
    部门-序列化器
    """

    parent_name = serializers.CharField(read_only=True, source="parent.name")
    status_label = serializers.SerializerMethodField()
    has_children = serializers.SerializerMethodField()
    owner_user = serializers.SerializerMethodField()

    def get_status_label(self, obj: Dept):
        status = "启用" if obj.status else "禁用"
        logger.debug(f"部门 {obj.name} 状态: {status}")
        return status

    def get_has_children(self, obj: Dept):
        count = Dept.objects.filter(parent_id=obj.id).count()
        logger.debug(f"部门 {obj.name} 子部门数量: {count}")
        return count

    def get_owner_user(self, obj: Dept):
        if not obj.owner_user:
            logger.debug(f"部门 {obj.name} 无负责人")
            return None
        logger.debug(f"部门 {obj.name} 负责人: {obj.owner_user.name}")
        return {"id": obj.owner_user.id, "name": obj.owner_user.name}

    class Meta:
        model = Dept
        fields = "__all__"
        read_only_fields = ["id"]


class DeptImportSerializer(CustomModelSerializer):
    """
    部门-导入-序列化器
    """

    class Meta:
        model = Dept
        fields = "__all__"
        read_only_fields = ["id"]


class DeptInitSerializer(CustomModelSerializer):
    """
    递归深度获取数信息(用于生成初始化json文件)
    """

    children = serializers.SerializerMethodField()

    def get_children(self, obj: Dept):
        logger.debug(f"获取部门 {obj.name} 的子部门")
        data = []
        instance = Dept.objects.filter(parent_id=obj.id)
        if instance:
            serializer = DeptInitSerializer(instance=instance, many=True)
            data = serializer.data
        logger.debug(f"部门 {obj.name} 子部门数量: {len(data)}")
        return data

    def save(self, **kwargs):
        logger.info(f"开始保存部门初始化数据: {self.initial_data.get('name', '未知')}")
        instance = super().save(**kwargs)
        logger.info(f"部门 {instance.name} 基础信息已保存，ID: {instance.id}")
        children = self.initial_data.get("children")
        if children:
            for menu_data in children:
                menu_data["parent"] = instance.id
                filter_data = {"name": menu_data["name"], "parent": menu_data["parent"]}
                if "key" in menu_data:
                    filter_data["key"] = menu_data["key"]
                instance_obj = Dept.objects.filter(**filter_data).first()
                if instance_obj and not self.initial_data.get("reset"):
                    continue
                serializer = DeptInitSerializer(instance_obj, data=menu_data, request=self.request)
                serializer.is_valid(raise_exception=True)
                serializer.save()
                logger.info(f"子部门 {menu_data.get('name')} 已保存")
        logger.info(f"部门 {instance.name} 初始化完成")
        return instance

    class Meta:
        model = Dept
        fields = ["name", "sort", "phone", "email", "status", "parent", "creator", "dept_belong_id", "children", "key"]
        extra_kwargs = {"creator": {"write_only": True}, "dept_belong_id": {"write_only": True}}
        read_only_fields = ["id", "children"]


class DeptCreateUpdateSerializer(CustomModelSerializer):
    """
    部门管理 创建/更新时的列化器
    """

    def create(self, validated_data):
        logger.info(f"开始创建部门: {validated_data.get('name', '未知')}")
        try:
            value = validated_data.get("parent", None)
            if value is None:
                validated_data["parent"] = self.request.user.dept
                logger.info(f"设置部门父级为当前用户部门: {self.request.user.dept}")
            instance = super().create(validated_data)
            instance.dept_belong_id = instance.id
            instance.save()
            logger.info(f"部门创建成功: {instance.name} (ID: {instance.id})")
            return instance
        except Exception as e:
            logger.error(f"创建部门时发生异常: {e}")
            logger.exception(e)
            raise

    class Meta:
        model = Dept
        fields = "__all__"


class DeptLazyFilter(LazyLoadFilter):
    class Meta:
        model = Dept
        fields = ["name", "dept", "parent", "status"]


class DeptViewSet(CustomModelViewSet):
    """
    部门管理接口
    list:查询
    create:新增
    update:修改
    retrieve:单例
    destroy:删除
    """

    queryset = Dept.objects.all()
    serializer_class = DeptSerializer
    create_serializer_class = DeptCreateUpdateSerializer
    update_serializer_class = DeptCreateUpdateSerializer
    # filter_fields = ["name", "id", "parent"]
    filter_class = DeptLazyFilter
    search_fields = ["name"]
    # extra_filter_backends = []
    import_serializer_class = DeptImportSerializer
    import_field_dict = {
        "name": "部门名称",
        "key": "部门标识",
    }

    def list(self, request, *args, **kwargs):
        logger.info(f"用户 {request.user.username} 请求获取部门列表")
        # 如果懒加载，则只返回父级
        params = request.query_params
        parent = params.get("parent", None)
        if not params or not parent:
            queryset = self.queryset.filter(parent__isnull=True)
            logger.debug("查询顶级部门")
        else:
            queryset = self.queryset.filter(parent=parent)
            logger.debug(f"查询父级部门ID: {parent} 的子部门")
        if request.user.is_staff:
            queryset = queryset.order_by("sort", "create_datetime")
        else:
            queryset = queryset.filter(status=1).order_by("sort", "create_datetime")
        serializer = DeptSerializer(queryset, many=True, request=request)
        data = serializer.data
        logger.info(f"返回部门数量: {len(data)}")
        return SuccessResponse(data=data)

    def retrieve(self, request, *args, **kwargs):
        logger.info(f"用户 {request.user.username} 请求获取部门详情")
        # 重写 否则会很慢
        pk = kwargs.get("pk", 0)
        instance = Dept.objects.filter(id=pk).first()
        if not instance:
            logger.warning(f"未找到部门ID: {pk}")
        else:
            logger.info(f"返回部门: {instance.name}")
        serializer = self.get_serializer(instance)
        return DetailResponse(data=serializer.data)

    def update(self, request, *args, **kwargs):
        logger.info(f"用户 {request.user.username} 请求更新部门")
        # 重写 否则会很慢
        pk = kwargs.get("pk", 0)
        instance = Dept.objects.filter(id=pk).first()
        if not instance:
            logger.warning(f"未找到部门ID: {pk}")
            return ErrorResponse(msg="部门不存在")
        logger.info(f"更新部门: {instance.name}")
        serializer = self.get_serializer(instance, data=request.data, partial=True)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        logger.info(f"部门 {instance.name} 更新成功")
        return SuccessResponse(msg="修改成功")

    def destroy(self, request, *args, **kwargs):
        logger.info(f"用户 {request.user.username} 请求删除部门")
        pk = kwargs.get("pk", 0)
        instance = Dept.objects.filter(id=pk).first()
        if not instance:
            logger.warning(f"未找到部门ID: {pk}")
            return ErrorResponse(msg="部门不存在")
        dept_name = instance.name
        instance.delete()
        logger.info(f"部门 {dept_name} 删除成功")
        return DetailResponse(data=[], msg="删除成功")

    @action(methods=["GET", "POST"], detail=False, permission_classes=[IsAuthenticated])
    def dept_lazy_tree(self, request, *args, **kwargs):
        self.request.query_params.get("parent")
        is_superuser = request.user.is_superuser
        if is_superuser:
            queryset = Dept.objects.values("id", "name", "parent", "status", "node_type")
        else:
            data_range = request.user.role.values_list("data_range", flat=True)
            user_dept_id = request.user.dept.id
            dept_list = [user_dept_id]
            data_range_list = list(set(data_range))
            for item in data_range_list:
                if item in [0, 2]:
                    dept_list = [user_dept_id]
                elif item == 1:
                    dept_list = Dept.recursion_dept_info(dept_id=user_dept_id)
                elif item == 3:
                    dept_list = Dept.objects.values_list("id", flat=True)
                elif item == 4:
                    dept_list = request.user.role.values_list("dept", flat=True)
                else:
                    dept_list = []
            queryset = Dept.objects.filter(id__in=dept_list, status=True).values("id", "name", "parent", "node_type")
        return DetailResponse(data=queryset, msg="获取成功")

    @action(methods=["GET"], detail=False, permission_classes=[AnonymousUserPermission])
    def all_dept(self, request, *args, **kwargs):
        data = self.get_queryset().filter(status=True).order_by("sort").values("name", "id", "parent", "node_type")
        return DetailResponse(data=data, msg="获取成功")

    @action(methods=["GET"], detail=False, permission_classes=[OpenApiPermission], authentication_classes=[])
    def open_dept_info(self, request, *args, **kwargs):
        """
        第三方API同步部门接口
        :param request:
        :param args:
        :param kwargs:
        :return:
        """
        self.extra_filter_backends = []
        queryset = Dept.objects.all().order_by("id")
        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True, request=request)
            return self.get_paginated_response(serializer.data)
        serializer = self.get_serializer(queryset, many=True, request=request)
        return SuccessResponse(data=serializer.data, msg="获取成功")

    @action(methods=["GET"], detail=False, permission_classes=[OpenApiPermission], authentication_classes=[])
    def open_single_dept_info(self, request, *args, **kwargs):
        """
        查询单个部门信息
        :param request:
        :param args:
        :param kwargs:
        :return:
        """
        nid = request.GET.get("nid", 0)
        if not nid:
            return ErrorResponse(msg="参数不合法")
        instance = Dept.objects.get(id=nid)
        serializer = self.get_serializer(instance)
        serializer_data = self.set_mask_fields(serializer)
        return DetailResponse(data=serializer_data, msg="获取成功")

    @action(methods=["POST"], detail=False, permission_classes=[OpenApiPermission], authentication_classes=[])
    def open_create_dept_info(self, request, *args, **kwargs):
        """
        第三方API创建部门信息
        :param request:
        :param args:
        :param kwargs:
        :return:
        """
        return self.create(request, *args, **kwargs)

    @action(methods=["PUT"], detail=False, permission_classes=[OpenApiPermission], authentication_classes=[])
    def open_update_dept_info(self, request, *args, **kwargs):
        """
        第三方API修改部门信息
        :param request:
        :param args:
        :param kwargs:
        :return:
        """
        partial = request.GET.get("partial", False)
        nid = request.GET.get("nid", 0)
        if not nid:
            return ErrorResponse(msg="参数不合法")
        instance = Dept.objects.get(id=nid)
        serializer = self.get_serializer(instance, data=request.data, request=request, partial=partial)
        serializer.is_valid(raise_exception=True)
        self.perform_update(serializer)
        if getattr(instance, "_prefetched_objects_cache", None):
            # If 'prefetch_related' has been applied to a queryset, we need to
            # forcibly invalidate the prefetch cache on the instance.
            instance._prefetched_objects_cache = {}
        return DetailResponse(data=serializer.data, msg="更新成功")

    @action(methods=["GET"], detail=False, permission_classes=[AnonymousUserPermission])
    def all_dept_not_extra(self, request, *args, **kwargs):
        self.extra_filter_backends = []
        queryset = self.filter_queryset(self.get_queryset())
        data = queryset.filter(status=True).order_by("sort").values("name", "id", "parent", "node_type", "status")
        return DetailResponse(data=data, msg="获取成功")

    @action(methods=["GET"], detail=False, permission_classes=[IsAuthenticated])
    def filter_dept_or_user(self, request):
        k = str(request.GET.get("k", "")).upper()
        if not k:
            return ErrorResponse(msg="参数不合法")
        result = []
        dept_result = Dept.objects.filter(Q(name__icontains=k) | Q(short_name__icontains=k))
        users_result = Users.objects.filter(Q(username__icontains=k) | Q(name__icontains=k), is_active=True)
        for item in dept_result:
            result.append(
                {
                    "id": item.id,
                    "type": "dept",
                    "name": item.name,
                    "key": item.key,
                    "short_name": item.short_name,
                    "node_type": item.node_type,
                }
            )
        for item in users_result:
            result.append(
                {
                    "id": item.id,
                    "type": "user",
                    "name": item.name,
                    "key": item.username,
                    "alias": item.alias,
                    "node_type": item.node_type,
                }
            )
        return DetailResponse(result)

    @action(methods=["POST"], detail=False, permission_classes=[IsAdminUser])
    def import_department(self, request, *args, **kwargs):
        """
        根据Excel文件 导入组织架构
        :param request:
        :param args:
        :param kwargs:
        :return:
        """
        excel_data_info = request.FILES.get("file", None)
        if not excel_data_info:
            return ErrorResponse(msg="参数不合法")
        excel_data_info = (
            pd.read_excel(excel_data_info, dtype=str).replace(np.nan, "", regex=True).to_dict(orient="records")
        )

        def create_or_update_department(path, short_name, sort, phone, email, parent=None):
            parts = path.split("/")
            if not parts:
                return None
            current_name = str(parts[0]).strip()
            if not current_name:
                return None
            # 查找或创建当前部门
            department, created = Dept.objects.get_or_create(
                name=current_name,
                parent=parent,
                defaults={
                    "dept_full_path": f"{parent.dept_full_path}/{current_name}" if parent else current_name,
                    "short_name": short_name if len(parts) == 1 else "",
                    "sort": sort if len(parts) == 1 else 1,
                    "phone": phone if len(parts) == 1 else None,
                    "email": email if len(parts) == 1 else None,
                },
            )
            # 递归处理下一级
            if len(parts) > 1:
                create_or_update_department("/".join(parts[1:]), short_name, sort, phone, email, department)
            return department

        for item in excel_data_info:
            full_name = item.get("部门名称", "")
            str(item.get("部门编码", "")).strip()
            short_name = str(item.get("部门简称", "")).strip()
            sort = str(item.get("排序", "")).strip()
            phone = str(item.get("座机", "")).strip()
            email = str(item.get("邮箱", "")).strip()
            create_or_update_department(path=full_name, short_name=short_name, sort=sort, phone=phone, email=email)
        return DetailResponse(msg="导入成功")
