import hmac
import threading
import traceback
import uuid
import hashlib
import xmltodict
import time
import logging
import requests
import os
import secrets
import random
import string
from calendar import monthrange
from decimal import Decimal
from datetime import date, datetime, timedelta
from django.utils import timezone
from django.conf import settings
from django.core.exceptions import ObjectDoesNotExist
from django.core.paginator import Paginator
from django.db import models, transaction, IntegrityError
from django.db.models import Q, Count, Sum, F, Exists, OuterRef
from gvsdsdk.fluent import db, func, FQ
from django.db.models.functions import TruncDate, TruncMonth, TruncYear
from django.contrib.auth.hashers import make_password
from django.views.decorators.csrf import csrf_exempt
from django.utils.decorators import method_decorator

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from rest_framework.permissions import IsAuthenticated, AllowAny
from rest_framework.parsers import JSONParser, MultiPartParser, FormParser

# 工具类导入
from utils.oss_utils import validate_image, upload_to_oss, delete_from_oss
from backend.utils import (
    update_dashou_daily_by_action,
    update_shangjia_daily
)
from jituan.services.club_context import filter_club_char_field, filter_queryset_by_club, filter_user_related_by_club, filter_user_qs_by_club, orders_for_request
from jituan.services.catalog_scope import block_non_group_catalog_scope
from jituan.services.club_penalty import (
    filter_penalty_qs, resolve_penalty_club_id, filter_gsfenhong_qs,
    forbid_penalty_out_of_scope, resolve_penalty_record_club_id,
)
from jituan.services.club_user_access import forbid_if_user_out_of_scope, list_response_meta
from shop.utils import update_dianpu_daily_stat
from products.utils import update_shangpin_daily_stat
from orders.notice_tasks import dingdan_guangbo
from ..utils import (
    verify_kefu_permission,
    PERMISSION_TO_SHENFEN,
    SHENFEN_PROFILE_MAP,
    has_fadan_view_permission,
    has_merchant_order_permission,
    check_fadan_permission,
    pick_order_id,
    pick_penalty_create_params,
    write_xiugai_log,
    XIUGAI_LEIXING_DASHOU,
    XIUGAI_LEIXING_GUANSHI,
    XIUGAI_LEIXING_SHANGJIA,
    XIUGAI_LEIXING_ZUZHANG,
    XIUGAI_LEIXING_LABEL,
)

# models 集中导入
## gvsdsdk RBAC 模型（使用 PascalCase 字段名，匹配实际数据库表结构）
from gvsdsdk.models import Role, Permission, RolePermission, UserRole
## backend
from backend.models import WithdrawalDailyStats

## users
from users.models import (
    UserGuanshi, UserBoss, UserZuzhang,
    UserKefu, UserDashou, Xiugaijilu, UserShangjia, UserShenheguan
)
from users.business_models import User

## orders
from orders.models import (
    CommissionRate, PlayerDeliveryImage, PenaltyRecord,
    OrderPlayerHistory, Order, RefundRecord,
    MerchantOrderExt, Penalty, PenaltyAppealImage, PenaltyBonus
)

## shop
from shop.models import Dianpu, DianpuMorenPeizhi, YonghuPingzheng, ShangpinLeixingDianpu, DianpuShangpinShenheShezhi

## products
from products.models import (
    Shangpin, ShangpinLeixing, ShangpinZhuanqu, Huiyuan,
    DuociFenhong, Czjilu, Huiyuangoumai, Gsfenhong
)

## config
from config.models import (
    WithdrawConfig, ShangjiaLianjie, AccountPermission,
    TixianQuotaDefault,
    DailyIncomeStat, DailyPayoutStat, PopupPage, PopupConfig, PopupImage
)

## rank
from rank.models import (
    KaoheguanBankuai, Bankuai, Chenghao, KaoheCishuFeiyong,
    YonghuChenghao, ShenheJilu, KaoheJiluFeiyong, KaoheJujueJilu
)

# 序列化器
from ..serializers import PopupPageSerializer

# 全局常量、日志对象
logger = logging.getLogger('houtai')
SHOP_PRODUCT_PERMS = ['1199ab', '1199abc', '1199abd']

class FaKuanTongJiView(APIView):
    """
    罚款统计接口
    POST /houtai/htglyhqcfsltj
    """
    permission_classes = [IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        username = request.data.get('username', '').strip()
        if not username:
            return Response({'code': 400, 'msg': '参数不完整'})

        try:
            kefu, permissions = verify_kefu_permission(request, username)
            if kefu is None:
                return permissions

            if not has_fadan_view_permission(permissions, username):
                return Response({'code': 403, 'msg': '无权限查看罚款统计'})

            from utils.penalty_status import penalty_platform_audit_pending_q
            pending_q = penalty_platform_audit_pending_q()
            stats = filter_penalty_qs(Penalty.query.all(), request).aggregate(
                total=Count('id'),
                daijiaona=Count('id', filter=Q(Status=1)),
                shensuzhong=Count('id', filter=Q(Status=3)),
                yijiaona=Count('id', filter=Q(Status=2)),
                yibohui=Count('id', filter=Q(Status=4)),
                pingtai_shenhe=Count('id', filter=pending_q),
            )
            data = {k: v or 0 for k, v in stats.items()}
            from jituan.services.club_user_access import list_response_meta
            return Response({'code': 0, 'msg': '成功', 'data': {**data, **list_response_meta(request)}})
        except Exception as e:
            logger.error(f"罚款统计异常: {traceback.format_exc()}")
            return Response({'code': 500, 'msg': '系统繁忙'})


class FaKuanLieBiaoView(APIView):
    """
    罚款列表接口
    POST /houtai/hthqfklb
    """
    permission_classes = [IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        username = request.data.get('username', '').strip()
        if not username:
            return Response({'code': 400, 'msg': '参数不完整'})

        try:
            kefu, permissions = verify_kefu_permission(request, username)
            if kefu is None:
                return permissions
            if not has_fadan_view_permission(permissions, username):
                return Response({'code': 403, 'msg': '无权限查看罚款列表'})

            page = int(request.data.get('page', 1))
            page_size = int(request.data.get('page_size', 20))
            if page_size > 100:
                page_size = 100

            qs = filter_penalty_qs(Penalty.query.all(), request)

            # 状态筛选（5=平台审核中，仅 zhuangtai=5）
            from utils.penalty_status import penalty_platform_audit_pending_q
            zhuangtai_raw = request.data.get('zhuangtai')
            if zhuangtai_raw is not None and str(zhuangtai_raw).strip() != '':
                try:
                    zt = int(zhuangtai_raw)
                    if zt == 5:
                        qs = qs.filter(penalty_platform_audit_pending_q())
                    elif zt in (1, 2, 3, 4):
                        qs = qs.filter(Status=zt)
                except (ValueError, TypeError):
                    pass

            # 被处罚人ID
            PenalizedUserID = request.data.get('PenalizedUserID', '').strip()
            if PenalizedUserID:
                qs = qs.filter(PenalizedUserID=PenalizedUserID)

            # 被处罚人身份
            beichufa_shenfen = request.data.get('beichufa_shenfen')
            if beichufa_shenfen is not None and int(beichufa_shenfen) in [1, 2, 3, 4]:
                qs = qs.filter(Identity=int(beichufa_shenfen))

            # 模糊搜索（订单ID、被罚人ID、申请人ID）
            sousuo = request.data.get('sousuo', '').strip()
            if sousuo:
                qs = qs.filter(
                    Q(RelatedOrderID__icontains=sousuo) |
                    Q(PenalizedUserID__icontains=sousuo) |
                    Q(ApplicantID__icontains=sousuo)
                )

            qs = qs.order_by('-CreateTime')
            paginator = Paginator(qs, page_size)
            try:
                page_obj = paginator.page(page)
            except Exception:
                return Response({
                    'code': 0, 'msg': '成功',
                    'data': {'list': [], 'total': 0, 'page': page, 'page_size': page_size}
                })

            records = list(page_obj)
            penalty_ids = [r.id for r in records]

            # 批量获取图片并分组
            zhengju_map = {}
            shensu_map = {}
            if penalty_ids:
                tupians = PenaltyAppealImage.query.filter(
                    Penalty_id__in=penalty_ids
                ).values('Penalty_id', 'ImageURL', 'Purpose')
                for t in tupians:
                    fid = t['Penalty_id']
                    url = t['ImageURL']
                    if t['Purpose'] == 1:
                        zhengju_map.setdefault(fid, []).append(url)
                    else:
                        shensu_map.setdefault(fid, []).append(url)

            from utils.penalty_status import penalty_display_status, is_penalty_platform_audit_pending

            # 组装列表数据
            results = []
            for r in records:
                results.append({
                    'id': r.id,
                    'beichufa_id': r.PenalizedUserID,
                    'shenfen': r.Identity,
                    'shenfen_text': dict(Penalty._meta.get_field('Identity').choices).get(r.Identity, ''),
                    'shenqing_chufa': r.ApplicantID or '',
                    'shenqingren_shenfen': r.ApplicantIdentity,
                    'chufaliyou': r.Reason or '',
                    'fakuanjine': str(r.FineAmount),
                    'guanliandingdan_id': r.RelatedOrderID or '',
                    'zhuangtai': r.Status,
                    'zhuangtai_text': penalty_display_status(r),
                    'platform_audit_pending': is_penalty_platform_audit_pending(r),
                    'yingxiang_qiangdan': r.AffectsGrabbing,
                    'shensuliyou': r.AppealReason or '',
                    'bohuiliyou': r.RejectReason or '',
                    'chulizhe': r.ProcessorID or '',
                    'chulizhe_shenfen': r.ProcessorIdentity,
                    'zhengju_tupian': zhengju_map.get(r.id, []),
                    'shensu_tupian': shensu_map.get(r.id, []),
                    'creat_time': r.CreateTime.strftime('%Y-%m-%d %H:%M:%S') if r.CreateTime else '',
                    'create_time': r.CreateTime.strftime('%Y-%m-%d %H:%M:%S') if r.CreateTime else '',
                    'UpdateTime': r.UpdateTime.strftime('%Y-%m-%d %H:%M:%S') if r.UpdateTime else '',
                })

            from jituan.services.club_user_access import list_response_meta
            return Response({
                'code': 0, 'msg': '成功',
                'data': {
                    'list': results,
                    'total': paginator.count,
                    'page': page,
                    'page_size': page_size,
                    **list_response_meta(request),
                }
            })
        except Exception as e:
            logger.error(f"罚款列表异常: {traceback.format_exc()}")
            return Response({'code': 500, 'msg': '系统繁忙'})


class FaKuanChuLiView(APIView):
    """
    处理罚款申诉（同意/拒绝）
    POST /houtai/glyclfk
    """
    permission_classes = [IsAuthenticated]
    parser_classes = [MultiPartParser, FormParser, JSONParser]

    def post(self, request):
        try:
            username = request.data.get('username', '').strip()
            penalty_id = request.data.get('penalty_id') or request.data.get('fadan_id')
            action = request.data.get('action', '').strip()
            chuli_liyou = request.data.get('chuli_liyou', '').strip()

            if not all([username, penalty_id, action]):
                return Response({'code': 400, 'msg': '参数不完整'})

            kefu, permissions = verify_kefu_permission(request, username)
            if kefu is None:
                return permissions

            with transaction.atomic():
                try:
                    penalty = Penalty.objects.select_for_update().get(id=penalty_id)
                except Penalty.DoesNotExist:
                    return Response({'code': 404, 'msg': '罚单不存在'})

                deny = forbid_penalty_out_of_scope(request, penalty)
                if deny:
                    return deny

                if penalty.Status != 3:
                    return Response({'code': 400, 'msg': '当前状态不可处理'})

                if not check_fadan_permission(permissions, penalty.Identity):
                    return Response({'code': 403, 'msg': '无权限处理该类罚单'})

                # 处理上传的图片
                uploaded_urls = []
                files = request.FILES.getlist('tupian') or []
                if not files:
                    single = request.FILES.get('tupian')
                    if single:
                        files = [single]
                for file in files:
                    valid, msg = validate_image(file)
                    if not valid:
                        return Response({'code': 400, 'msg': msg})
                    ext = file.name.split('.')[-1] if '.' in file.name else 'jpg'
                    file_name = f"chufa_{penalty_id}_{int(time.time() * 1000)}.{ext}"
                    file_path = f"chufatupian/kechufatupian/{file_name}"
                    url = upload_to_oss(file, file_path)
                    if not url:
                        return Response({'code': 500, 'msg': '图片上传失败'})
                    uploaded_urls.append(file_path)

                # 更新状态
                if action == 'agree':          # 同意申诉 → 驳回处罚
                    penalty.Status = 4
                    penalty.RejectReason = chuli_liyou
                elif action == 'reject':       # 拒绝申诉 → 回到待缴纳
                    penalty.Status = 1
                    penalty.RejectReason = chuli_liyou
                else:
                    return Response({'code': 400, 'msg': '无效的操作类型'})

                # 记录处理者（使用 request.user 的 phone）
                penalty.ProcessorID = request.user.Phone
                penalty.ProcessorIdentity = 2   # 这里假设处理者是售后身份，可根据实际业务获取
                penalty.save()

                # 保存图片（证据图片，用途1）
                for relative_url in uploaded_urls:
                    PenaltyAppealImage.query.create(
                        Penalty_id=penalty_id,
                        PenalizedUserID=penalty.PenalizedUserID,
                        ImageURL=relative_url,
                        Purpose=1
                    )

            logger.info(f"罚款处理成功: {penalty_id}, 操作: {action}")
            return Response({'code': 0, 'msg': '处理成功'})

        except Exception as e:
            logger.error(f"罚款处理异常: {traceback.format_exc()}")
            return Response({'code': 500, 'msg': '系统繁忙'})


class FaKuanPingTaiShenHeView(APIView):
    """
    平台审核商家提交的罚款（同意/驳回）
    POST /houtai/glyptshfk
    action: platform_approve | platform_reject
    """
    permission_classes = [IsAuthenticated]
    parser_classes = [MultiPartParser, FormParser, JSONParser]

    def post(self, request):
        try:
            from utils.penalty_status import (
                PENALTY_PLATFORM_AUDIT, PENALTY_PENDING_PAY, PENALTY_APPEALING, PENALTY_REJECTED,
            )
            username = request.data.get('username', '').strip()
            penalty_id = request.data.get('penalty_id') or request.data.get('fadan_id')
            action = request.data.get('action', '').strip()
            chuli_liyou = request.data.get('chuli_liyou', '').strip()

            if not all([username, penalty_id, action]):
                return Response({'code': 400, 'msg': '参数不完整'})

            kefu, permissions = verify_kefu_permission(request, username)
            if kefu is None:
                return permissions

            with transaction.atomic():
                try:
                    penalty = Penalty.objects.select_for_update().get(id=penalty_id)
                except Penalty.DoesNotExist:
                    return Response({'code': 404, 'msg': '罚单不存在'})

                deny = forbid_penalty_out_of_scope(request, penalty)
                if deny:
                    return deny

                if penalty.Status != PENALTY_PLATFORM_AUDIT:
                    return Response({'code': 400, 'msg': '当前状态不可平台审核'})

                if not check_fadan_permission(permissions, penalty.Identity):
                    return Response({'code': 403, 'msg': '无权限处理该类罚单'})

                if action == 'platform_approve':
                    if penalty.AppealReason:
                        penalty.Status = PENALTY_APPEALING
                    else:
                        penalty.Status = PENALTY_PENDING_PAY
                    penalty.ApproveReason = chuli_liyou or penalty.ApproveReason or ''
                elif action == 'platform_reject':
                    penalty.Status = PENALTY_REJECTED
                    penalty.RejectReason = chuli_liyou or '平台审核驳回'
                else:
                    return Response({'code': 400, 'msg': '无效的操作类型'})

                penalty.ProcessorID = request.user.Phone
                penalty.ProcessorIdentity = 3
                penalty.save()

            logger.info(f"罚款平台审核成功: {penalty_id}, 操作: {action}")
            return Response({'code': 0, 'msg': '平台审核完成'})

        except Exception as e:
            logger.error(f"罚款平台审核异常: {traceback.format_exc()}")
            return Response({'code': 500, 'msg': '系统繁忙'})


class FaKuanChuangJianView(APIView):
    """
    管理员创建罚款
    POST /houtai/htfksc
    """
    permission_classes = [IsAuthenticated]
    parser_classes = [MultiPartParser, FormParser, JSONParser]

    def post(self, request):
        try:
            username = request.data.get('username', '').strip()
            PenalizedUserID, Reason, FineAmount, AffectsGrabbing = pick_penalty_create_params(request.data)
            shenfen = request.data.get('shenfen')

            if not all([username, PenalizedUserID, shenfen, Reason, FineAmount is not None]):
                return Response({'code': 400, 'msg': '参数不完整'})

            try:
                shenfen = int(shenfen)
                FineAmount = float(FineAmount)
            except (ValueError, TypeError):
                return Response({'code': 400, 'msg': '参数格式错误'})

            if shenfen not in [1, 2, 3, 4]:
                return Response({'code': 400, 'msg': '无效的被罚人身份'})

            kefu, permissions = verify_kefu_permission(request, username)
            if kefu is None:
                return permissions

            if not check_fadan_permission(permissions, shenfen):
                return Response({'code': 403, 'msg': '无权限创建该类罚单'})

            # 验证用户是否存在对应的扩展表
            try:
                user = User.query.get(UserUID=PenalizedUserID)
                profile_attr = SHENFEN_PROFILE_MAP.get(shenfen)
                if not profile_attr or not hasattr(user, profile_attr):
                    return Response({'code': 400, 'msg': '该用户不是所选身份'})
            except User.DoesNotExist:
                return Response({'code': 404, 'msg': '用户不存在'})

            # 处理图片上传
            uploaded_urls = []
            files = request.FILES.getlist('tupian') or []
            if not files:
                single = request.FILES.get('tupian')
                if single:
                    files = [single]
            for file in files:
                valid, msg = validate_image(file)
                if not valid:
                    return Response({'code': 400, 'msg': msg})
                ext = file.name.split('.')[-1] if '.' in file.name else 'jpg'
                file_name = f"chufa_{int(time.time() * 1000)}.{ext}"
                file_path = f"chufatupian/kechufatupian/{file_name}"
                url = upload_to_oss(file, file_path)
                if not url:
                    return Response({'code': 500, 'msg': '图片上传失败'})
                uploaded_urls.append(file_path)

            with transaction.atomic():
                penalty = Penalty.query.create(
                    PenalizedUserID=PenalizedUserID,
                    Identity=shenfen,
                    ApplicantID=request.user.Phone,      # 申请人（客服）手机号
                    ApplicantIdentity=2,                   # 售后身份
                    Reason=Reason,
                    FineAmount=FineAmount,
                    AffectsGrabbing=AffectsGrabbing,
                    Status=1,                            # 待缴纳
                    ClubID=resolve_penalty_club_id(
                        penalized_user_id=PenalizedUserID,
                        request=request,
                        user=request.user,
                    ),
                )
                PenaltyAppealImage.objects.bulk_create([
                    PenaltyAppealImage(
                        Penalty=penalty,
                        PenalizedUserID=PenalizedUserID,
                        ImageURL=relative_url,
                        Purpose=1,
                    )
                    for relative_url in uploaded_urls
                ])
                from users.fadan_fenhong_utils import lock_penalty_bonus
                lock_penalty_bonus(penalty)

            logger.info(f"罚款创建成功: {penalty.id}")
            return Response({'code': 0, 'msg': '罚款已创建', 'data': {'id': penalty.id}})

        except Exception as e:
            logger.error(f"创建罚款异常: {traceback.format_exc()}")
            return Response({'code': 500, 'msg': '系统繁忙'})


class FineApplyView(APIView):
    """
    客服罚款申请接口（基于订单对打手发起罚款）
    POST /houtai/kffkdssq
    权限: JWT认证 + 客服权限验证

    请求参数:
        username             (必填) : 客服用户名（手机号）
        OrderID           (必填) : 订单ID
        Reason           (必填) : 罚款原因
        FineAmount           (必填) : 罚款金额（元）
        AffectsGrabbing   (可选) : 是否影响抢单，1=是，0=否，默认1
    """
    permission_classes = [IsAuthenticated]
    parser_classes = [MultiPartParser, FormParser, JSONParser]

    def post(self, request):
        try:
            username = request.data.get('username', '').strip()
            OrderID = pick_order_id(request.data)
            _, Reason, FineAmount, AffectsGrabbing = pick_penalty_create_params(request.data)

            if not all([username, OrderID, Reason, FineAmount is not None]):
                return Response({'code': 400, 'msg': '参数不完整'})

            try:
                FineAmount = float(FineAmount)
            except (ValueError, TypeError):
                return Response({'code': 400, 'msg': '罚款金额格式错误'})

            kefu, permissions = verify_kefu_permission(request, username)
            if kefu is None:
                return permissions

            # 验证订单存在
            try:
                order = Order.query.get(OrderID=OrderID)
            except Order.DoesNotExist:
                return Response({'code': 404, 'msg': '订单不存在'})

            # 获取打手ID
            dashou_id = order.PlayerID
            if not dashou_id:
                return Response({'code': 400, 'msg': '该订单无接单打手，无法罚款'})

            # 重复罚款检查（组队单按订单维度防重复）
            from orders.services.team_recruit import get_active_recruit
            _active_team = get_active_recruit(OrderID)
            if _active_team:
                if Penalty.query.filter(RelatedOrderID=OrderID).exclude(Status=4).exists():
                    return Response({'code': 400, 'msg': '该订单已有罚单'})
            elif Penalty.query.filter(PenalizedUserID=dashou_id, RelatedOrderID=OrderID).exists():
                return Response({'code': 400, 'msg': '该打手已被罚款过'})

            # 检查权限（打手身份 shenfen=1）
            if not check_fadan_permission(permissions, 1):
                return Response({'code': 403, 'msg': '无权限处罚打手'})

            # 处理图片上传
            uploaded_urls = []
            files = request.FILES.getlist('tupian') or []
            if not files:
                single = request.FILES.get('tupian')
                if single:
                    files = [single]
            for file in files:
                valid, msg = validate_image(file)
                if not valid:
                    return Response({'code': 400, 'msg': msg})
                ext = file.name.split('.')[-1] if '.' in file.name else 'jpg'
                file_name = f"chufa_{int(time.time() * 1000)}.{ext}"
                file_path = f"chufatupian/kechufatupian/{file_name}"
                url = upload_to_oss(file, file_path)
                if not url:
                    return Response({'code': 500, 'msg': '图片上传失败'})
                uploaded_urls.append(file_path)

            # 创建罚单（组队均摊）
            with transaction.atomic():
                from orders.services.team_recruit import maybe_split_penalties
                from users.fadan_fenhong_utils import lock_penalty_bonus
                club_for_p = resolve_penalty_club_id(
                    order=order,
                    request=request,
                    user=request.user,
                    applicant_id=getattr(request.user, 'UserUID', None),
                )
                split = maybe_split_penalties(
                    order_id=OrderID,
                    total_amount=FineAmount,
                    reason=Reason,
                    applicant_id=request.user.Phone,
                    applicant_identity=1,
                    affects_grabbing=AffectsGrabbing,
                    club_id=club_for_p,
                )
                if split:
                    for p in split:
                        for relative_url in uploaded_urls:
                            PenaltyAppealImage.query.create(
                                Penalty=p,
                                PenalizedUserID=p.PenalizedUserID,
                                ImageURL=relative_url,
                                Purpose=1,
                            )
                        lock_penalty_bonus(p)
                    penalty = split[0]
                else:
                    penalty = Penalty.query.create(
                        PenalizedUserID=dashou_id,
                        ApplicantID=request.user.Phone,
                        Identity=1,
                        Reason=Reason,
                        FineAmount=FineAmount,
                        RelatedOrderID=OrderID,
                        Status=1,
                        AffectsGrabbing=AffectsGrabbing,
                        ApplicantIdentity=1,
                        ClubID=club_for_p,
                    )
                    for relative_url in uploaded_urls:
                        PenaltyAppealImage.query.create(
                            Penalty=penalty,
                            PenalizedUserID=dashou_id,
                            ImageURL=relative_url,
                            Purpose=1
                        )
                    lock_penalty_bonus(penalty)

            logger.info(f"客服罚款申请成功: 订单 {OrderID}, 打手 {dashou_id}, 金额 {FineAmount}")
            return Response({'code': 0, 'msg': '罚款已生成', 'data': {'id': penalty.id}})

        except Exception as e:
            logger.error(f"客服罚款申请异常: {traceback.format_exc()}")
            return Response({'code': 500, 'msg': '系统繁忙'})


class PunishDashouView(APIView):
    """
    客服处罚打手接口（扣除积分）
    POST /houtai/kpcf
    权限: JWT认证 + 客服权限验证

    请求参数:
        username       (必填) : 客服用户名（手机号）
        OrderID     (必填) : 订单ID
        reason         (可选) : 处罚原因
    """
    permission_classes = [IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        try:
            username = request.data.get('username', '').strip()
            OrderID = request.data.get('OrderID', '').strip()
            reason = request.data.get('reason', '').strip()

            if not all([username, OrderID]):
                return Response({'code': 400, 'msg': '参数不完整'})

            kefu, permissions = verify_kefu_permission(request, username)
            if kefu is None:
                return permissions

            # 检查权限（打手身份 shenfen=1）
            if not check_fadan_permission(permissions, 1):
                return Response({'code': 403, 'msg': '无权限处罚打手'})

            # 查询订单
            try:
                order = Order.query.get(OrderID=OrderID)
            except Order.DoesNotExist:
                return Response({'code': 404, 'msg': '订单不存在'})

            # 获取打手ID
            dashou_id = order.PlayerID
            if not dashou_id:
                return Response({'code': 400, 'msg': '订单未接单，无法处罚打手'})

            # 查询打手
            try:
                dashou_user = User.query.get(UserUID=dashou_id)
                dashou = dashou_user.DashouProfile
            except User.DoesNotExist:
                return Response({'code': 404, 'msg': '打手用户不存在'})
            except ObjectDoesNotExist:
                return Response({'code': 400, 'msg': '该用户不是打手'})

            # 创建处罚记录（扣除积分5分）
            jifen = 5
            with transaction.atomic():
                penalty_record = PenaltyRecord.query.create(
                    PlayerID=dashou_id,
                    ApplicantID=username,
                    PenaltyReason=reason or '',
                    ApplyStatus=0,
                    DeductedPoints=jifen,
                    OrderID=OrderID,
                    ClubID=resolve_penalty_record_club_id(
                        order_id=OrderID,
                        player_id=dashou_id,
                        request=request,
                        user=request.user,
                        applicant_id=getattr(request.user, 'UserUID', None) or username,
                    ),
                )
                # 扣除打手积分
                dashou.jifen = F('jifen') - jifen
                dashou.save(update_fields=['jifen'])

            logger.info(f"客服处罚打手成功: 打手 {dashou_id}, 订单 {OrderID}, 扣除积分 {jifen}")
            return Response({'code': 0, 'msg': '处罚成功', 'data': {'penalty_record_id': penalty_record.id}})

        except Exception as e:
            logger.error(f"客服处罚打手异常: {traceback.format_exc()}")
            return Response({'code': 500, 'msg': '系统繁忙'})







