"""orders.views.dashou - auto-generated by split script."""
# ==================== 标准库 ====================
import hmac
import os
import json
import time
import random
import string
import traceback
import threading
import requests
import hashlib
import xml.etree.ElementTree as ET
import xmltodict
import logging
from decimal import Decimal

from django.conf import settings
from django.db import models, transaction
from gvsdsdk.fluent import db, func, FQ
from django.db.models import F, Q, OuterRef, Subquery
from django.core.cache import cache
from django.core.exceptions import ObjectDoesNotExist
from django.http import HttpResponse
from django.utils import timezone

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import permissions, status
from rest_framework.permissions import AllowAny, IsAuthenticated
from rest_framework.parsers import JSONParser
from rest_framework.throttling import AnonRateThrottle
from rest_framework_simplejwt.authentication import JWTAuthentication

from tencentcloud.common import credential
from tencentcloud.common.profile.client_profile import ClientProfile
from tencentcloud.common.profile.http_profile import HttpProfile
from tencentcloud.common.exception.tencent_cloud_sdk_exception import TencentCloudSDKException
from tencentcloud.sts.v20180813 import sts_client, models

from utils.weixin_broadcast import WeixinBroadcastSender
from utils.money import yuan_to_fen
from utils.chat_utils import (
    _send_group_message, _subscribe_users_to_group, establish_order_chat,
    prepare_order_group_chat, resolve_pair_group_id,
    parse_pair_from_group_id, resolve_pair_from_order, check_pair_chat_permission,
    query_pair_orders, order_to_chat_dict,
)
from utils.fadan_utils import check_fadan_qiangdan_eligible

from orders.utils import (
    calc_shangjia_order_fencheng,
    update_daily_payout,
    settle_shangjia_order_guanshi_fenhong
)
from shop.utils import calculate_pingtai_and_dianpu_shouyi, validate_shangpin_and_dianpu, update_dianpu_daily_stat
from products.utils import update_shangpin_daily_stat
from backend.utils import update_shangjia_daily, update_dashou_daily_by_action, pick_leixing_id, datetime_aliases, fmt_datetime
from rank.services import record_dashou_biaoxian
from rank.utils import check_dashou_biaoqian_required

from orders.notice_tasks import dingdan_guangbo

from ..models import (
    Order, MerchantOrderExt, PlatformOrderExt, PlayerDeliveryImage,
    PenaltyRecord, PenaltyEvidenceImage, Penalty, PenaltyAppealImage, PenaltyBonus, PenaltyBonusRate,
    CommissionRate, PlayerRating, RefundRecord,
)
from jituan.services.club_config import get_commission_rate, get_commission_rate_object
from jituan.services.club_context import resolve_club_id_from_request
from jituan.services.club_user import get_payment_openid
from jituan.services.club_penalty import resolve_penalty_club_id, resolve_penalty_record_club_id
from users.fadan_fenhong_utils import lock_penalty_bonus
from users.fadan_fenhong_utils import lock_penalty_bonus
from products.models import Shangpin, ShangpinLeixing, Huiyuangoumai
from users.models import UserDashou, UserShangjia, UserBoss
from users.business_models import User
from rank.models import DashouBiaoxian, Chenghao, DingdanBiaoqian, YonghuChenghao
from config.models import (
    ShangjiaLianjie
)



logger = logging.getLogger(__name__)

ZHIDING_HF_TEXT = {1: '想接', 2: '不想接', 3: '等会接'}


class DashouDingdanHuoquView(APIView):
    """
    获取可抢订单列表（支持标签筛选）
    POST /dingdan/ddhq
    需要JWT Token认证
    """
    permission_classes = [IsAuthenticated]

    def post(self, request):
        try:
            from orders.services.fake_order_pool import (
                MODE_FAKE_ONLY,
                MODE_MIX,
                build_fake_order_pool_response,
                list_formatted_fake_orders,
                resolve_fake_pool_mode,
            )

            # 1. 获取请求参数
            data = request.data
            leixing_id = pick_leixing_id(data)
            page = int(data.get('page', 1))
            page_size = int(data.get('page_size', 10))
            biaoqian_id = data.get('biaoqian_id')

            from jituan.services.club_context import resolve_effective_club_id
            from jituan.services.huiyuan_bundle import (
                refresh_grab_pool_membership_state,
                resolve_grab_pool_member_display,
            )
            club_id = resolve_effective_club_id(request, getattr(request, 'user', None))

            # 假单模式：封禁只假单；未充会员且押金未达门槛 → 真假混排；有会员/高押金 → 只真单
            fake_mode = resolve_fake_pool_mode(
                request.user, club_id=club_id, leixing_id=leixing_id,
            )
            logger.info(
                'ddhq fake_mode=%s club=%s leixing=%s uid=%s',
                fake_mode, club_id, leixing_id, getattr(request.user, 'UserUID', ''),
            )
            if fake_mode == MODE_FAKE_ONLY:
                return build_fake_order_pool_response(request)

            yonghuid = request.user.UserUID
            _has_member, user_clumber = refresh_grab_pool_membership_state(
                yonghuid, club_id=club_id,
            )

            fake_prefix = []
            if fake_mode == MODE_MIX:
                fake_prefix = list_formatted_fake_orders(club_id, leixing_id)
            fake_n = len(fake_prefix)

            # 2. 构建基础查询条件：本店待抢单 + 集团配置的单向互通店
            from jituan.services.order_grab_share import order_club_q_for_grabber
            base_query = Q(Status__in=[1, 7]) & order_club_q_for_grabber(club_id)
            if leixing_id is not None:
                base_query &= Q(ProductTypeID=leixing_id)

            # 3. 标签筛选：先查出符合条件的订单ID，避免跨表 JOIN 排序冲突
            if biaoqian_id and int(biaoqian_id) > 0:
                biaoqian_order_ids = DingdanBiaoqian.query.filter(
                    chenghao_id=int(biaoqian_id)
                ).values_list('dingdan_id', flat=True)
                base_query &= Q(OrderID__in=list(biaoqian_order_ids))

            # 4. 构建基础查询集
            base_qs = Order.query.filter(base_query).order_by('-CreateTime').distinct()

            # 5. 真单总数；混排时列表前半段是假单
            real_total = base_qs.count()
            total = fake_n + real_total

            # 6. 混排分页：前 fake_n 条为假单，之后为真单
            offset = (page - 1) * page_size
            page_fake = []
            real_offset = 0
            real_limit = page_size
            if fake_n > 0:
                if offset < fake_n:
                    page_fake = fake_prefix[offset:offset + page_size]
                    real_limit = page_size - len(page_fake)
                    real_offset = 0
                else:
                    page_fake = []
                    real_offset = offset - fake_n
                    real_limit = page_size

            # 7. 获取当前页真单
            if real_limit > 0:
                page_qs = base_qs[real_offset:real_offset + real_limit]
            else:
                page_qs = base_qs[0:0]

            # 8. 使用子查询获取商家昵称（Subquery 须用 Django 原生 QuerySet，不能用 .query.values()）
            shangjia_sub = MerchantOrderExt.objects.filter(
                Order__OrderID=OuterRef('OrderID')
            ).values('MerchantNickname')[:1]

            # 9. 获取当前页所有需要的字段
            dingdan_values = page_qs.annotate(
                MerchantNickname=Subquery(shangjia_sub)
            ).values(
                'OrderID', 'Status', 'Platform', 'PlayerCommission',
                'AssignedID', 'AssignedResponse', 'AssignedResponseAt', 'AssignedLaterNote',
                'ProductTypeID', 'ImageURL', 'GrabRequirement',
                'MembershipID', 'CommissionReq', 'Description', 'Remark', 'CreateTime',
                'MerchantNickname', 'ClubID',
            )

            # 10. 转换为列表
            dingdan_list = list(dingdan_values)

            # 11. 批量获取指定打手的头像和昵称
            zhiding_ids = {item['AssignedID'] for item in dingdan_list if item.get('AssignedID')}
            zhiding_info = {}
            if zhiding_ids:
                dashou_query = User.query.filter(
                    UserUID__in=zhiding_ids
                ).select_related('DashouProfile').annotate(
                    Nickname=F('DashouProfile__nicheng')
                ).values('UserUID', 'Avatar', 'Nickname')
                zhiding_info = {
                    item['UserUID']: {
                        'avatar': item['Avatar'] or '',
                        'nicheng': item['Nickname'] or ''
                    }
                    for item in dashou_query
                }

            # ============ 批量获取三层标签 ============
            order_ids = [item['OrderID'] for item in dingdan_list]

            # --- 订单需求标签 ---
            xuqiu_tags_map = {}
            if order_ids:
                try:
                    dbq_qs = DingdanBiaoqian.query.filter(
                        dingdan_id__in=order_ids
                    ).select_related('chenghao')
                    for dbq in dbq_qs:
                        oid = dbq.dingdan_id
                        if oid not in xuqiu_tags_map:
                            xuqiu_tags_map[oid] = []
                        ch = dbq.chenghao
                        xuqiu_tags_map[oid].append({
                            'id': ch.id,
                            'mingcheng': ch.mingcheng,
                            'texiao_json': self._parse_texiao_json(ch.texiao_miaoshu)
                        })
                except Exception as e:
                    logger.error(f"查询订单需求标签失败: {e}", exc_info=True)

            # --- 所有需要查询标签的用户ID集合（指定打手 + 商家） ---
            yonghuid_set = set(zhiding_ids)
            shangjia_order_ids = [item['OrderID'] for item in dingdan_list if item['Platform'] == 2]
            shangjia_id_map = {}
            if shangjia_order_ids:
                # 使用跨表查询 Order__OrderID__in 匹配字符串订单ID
                sj_exts = MerchantOrderExt.query.filter(
                    Order__OrderID__in=shangjia_order_ids
                ).values('Order__OrderID', 'MerchantID')
                for sj in sj_exts:
                    shangjia_id_map[sj['Order__OrderID']] = sj['MerchantID']
                    if sj['MerchantID']:
                        yonghuid_set.add(sj['MerchantID'])

            # 将 yonghuid 字符串转换为 User 的主键 UserUUID
            user_id_map = {}
            user_avatar_map = {}
            if yonghuid_set:
                users = User.query.filter(UserUID__in=yonghuid_set).values('UserUUID', 'UserUID', 'Avatar')
                for u in users:
                    user_id_map[u['UserUID']] = u['UserUUID']
                    user_avatar_map[u['UserUID']] = (u['Avatar'] or '').strip()

            user_main_ids = list(user_id_map.values())
            user_tags_map = {}
            if user_main_ids:
                uc_qs = YonghuChenghao.query.filter(
                    yonghu_id__in=user_main_ids
                ).select_related('chenghao')
                for uc in uc_qs:
                    uid = uc.yonghu_id
                    if uid not in user_tags_map:
                        user_tags_map[uid] = []
                    user_tags_map[uid].append(uc.chenghao)

            dashou_tags_map = {}
            shangjia_tags_map = {}
            for item in dingdan_list:
                oid = item['OrderID']
                # 指定打手标签
                zhid = item['AssignedID']
                dashou_tags = []
                if zhid and zhid in user_id_map:
                    uid = user_id_map[zhid]
                    if uid in user_tags_map:
                        for ch in user_tags_map[uid]:
                            if ch.leixing == 'dashou':
                                dashou_tags.append({
                                    'id': ch.id,
                                    'mingcheng': ch.mingcheng,
                                    'texiao_json': self._parse_texiao_json(ch.texiao_miaoshu)
                                })
                dashou_tags_map[oid] = dashou_tags

                # 商家标签
                sj_tags = []
                if item['Platform'] == 2 and oid in shangjia_id_map:
                    sj_yonghuid = shangjia_id_map[oid]
                    if sj_yonghuid and sj_yonghuid in user_id_map:
                        uid = user_id_map[sj_yonghuid]
                        if uid in user_tags_map:
                            for ch in user_tags_map[uid]:
                                if ch.leixing == 'shangjia':
                                    sj_tags.append({
                                        'id': ch.id,
                                        'mingcheng': ch.mingcheng,
                                        'texiao_json': self._parse_texiao_json(ch.texiao_miaoshu)
                                    })
                shangjia_tags_map[oid] = sj_tags

            # --- 身份装饰标签 + 优质商家 ---
            from jituan.services.identity_tag import (
                SHENFEN_DASHOU,
                SHENFEN_SHANGJIA,
                batch_identity_tags,
            )
            from users.models import UserShangjia

            identity_pairs = []
            youzhi_map = {}
            merchant_uids = {u for u in shangjia_id_map.values() if u}
            if merchant_uids:
                for sj in UserShangjia.query.filter(
                    user__UserUID__in=merchant_uids
                ).select_related('user').values('user__UserUID', 'is_youzhi_shangjia'):
                    youzhi_map[sj['user__UserUID']] = bool(sj['is_youzhi_shangjia'])

            for item in dingdan_list:
                oid = item['OrderID']
                zhid = item.get('AssignedID')
                if zhid:
                    identity_pairs.append((zhid, SHENFEN_DASHOU))
                if item['Platform'] == 2 and oid in shangjia_id_map:
                    sj_uid = shangjia_id_map[oid]
                    if sj_uid:
                        identity_pairs.append((sj_uid, SHENFEN_SHANGJIA))

            identity_tag_map = batch_identity_tags(club_id, identity_pairs) if identity_pairs else {}

            # --- 商家成交指标（有样本才返回） ---
            merchant_stat_map = {}
            if merchant_uids:
                try:
                    from jituan.services.deal_stats import batch_pool_merchant_stats
                    order_club_by_merchant = {}
                    for item in dingdan_list:
                        if item['Platform'] != 2:
                            continue
                        oid = item['OrderID']
                        sj = shangjia_id_map.get(oid)
                        if not sj:
                            continue
                        ocid = (item.get('ClubID') or club_id or '').strip()
                        if sj not in order_club_by_merchant and ocid:
                            order_club_by_merchant[sj] = ocid
                    merchant_stat_map = batch_pool_merchant_stats(
                        club_id, merchant_uids, order_club_map=order_club_by_merchant,
                    )
                except Exception as e:
                    logger.error(f"批量商家成交指标失败: {e}", exc_info=True)

            # 12. 格式化返回数据
            formatted_list = []
            for order in dingdan_list:
                oid = order['OrderID']
                zid = order.get('AssignedID')
                info = zhiding_info.get(zid, {})
                sj_uid = shangjia_id_map.get(oid) if order['Platform'] == 2 else None
                display_grab_req, display_huiyuan_id, has_required_member = (
                    resolve_grab_pool_member_display(
                        order, yonghuid, club_id=club_id, user_clumber=user_clumber,
                    )
                )
                row = {
                    'dingdan_id': order['OrderID'],
                    'zhuangtai': order['Status'],
                    'pingtai': order['Platform'],
                    'dashou_fencheng': float(order['PlayerCommission']) if order['PlayerCommission'] else 0.0,
                    'leixing_id': order['ProductTypeID'] or 0,
                    'tupian': order['ImageURL'] or '',
                    'yaoqiuleixing': display_grab_req,
                    'huiyuan_id': display_huiyuan_id,
                    'hasRequiredMember': has_required_member,
                    'has_required_member': has_required_member,
                    'yajin': float(order['CommissionReq']) if order['CommissionReq'] else 0.0,
                    'jieshao': order['Description'] or '',
                    'beizhu': order['Remark'] or '',
                    'creat_time': fmt_datetime(order['CreateTime']),
                    'create_time': fmt_datetime(order['CreateTime']),
                    'sjnicheng': order['MerchantNickname'] or '',
                    'sj_avatar': user_avatar_map.get(sj_uid, '') if sj_uid else '',
                    'zhiding_uid': order['AssignedID'] or '',
                    'zhiding_avatar': info.get('avatar', ''),
                    'zhiding_nicheng': info.get('nicheng', ''),
                    'zhiding_hf': order.get('AssignedResponse'),
                    'zhiding_hf_text': ZHIDING_HF_TEXT.get(order.get('AssignedResponse'), ''),
                    'zhiding_dhj_sm': order.get('AssignedLaterNote') or '',
                    'zhiding_hf_sj': fmt_datetime(order['AssignedResponseAt']) if order.get('AssignedResponseAt') else '',
                    # 三层标签
                    'xuqiu_biaoqian': xuqiu_tags_map.get(oid, []),
                    'dashou_biaoqian': dashou_tags_map.get(oid, []),
                    'shangjia_biaoqian': shangjia_tags_map.get(oid, []),
                    # 身份装饰标签 + 优质商家
                    'shangjia_identity_biaoqian': identity_tag_map.get((sj_uid, SHENFEN_SHANGJIA), []) if sj_uid else [],
                    'zhiding_identity_biaoqian': identity_tag_map.get((zid, SHENFEN_DASHOU), []) if zid else [],
                    'shangjia_youzhi': bool(youzhi_map.get(sj_uid)) if sj_uid else False,
                }
                if sj_uid and sj_uid in merchant_stat_map:
                    row['shangjia_deal_stat'] = merchant_stat_map[sj_uid]
                formatted_list.append(row)

            # 混排：假单在前（展示价格），真单在后（未开通会员时前端显示「未开通会员」）
            if page_fake:
                formatted_list = list(page_fake) + formatted_list

            has_more = (page * page_size) < total

            badge = {}
            try:
                from orders.services.dashou_badges import dashou_badge_fields
                badge = dashou_badge_fields(club_id, user=request.user)
            except Exception as e:
                logger.warning('ddhq 角标附加失败: %s', e)

            return Response({
                'code': 200,
                'msg': '获取成功',
                'data': {
                    'list': formatted_list,
                    'has_more': has_more,
                    'total': total,
                    'current_page': page,
                    'page_size': page_size,
                    'total_pages': (total + page_size - 1) // page_size if page_size else 0,
                    'clumber': user_clumber,
                    'is_fake_pool': False,
                    'fake_pool_mode': fake_mode,
                    **badge,
                }
            })

        except Exception as e:
            logger.error(f"订单列表查询失败: {e}", exc_info=True)
            return Response({'code': 500, 'msg': f'服务器内部错误: {str(e)}'}, status=500)

    def _parse_texiao_json(self, texiao_miaoshu):
        if not texiao_miaoshu:
            return {}
        try:
            return json.loads(texiao_miaoshu)
        except:
            return {}





class ShangpinLeixingHuoquView(APIView):
    """
    获取商品类型列表
    POST /dingdan/ddlxhq
    需要JWT Token认证
    """
    authentication_classes = [JWTAuthentication]
    permission_classes = [IsAuthenticated]

    def post(self, request):
        # 1. 查询商品类型表
        # 假设你的商品类型模型字段为：id, jieshao, tupian_url
        leixing_list = ShangpinLeixing.query.all().values(
            'id',  # 商品类型ID
            'jieshao',  # 类型介绍
            'tupian_url'  # 类型图片URL（相对URL）
        ).order_by('id')  # 按ID排序，可根据需要调整

        # 2. 格式化返回数据
        formatted_list = []
        for leixing in leixing_list:
            formatted_leixing = {
                'id': leixing['id'],
                'jieshao': leixing['jieshao'] or '',  # 处理空值
                'tupian_url': leixing['tupian_url'] or ''  # 处理空值
            }
            formatted_list.append(formatted_leixing)

        # 3. 返回响应
        return Response({
            'code': 200,
            'msg': '获取成功',
            'data': {
                'list': formatted_list,
                'total': len(formatted_list)
            }
        })




# ----------------- 基础配置获取 -----------------


class QiangdanView(APIView):
    authentication_classes = [JWTAuthentication]
    permission_classes = [IsAuthenticated]

    def post(self, request):
        data = request.data
        dingdan_id = data.get('dingdan_id') or data.get('OrderID')
        if not dingdan_id:
            return Response({'code': 400, 'msg': '订单ID不能为空'}, status=400)

        dingdan_id = str(dingdan_id).strip()
        if dingdan_id.upper().startswith('JD'):
            return Response({
                'code': 400,
                'msg': '您没充值会员或保证金不可接单',
                'fail_type': 'huiyuan',
            })

        try:
            with transaction.atomic():
                # 1. 验证打手身份和状态
                dashou_profile = self._validate_dashou_status(request.user)
                if not dashou_profile:
                    return Response({'code': 403, 'msg': '您不是打手或账号状态异常'}, status=403)


                # ==================== 【新增】罚单检查 ====================
                fadan_ok, fadan_msg = check_fadan_qiangdan_eligible(request.user.UserUID,1)
                if not fadan_ok:
                    return Response({'code': 400, 'msg': fadan_msg})
                # =========================================================    
                # ========== 标签快速校验（提前拒绝，避免锁资源） ==========
                biaoqian_ok, biaoqian_msg = check_dashou_biaoqian_required(dingdan_id, request.user.UserUID)
                if not biaoqian_ok:
                    return Response({'code': 400, 'msg': biaoqian_msg})
                # ===========================================================

                # 2. 锁定并验证订单（行锁）
                order_result = self._validate_and_lock_order(dingdan_id, request.user.UserUID)
                if isinstance(order_result, str):
                    return Response({'code': 400, 'msg': order_result})
                order = order_result

                # 2.1 俱乐部互通：只能抢本店或已授权可抢的对方店订单
                from jituan.services.club_context import resolve_effective_club_id
                from jituan.services.order_grab_share import can_grabber_take_order_club
                grabber_club = resolve_effective_club_id(request, request.user)
                if not can_grabber_take_order_club(grabber_club, getattr(order, 'ClubID', None)):
                    return Response({'code': 403, 'msg': '无权抢该俱乐部订单'})

                validation_result = self._validate_order_requirements(order, dashou_profile, request.user.UserUID)
                if not validation_result['success']:
                    payload = {
                        'code': 400,
                        'msg': validation_result['message'],
                    }
                    # 结构化失败类型，供前端跳转会员/押金页（不影响旧客户端）
                    if validation_result.get('fail_type'):
                        payload['fail_type'] = validation_result['fail_type']
                    if validation_result.get('huiyuan_id') is not None:
                        payload['huiyuan_id'] = validation_result['huiyuan_id']
                    if validation_result.get('required_yajin') is not None:
                        payload['required_yajin'] = validation_result['required_yajin']
                    return Response(payload)
                self._execute_qiangdan(order, dashou_profile, request.user.UserUID)

            # 建聊必须在事务提交后：GoEasy HTTP 不可放在行锁事务里，失败也不回滚抢单
            chat_success = False
            try:
                chat_success = establish_order_chat(dingdan_id)
                if not chat_success:
                    # 再试一次，避免偶发订阅/发消息失败导致消息列表空白
                    chat_success = establish_order_chat(dingdan_id)
            except Exception as e:
                logger.error(f"抢单后建立聊天失败 dingdan={dingdan_id}: {e}", exc_info=True)

            try:
                update_dashou_daily_by_action(
                    yonghuid=order.PlayerID,
                    amount=order.PlayerCommission,
                    action=1
                )
                logger.info(f"打手 {order.PlayerID} 每日统计更新成功")
            except Exception as e:
                logger.error(f"打手每日统计更新失败: {e}")


            # 在 QiangdanView.post 里，_execute_qiangdan 之后添加：
            # 记录抢单表现（不影响主流程）
            # 如果订单表里有 bankuai 信息，可以用 order.bankuai 代替 None
            record_dashou_biaoxian(
                dingdan_id=dingdan_id,
                dashou_id=order.PlayerID,
                xingwei=1,
                jiedan_time=timezone.now(),  # 直接取当前时间
                bankuai=None  # 暂不填，后续提交时补上
            )    

            return Response({
                'code': 200,
                'msg': '抢单成功',
                'data': {
                    'dingdan_id': dingdan_id,
                    'chat_established': chat_success
                }
            })

        except Exception as e:
            logger.error(f"抢单异常: {str(e)}", exc_info=True)
            return Response({'code': 500, 'msg': '系统异常，请稍后重试'}, status=500)

    # ---------- 以下所有方法原封不动照抄旧版 ----------
    def _validate_dashou_status(self, user):
        try:
            dashou_profile = user.DashouProfile
            if (dashou_profile.zhuangtai != 1 or
                dashou_profile.zhanghaozhuangtai != 1 or
                dashou_profile.jifen < 5):
                return None
            return dashou_profile
        except UserDashou.DoesNotExist:
            return None

    def _validate_and_lock_order(self, dingdan_id, dashou_yonghuid):
        try:
            order = Order.query.select_for_update().get(OrderID=dingdan_id)
            if order.Status not in [1, 7]:
                return "订单状态不可抢"
            if order.Status == 7:
                if not order.AssignedID or order.AssignedID != dashou_yonghuid:
                    return "此订单为指定单，您不是指定打手"
            if order.PlayerID:
                return "订单已被其他打手抢走"
            return order
        except Order.DoesNotExist:
            return "订单不存在"

    def _validate_order_requirements(self, order, dashou_profile, dashou_yonghuid):
        if order.GrabRequirement == 1:
            return self._validate_huiyuan_requirement(order, dashou_yonghuid)
        elif order.GrabRequirement == 2:
            return self._validate_yajin_requirement(order, dashou_profile)
        return {'success': True, 'message': '验证通过'}

    def _validate_huiyuan_requirement(self, order, dashou_yonghuid):
        from jituan.services.huiyuan_bundle import (
            user_has_huiyuan_access_any,
            resolve_order_membership_ids,
            normalize_huiyuan_id,
        )
        from jituan.services.club_context import resolve_effective_club_id

        club_id = None
        try:
            club_id = resolve_effective_club_id(self.request, self.request.user)
        except Exception:
            pass
        order_dict = {
            'MembershipID': order.MembershipID,
            'GrabRequirement': order.GrabRequirement,
            'ProductTypeID': order.ProductTypeID,
        }
        required_ids = resolve_order_membership_ids(order_dict)
        if user_has_huiyuan_access_any(dashou_yonghuid, required_ids, club_id=club_id):
            return {'success': True, 'message': '会员验证通过'}
        primary = ''
        if required_ids:
            primary = normalize_huiyuan_id(required_ids[0]) or str(required_ids[0])
        elif order.MembershipID:
            primary = normalize_huiyuan_id(order.MembershipID) or str(order.MembershipID)
        return {
            'success': False,
            'message': '未开通对应会员或会员已过期，无法抢此订单',
            'fail_type': 'huiyuan',
            'huiyuan_id': primary,
        }

    def _validate_yajin_requirement(self, order, dashou_profile):
        yajin_required = order.CommissionReq or 0
        dashou_yajin = dashou_profile.yajin or 0
        try:
            need = float(yajin_required)
        except (TypeError, ValueError):
            need = 0.0
        try:
            have = float(dashou_yajin)
        except (TypeError, ValueError):
            have = 0.0
        if have < need:
            return {
                'success': False,
                'message': f'押金不足，需要{need}元，当前有{have}元',
                'fail_type': 'yajin',
                'required_yajin': need,
            }
        return {'success': True, 'message': '押金验证通过'}

    def _execute_qiangdan(self, order, dashou_profile, dashou_yonghuid):
        order.Status = 2
        order.PlayerID = dashou_yonghuid
        order.User2ID = f"Ds{dashou_yonghuid}"
        order.save()

        dashou_profile.zhuangtai = 0
        dashou_profile.jiedanzongliang = F('jiedanzongliang') + 1
        dashou_profile.jinrijiedan = F('jinrijiedan') + 1
        dashou_profile.jinyuejiedan = F('jinyuejiedan') + 1
        dashou_profile.save()


class DashouDingdanHuoquView1(APIView):
    """
    打手订单获取接口
    支持筛选条件：
    - zhuangtai_list: 订单状态列表（可选，空数组或不传表示全部状态）
    - leixing_id: 商品类型ID（可选）
    - keyword: 搜索关键词，模糊匹配订单ID和订单介绍（可选）
    """
    permission_classes = [IsAuthenticated]

    def post(self, request):
        # 1. 获取当前登录用户的 yonghuid
        try:
            current_user = request.user
            yonghuid = current_user.UserUID
        except AttributeError:
            return Response({
                'code': 1,
                'msg': '用户认证失败',
                'data': None
            }, status=status.HTTP_401_UNAUTHORIZED)

        # 2. 获取并校验前端参数
        try:
            data = request.data
            zhuangtai_list = data.get('zhuangtai_list', [])   # 可选，默认空列表（全部）
            page = max(1, int(data.get('page', 1)))
            page_size = min(100, max(1, int(data.get('page_size', 10))))
            leixing_id = pick_leixing_id(data)          # 可选，商品类型ID
            keyword = data.get('keyword', '').strip()          # 可选，搜索关键词
        except (ValueError, TypeError):
            return Response({
                'code': 2,
                'msg': '参数格式错误',
                'data': None
            }, status=status.HTTP_400_BAD_REQUEST)

        # 3. 参数默认值与类型修正
        if not isinstance(zhuangtai_list, list):
            zhuangtai_list = []   # 非列表则视为全部

        # 4. 构建查询条件
        try:
            # 基础条件：本人接单 或 本俱乐部组队在队成员（队友也能在订单列表看到）
            from orders.models import TeamMember, TeamRecruit
            team_oids = list(
                TeamMember.query.filter(
                    user_uid=yonghuid,
                    join_status=TeamMember.JOIN_ACTIVE,
                ).values_list('order_id', flat=True)[:500]
            )
            if team_oids:
                # 仅有效组队帖（招募中/锁定/已分账结束）
                valid_oids = list(
                    TeamRecruit.query.filter(
                        order_id__in=team_oids,
                        status__in=[
                            TeamRecruit.STATUS_RECRUITING,
                            TeamRecruit.STATUS_LOCKED,
                            TeamRecruit.STATUS_FINISHED,
                        ],
                    ).values_list('order_id', flat=True)
                )
                query = Q(PlayerID=yonghuid) | Q(OrderID__in=valid_oids or ['__none__'])
            else:
                query = Q(PlayerID=yonghuid)

            # 状态筛选：如果 zhuangtai_list 不为空列表，则加入筛选；否则查询全部状态
            if zhuangtai_list:
                query &= Q(Status__in=zhuangtai_list)

            # 商品类型筛选
            if leixing_id is not None:
                query &= Q(ProductTypeID=leixing_id)

            # 关键词搜索：模糊匹配订单ID和订单介绍
            if keyword:
                keyword_query = Q(OrderID__icontains=keyword) | Q(Description__icontains=keyword)
                query &= keyword_query

            from orders.services.merchant_order_list_filters import wants_auto_settle_pending
            # 待自动结算筛：强制落在结算中且 eligible
            if wants_auto_settle_pending(data):
                query &= Q(Status=8, AutoSettleEligible=True, AutoExpireAt__isnull=False)

            # 5. 执行查询，按创建时间倒序
            dingdan_query = Order.query.filter(query).order_by('-CreateTime')

            # 只选择需要的字段，提高性能
            dingdan_query = dingdan_query.only(
                'OrderID',
                'Status',
                'PlayerCommission',   # 打手分成金额
                'Description',
                'ImageURL',
                'Nickname',
                'CreateTime',
                'AutoSettleEligible',
                'AutoExpireAt',
            )

            total_count = dingdan_query.count()

            # 6. 分页处理
            start_index = (page - 1) * page_size
            end_index = start_index + page_size
            current_page_orders = dingdan_query[start_index:end_index]
            current_page_count = len(current_page_orders)

            # 7. 构建返回数据列表（附组队标记，无游戏ID）
            from jituan.services.order_deal import order_auto_settle_payload
            from orders.services.team_recruit import batch_team_list_flags
            page_oids = [o.OrderID for o in current_page_orders]
            team_flags = batch_team_list_flags(page_oids, viewer_uid=yonghuid)
            order_list = []
            for order in current_page_orders:
                order_data = {
                    'dingdan_id': order.OrderID,
                    'zhuangtai': order.Status,
                    'jine': float(order.PlayerCommission) if order.PlayerCommission else 0.0,
                    'jieshao': order.Description or '',
                    'tupian': order.ImageURL or '',
                    'nicheng': order.Nickname or '',
                    **datetime_aliases(order.CreateTime),
                }
                order_data.update(order_auto_settle_payload(order))
                tf = team_flags.get(order.OrderID) or {'has_team': False}
                order_data.update(tf)
                order_list.append(order_data)

            # 8. 判断是否还有更多数据
            has_more = (current_page_count == page_size) and (end_index < total_count)
            if total_count == 0:
                has_more = False

            badge = {}
            try:
                from jituan.services.club_context import resolve_effective_club_id
                from orders.services.dashou_badges import dashou_badge_fields
                badge = dashou_badge_fields(
                    resolve_effective_club_id(request, getattr(request, 'user', None)),
                    user=getattr(request, 'user', None),
                )
            except Exception as e:
                logger.warning('dshqdingdan 角标附加失败: %s', e)

            return Response({
                'code': 0,
                'msg': '成功',
                'data': {
                    'list': order_list,
                    'has_more': has_more,
                    'total': total_count,
                    **badge,
                }
            }, status=status.HTTP_200_OK)

        except Exception as e:
            logger.error(f"打手订单获取失败: {str(e)}", exc_info=True)

            return Response({
                'code': 4,
                'msg': '服务器内部错误',
                'data': None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)



class DashouCOSZhengshuView(APIView):
    """打手获取COS上传凭证接口（调试版本）"""
    permission_classes = [IsAuthenticated]

    def post(self, request):
        try:
            # 1. 接收参数（兼容 OrderID / dingdan_id）
            dingdan_id = str(request.data.get('OrderID') or request.data.get('dingdan_id') or '').strip()
            yongtu = request.data.get('yongtu', 'dingdan')

            # 2. 条件判断修正：除了 fakuan 之外，其他用途均需提供 dingdan_id
            if yongtu != 'fakuan' and not dingdan_id:
                return Response(
                    {'code': 400, 'msg': '订单ID不能为空', 'error': 'dingdan_id is required when yongtu is not fakuan'},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 3. 业务验证逻辑（根据用途分别验证）
            if yongtu == 'chufa':
                try:
                    chufa_record = PenaltyRecord.query.filter(
                        OrderID=dingdan_id,
                        PlayerID=request.user.UserUID,
                        ApplyStatus__in=[0, 3]
                    ).first()
                    if not chufa_record:
                        return Response(
                            {'code': 403, 'msg': '处罚记录无权限或状态不对',
                             'error': f'No punishment record found for user {request.user.UserUID} on order {dingdan_id}'},
                            status=status.HTTP_403_FORBIDDEN
                        )
                except Exception as e:
                    logger.error(f"查处罚记录异常: {str(e)}")
                    return Response(
                        {'code': 500, 'msg': '服务器内部错误', 'error': str(e)},
                        status=status.HTTP_500_INTERNAL_SERVER_ERROR
                    )
            elif yongtu == 'fakuan':
                # 罚款申诉不需要订单验证
                pass
            elif yongtu in ('fakuan_evidence', 'fakuan_evidence_draft'):
                # 商家或子客服（总管等）上传/补传罚单证据图
                from merchant_ops.helpers import (
                    PenaltyEvidenceAuthError,
                    resolve_penalty_evidence_upload_auth,
                )
                if not dingdan_id:
                    return Response({'code': 400, 'msg': '缺少订单ID'}, status=400)
                fadan_id = request.data.get('fadan_id') if yongtu == 'fakuan_evidence' else None
                if yongtu == 'fakuan_evidence' and not fadan_id:
                    return Response(
                        {'code': 400, 'msg': '缺少订单ID或罚单ID'},
                        status=status.HTTP_400_BAD_REQUEST,
                    )
                try:
                    resolve_penalty_evidence_upload_auth(request, dingdan_id, fadan_id=fadan_id)
                except PenaltyEvidenceAuthError as e:
                    return Response({'code': e.code, 'msg': e.msg}, status=403)
            elif yongtu == 'tuikuan_evidence':
                # 商家老板或能操作该订单的子客服上传退款证据图
                if not dingdan_id:
                    return Response({'code': 400, 'msg': '缺少订单ID'}, status=400)
                uid = getattr(request.user, 'UserUID', None)
                allowed = False
                try:
                    from orders.models import MerchantOrderExt
                    sj = getattr(request.user, 'ShopProfile', None)
                    if sj and getattr(sj, 'zhuangtai', None) == 1:
                        if MerchantOrderExt.query.filter(
                            Order__OrderID=dingdan_id, MerchantID=uid
                        ).exists():
                            allowed = True
                except Exception:
                    pass
                if not allowed:
                    try:
                        from merchant_ops.services.authz import get_active_staff_member, staff_can_access_order
                        member = get_active_staff_member(request.user)
                        if member:
                            ok, _ = staff_can_access_order(member, dingdan_id)
                            allowed = bool(ok)
                    except Exception:
                        pass
                if not allowed:
                    return Response({'code': 403, 'msg': '无权上传退款图片'}, status=403)
            else:
                # 默认为订单交付图：组队仅队长；非组队须接单人
                try:
                    dingdan = Order.query.get(
                        OrderID=dingdan_id,
                        Status__in=[2, 8]
                    )
                except Order.DoesNotExist:
                    return Response(
                        {'code': 403, 'msg': '此功能暂未开放', 'error': f'Order {dingdan_id} not found'},
                        status=status.HTTP_403_FORBIDDEN
                    )
                try:
                    from orders.services.team_recruit import ensure_team_leader_can_submit
                    deny = ensure_team_leader_can_submit(dingdan, request.user.UserUID)
                    if deny:
                        return Response({'code': 403, 'msg': deny}, status=status.HTTP_403_FORBIDDEN)
                except Exception:
                    if dingdan.PlayerID != request.user.UserUID:
                        return Response(
                            {'code': 403, 'msg': '此功能暂未开放'},
                            status=status.HTTP_403_FORBIDDEN
                        )

            # 4. 获取腾讯云STS临时密钥
            try:
                # 初始化固定凭证
                cred = credential.Credential(
                    settings.COS_SECRET_ID,
                    settings.COS_SECRET_KEY
                )

                # 创建STS客户端
                http_profile = HttpProfile()
                http_profile.endpoint = "sts.tencentcloudapi.com"
                client_profile = ClientProfile()
                client_profile.httpProfile = http_profile
                client = sts_client.StsClient(cred, "ap-shanghai", client_profile)

                # 构建策略资源
                resources = []
                if yongtu == 'chufa':
                    resources.append(
                        f"qcs::cos:{settings.COS_REGION}:uid/{settings.COS_APPID}:{settings.COS_BUCKET}/a_long/chfajltp/dssstp/*"
                    )
                elif yongtu == 'fakuan':
                    resources.append(
                        f"qcs::cos:{settings.COS_REGION}:uid/{settings.COS_APPID}:{settings.COS_BUCKET}/fakuan/dashoufakuan/dashoufakuanshensu/*"
                    )
                elif yongtu == 'fakuan_evidence':
                    resources.append(
                        f"qcs::cos:{settings.COS_REGION}:uid/{settings.COS_APPID}:{settings.COS_BUCKET}/fakuan/shangjiafakuan/zhengju/*"
                    )
                elif yongtu == 'fakuan_evidence_draft':
                    resources.append(
                        f"qcs::cos:{settings.COS_REGION}:uid/{settings.COS_APPID}:{settings.COS_BUCKET}/fakuan/shangjiafakuan/zhengju/*"
                    )
                elif yongtu == 'tuikuan_evidence':
                    resources.append(
                        f"qcs::cos:{settings.COS_REGION}:uid/{settings.COS_APPID}:{settings.COS_BUCKET}/tuikuan/shangjiatuikuan/zhengju/*"
                    )
                else:
                    resources.append(
                        f"qcs::cos:{settings.COS_REGION}:uid/{settings.COS_APPID}:{settings.COS_BUCKET}/order/{dingdan_id}/*"
                    )

                policy = {
                    "version": "2.0",
                    "statement": [{
                        "effect": "allow",
                        "action": [
                            "cos:PutObject",
                            "cos:PostObject",
                            "cos:InitiateMultipartUpload",
                            "cos:UploadPart",
                            "cos:CompleteMultipartUpload"
                        ],
                        "resource": resources
                    }]
                }

                req = models.GetFederationTokenRequest()
                req.Name = f"dashou_{dingdan_id}_{int(time.time())}"
                req.Policy = json.dumps(policy)
                req.DurationSeconds = 7200

                resp = client.GetFederationToken(req)
                credentials = resp.Credentials

            except TencentCloudSDKException as e:
                logger.error(f"获取STS临时密钥失败: {str(e)}")
                return Response({
                    'code': 500,
                    'msg': f'获取上传凭证失败: {str(e)}',
                    'error_detail': str(e)
                }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

            # 5. 构建响应
            current_time = int(time.time())
            upload_dir = (
                'tuikuan/shangjiatuikuan/zhengju/' if yongtu == 'tuikuan_evidence' else
                'fakuan/shangjiafakuan/zhengju/' if yongtu in ('fakuan_evidence', 'fakuan_evidence_draft') else
                'fakuan/dashoufakuan/dashoufakuanshensu/' if yongtu == 'fakuan' else (
                    'a_long/chfajltp/dssstp/' if yongtu == 'chufa' else f'order/{dingdan_id}/'
                )
            )
            response_data = {
                'credentials': {
                    'tmpSecretId': credentials.TmpSecretId,
                    'tmpSecretKey': credentials.TmpSecretKey,
                    'sessionToken': credentials.Token,
                },
                'startTime': current_time,
                'expiredTime': current_time + 7200,
                'bucket': settings.COS_BUCKET,
                'region': settings.COS_REGION,
                'upload_dir': upload_dir,
            }
            return Response({'code': 0, 'msg': '成功', 'data': response_data})

        except Exception as e:
            # 捕捉所有未预期的异常，返回完整 traceback
            logger.error(f'COS凭证接口未知错误: {traceback.format_exc()}')
            return Response({
                'code': 500,
                'msg': f'服务器内部错误: {str(e)}',
                'error_detail': traceback.format_exc()
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)


class ShangjiaCOSZhengshuView(APIView):
    """商家获取COS上传凭证接口（用于处罚申诉图片上传）"""
    permission_classes = [IsAuthenticated]

    def post(self, request):
        try:
            # 1. 接收参数
            dingdan_id = str(request.data.get('OrderID') or request.data.get('dingdan_id') or '').strip()
            yongtu = request.data.get('yongtu', 'chufa')  # 用途：chufa=处罚申诉

            if not dingdan_id:
                return Response({'code': 1, 'msg': '订单ID不能为空', 'data': None},
                                status=status.HTTP_400_BAD_REQUEST)

            # 2. 🔴【修改】验证商家身份 - 通过反向查询shop_profile判断是否为商家
            try:
                # 检查是否有商家扩展表
                shangjia_profile = request.user.ShopProfile

                # 验证商家状态是否为1（正常）
                if shangjia_profile.zhuangtai != 1:
                    return Response({'code': 3, 'msg': '商家账号状态异常，无法操作', 'data': None},
                                    status=status.HTTP_403_FORBIDDEN)

                # 🔴【重要】获取商家ID（从商家扩展表中获取）
                shangjia_id = request.user.UserUID  # 假设商家扩展表中有yonghuid字段

            except AttributeError:
                # 没有shop_profile属性，说明不是商家
                return Response({'code': 3, 'msg': '非商家用户无权限', 'data': None},
                                status=status.HTTP_403_FORBIDDEN)

            # 3. 🔴【修改】验证订单权限 - 通过商家订单扩展表验证
            try:
                # 获取订单
                dingdan = Order.query.get(OrderID=dingdan_id)

                # 🔴【重要】通过反向查询商家扩展表验证订单是否属于当前商家
                try:
                    shangjia_kuozhan = dingdan.shangjia_kuozhan  # 使用反向关系名

                    # 验证商家ID是否匹配
                    if str(shangjia_kuozhan.MerchantID) != str(shangjia_id):
                        return Response({'code': 2, 'msg': '订单不属于当前商家', 'data': None},
                                        status=status.HTTP_403_FORBIDDEN)

                    # 验证订单状态是否允许申请处罚（根据前端逻辑）
                    allowed_zhuangtai = [2, 4, 5, 6, 8]
                    if dingdan.Status not in allowed_zhuangtai:
                        return Response({'code': 4, 'msg': '当前订单状态不允许申请处罚', 'data': None},
                                        status=status.HTTP_400_BAD_REQUEST)

                    # 🔴【新增】检查是否已存在处罚申请（通过Chufajilu模型）
                    # 注意：这里假设Chufajilu模型存在，并且有shangjia_id字段
                    try:
                        existing_chufa = PenaltyRecord.query.filter(
                            OrderID=dingdan_id,
                            ApplicantID=shangjia_id,
                            ApplyStatus__in=[0, 1]  # 审核中或已处罚状态
                        ).exists()

                        if existing_chufa:
                            return Response({'code': 5, 'msg': '该订单已有处罚申请，请勿重复上传', 'data': None},
                                            status=status.HTTP_400_BAD_REQUEST)
                    except ImportError:
                        # 如果没有Chufajilu模型，跳过这个检查
                        pass

                except MerchantOrderExt.DoesNotExist:
                    # 没有商家扩展记录，说明这不是商家订单
                    return Response({'code': 2, 'msg': '非商家订单无法操作', 'data': None},
                                    status=status.HTTP_403_FORBIDDEN)

            except Order.DoesNotExist:
                return Response({'code': 2, 'msg': '订单不存在', 'data': None},
                                status=status.HTTP_404_NOT_FOUND)
            except Exception as e:
                logger.error(f"订单验证异常: {str(e)}")
                return Response({'code': 500, 'msg': '服务器验证异常', 'data': None},
                                status=status.HTTP_500_INTERNAL_SERVER_ERROR)

            # 4. 获取腾讯云STS临时密钥
            try:
                # 初始化固定凭证
                cred = credential.Credential(
                    settings.COS_SECRET_ID,
                    settings.COS_SECRET_KEY
                )

                # 创建STS客户端
                http_profile = HttpProfile()
                http_profile.endpoint = "sts.tencentcloudapi.com"
                client_profile = ClientProfile()
                client_profile.httpProfile = http_profile

                client = sts_client.StsClient(cred, "ap-shanghai", client_profile)

                # 🔴【修改】构建策略 - 只允许上传到商家处罚证据图片目录
                resources = [
                    f"qcs::cos:{settings.COS_REGION}:uid/{settings.COS_APPID}:{settings.COS_BUCKET}/a_long/chfajltp/sjzjtp/*"
                ]

                policy = {
                    "version": "2.0",
                    "statement": [
                        {
                            "effect": "allow",
                            "action": [
                                "cos:PutObject",
                                "cos:PostObject",
                                "cos:InitiateMultipartUpload",
                                "cos:UploadPart",
                                "cos:CompleteMultipartUpload"
                            ],
                            "resource": resources
                        }
                    ]
                }

                # 请求STS临时凭证
                req = models.GetFederationTokenRequest()
                # 🔴【修改】命名包含商家ID
                req.Name = f"shangjia_{shangjia_id}_{dingdan_id}_{int(time.time())}"
                req.Policy = json.dumps(policy)
                req.DurationSeconds = 7200  # 2小时有效期

                resp = client.GetFederationToken(req)

                # 提取临时密钥
                credentials = resp.Credentials

            except TencentCloudSDKException as e:
                logger.error(f"商家获取STS临时密钥失败: {str(e)}")
                return Response({
                    'code': 500,
                    'msg': f'获取上传凭证失败: {str(e)}',
                    'data': None
                }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

            # 5. 构建响应数据
            current_time = int(time.time())
            response_data = {
                'credentials': {
                    'tmpSecretId': credentials.TmpSecretId,
                    'tmpSecretKey': credentials.TmpSecretKey,
                    'sessionToken': credentials.Token,
                },
                'startTime': current_time,
                'expiredTime': current_time + 7200,
                'bucket': settings.COS_BUCKET,
                'region': settings.COS_REGION,
                # 🔴【修改】商家专用上传目录
                'upload_dir': 'a_long/chfajltp/sjzjtp/',
                # 返回商家ID和订单ID，便于前端生成文件名
                'dingdan_id': dingdan_id,
                'shangjia_id': shangjia_id,
                # 返回商家昵称，便于前端显示
                'shangjia_nicheng': shangjia_profile.nicheng if hasattr(shangjia_profile, 'nicheng') else ''
            }

            # 6. 返回成功
            return Response({
                'code': 0,
                'msg': '成功',
                'data': response_data
            }, status=status.HTTP_200_OK)

        except Exception as e:
            logger.error(f'商家COS凭证接口未知错误: {str(e)}', exc_info=True)
            return Response({
                'code': 500,
                'msg': f'服务器内部错误: {str(e)}',
                'data': None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)


class DashouTijiaoView(APIView):
    """打手提交订单完成接口"""
    permission_classes = [IsAuthenticated]

    def post(self, request):
        try:
            # 1. 获取参数
            data = request.data
            dingdan_id = str(data.get('OrderID') or data.get('dingdan_id') or '').strip()
            liuyan = data.get('liuyan', '')
            jiaofu_tupian_urls = data.get('jiaofu_tupian_urls', [])

            # 2. 参数验证
            if not dingdan_id:
                return Response({
                    'code': 1,
                    'msg': '订单ID不能为空',
                    'data': None
                }, status=status.HTTP_400_BAD_REQUEST)

            if not isinstance(jiaofu_tupian_urls, list):
                return Response({
                    'code': 2,
                    'msg': '图片URL列表格式错误',
                    'data': None
                }, status=status.HTTP_400_BAD_REQUEST)

            # 限制图片数量（最多9张，最少1张）
            if len(jiaofu_tupian_urls) == 0:
                return Response({
                    'code': 3,
                    'msg': '至少需要上传一张图片',
                    'data': None
                }, status=status.HTTP_400_BAD_REQUEST)

            if len(jiaofu_tupian_urls) > 9:
                return Response({
                    'code': 4,
                    'msg': '最多只能上传9张图片',
                    'data': None
                }, status=status.HTTP_400_BAD_REQUEST)

            # 留言长度限制（50字）
            if liuyan and len(liuyan) > 50:
                return Response({
                    'code': 5,
                    'msg': '留言最多50个字',
                    'data': None
                }, status=status.HTTP_400_BAD_REQUEST)

            # 3. 获取当前用户并验证打手身份
            current_user = request.user
            yonghuid = current_user.UserUID

            try:
                dashou_profile = current_user.DashouProfile
            except UserDashou.DoesNotExist:
                return Response({
                    'code': 6,
                    'msg': '用户不是打手身份',
                    'data': None
                }, status=status.HTTP_403_FORBIDDEN)

            # 4. 验证订单状态和权限（组队单仅队长可提交）
            try:
                dingdan = Order.query.get(OrderID=dingdan_id, Status=2)
            except Order.DoesNotExist:
                return Response({
                    'code': 7,
                    'msg': '订单不存在或没有提交权限',
                    'data': None
                }, status=status.HTTP_403_FORBIDDEN)
            try:
                from orders.services.team_recruit import ensure_team_leader_can_submit
                deny = ensure_team_leader_can_submit(dingdan, yonghuid)
                if deny:
                    return Response({'code': 7, 'msg': deny, 'data': None}, status=status.HTTP_403_FORBIDDEN)
            except Exception:
                if dingdan.PlayerID != yonghuid:
                    return Response({
                        'code': 7,
                        'msg': '订单不存在或没有提交权限',
                        'data': None
                    }, status=status.HTTP_403_FORBIDDEN)

            # 5. 存储图片到Dashoutupian表（统一记在接单人/队长名下，组员可读）
            owner_uid = dingdan.PlayerID or yonghuid
            for tupian_url in jiaofu_tupian_urls:
                PlayerDeliveryImage.query.create(
                    OrderID=dingdan_id,
                    PlayerID=owner_uid,
                    ImageURL=tupian_url,
                    CreateTime=timezone.now()
                )

            # 6. 更新订单主表
            dingdan.PlayerRemark = liuyan
            dingdan.Status = 8  # 状态改为结算中
            dingdan.UpdateTime = timezone.now()
            dingdan.save()

            # 7. 更新打手扩展表状态
            dashou_profile.zhuangtai = 1  # 改为数字1（根据你之前说的）
            dashou_profile.save()

            # ========== 新增：记录打手提交时间 ==========
            record_dashou_biaoxian(
                dingdan_id=dingdan_id,
                dashou_id=yonghuid,
                xingwei=2,  # 提交
                tijiao_time=timezone.now()
            )
            # ===========================================

            # 8. 返回成功响应
            return Response({
                'code': 0,
                'msg': '订单提交成功',
                'data': {
                    'dingdan_id': dingdan_id,
                    'new_zhuangtai': 8,  # 新的订单状态
                    'dashou_zhuangtai': 1  # 打手新的状态
                }
            }, status=status.HTTP_200_OK)

        except Exception as e:
            logger.error(f"打手提交订单失败: {str(e)}", exc_info=True)

            return Response({
                'code': 8,
                'msg': '服务器内部错误',
                'data': None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)


class DashouDingdanXiangqingView(APIView):
    """打手订单详情获取接口"""
    permission_classes = [IsAuthenticated]

    def post(self, request):
        try:
            # 1. 获取订单ID
            dingdan_id = str(request.data.get('OrderID') or request.data.get('dingdan_id') or '').strip()
            if not dingdan_id:
                return Response({
                    'code': 1,
                    'msg': '订单ID不能为空',
                    'data': None
                }, status=status.HTTP_400_BAD_REQUEST)

            # 2. 获取当前用户并验证权限
            current_user = request.user
            yonghuid = current_user.UserUID

            try:
                dashou_profile = current_user.DashouProfile
            except UserDashou.DoesNotExist:
                return Response({
                    'code': 2,
                    'msg': '用户不是打手身份',
                    'data': None
                }, status=status.HTTP_403_FORBIDDEN)

            # 3. 查询订单主表
            try:
                dingdan = Order.query.get(OrderID=dingdan_id)
            except Order.DoesNotExist:
                return Response({
                    'code': 3,
                    'msg': '订单不存在',
                    'data': None
                }, status=status.HTTP_404_NOT_FOUND)

            # 4. 验证：接单打手，或本单在队成员（含已分账结束仍在队）
            is_player = dingdan.PlayerID == yonghuid
            is_team_member = False
            if not is_player:
                try:
                    from orders.models import TeamMember
                    is_team_member = TeamMember.query.filter(
                        order_id=dingdan_id,
                        user_uid=yonghuid,
                        join_status=TeamMember.JOIN_ACTIVE,
                    ).exists()
                except Exception:
                    is_team_member = False
            if not is_player and not is_team_member:
                return Response({
                    'code': 4,
                    'msg': '没有权限查看此订单',
                    'data': None
                }, status=status.HTTP_403_FORBIDDEN)

            # 5. 构建基础订单数据（组队：组员看本人份额；交付图全员可见）
            from orders.services.team_recruit import get_team_role_for_user, ensure_team_leader_can_submit
            team_ctx = get_team_role_for_user(dingdan.OrderID, yonghuid)
            full_commission = float(dingdan.PlayerCommission) if dingdan.PlayerCommission else 0.0
            my_share = team_ctx.get('my_share')
            show_jine = full_commission
            if team_ctx.get('has_team') and not team_ctx.get('is_leader') and my_share is not None:
                show_jine = float(my_share)
            submit_deny = ensure_team_leader_can_submit(dingdan, yonghuid)
            can_submit = int(dingdan.Status or 0) == 2 and submit_deny is None
            can_modify = int(dingdan.Status or 0) in (4, 8) and submit_deny is None
            is_team_leader = (
                bool(team_ctx.get('is_leader'))
                if team_ctx.get('has_team')
                else (dingdan.PlayerID == yonghuid)
            )

            dingdan_data = {
                'dingdan_id': dingdan.OrderID,
                'zhuangtai': dingdan.Status,
                'jine': show_jine,
                'order_commission': full_commission,
                'my_share_amount': my_share if my_share is not None else full_commission,
                'is_team_leader': is_team_leader,
                'can_submit': bool(can_submit),
                'can_modify': bool(can_modify),
                'jieshao': dingdan.Description or '',
                'tupian': dingdan.ImageURL or '',
                'nicheng': dingdan.Nickname or '',
                'beizhu': dingdan.Remark or '',
                **datetime_aliases(dingdan.CreateTime),
                'tuikuan_liyou':dingdan.RefundReason or '',
                'dashou_liuyan': dingdan.PlayerRemark or '',
                'fuwudashou_id': dingdan.PlayerID or '',
                'fadanpingtai': dingdan.Platform or ''
            }
            try:
                from orders.models import RefundEvidenceImage
                dingdan_data['tuikuan_tupian'] = list(
                    RefundEvidenceImage.query.filter(OrderID=dingdan.OrderID)
                    .exclude(ImageURL__isnull=True)
                    .exclude(ImageURL='')
                    .values_list('ImageURL', flat=True)
                )
            except Exception:
                dingdan_data['tuikuan_tupian'] = []
            try:
                from jituan.services.order_deal import order_auto_settle_payload
                dingdan_data.update(order_auto_settle_payload(dingdan))
            except Exception:
                pass
            try:
                from orders.services.team_recruit import get_active_recruit, serialize_recruit_public
                from orders.models import TeamMember
                rec = get_active_recruit(dingdan.OrderID)
                if not rec:
                    from orders.models import TeamRecruit
                    rec = TeamRecruit.query.filter(order_id=dingdan.OrderID).order_by('-id').first()
                if rec:
                    is_mem = TeamMember.query.filter(
                        recruit_id=rec.id, user_uid=yonghuid, join_status=1,
                    ).exists() or rec.leader_uid == yonghuid
                    dingdan_data['team'] = serialize_recruit_public(
                        rec, dingdan, include_game_ids=is_mem,
                    )
                else:
                    dingdan_data['team'] = None
            except Exception:
                dingdan_data['team'] = None

            # 6. 订单交付图（组队全员可见，不按当前用户过滤）
            dashou_tupian_list = PlayerDeliveryImage.query.filter(
                OrderID=dingdan_id,
            ).order_by('CreateTime')

            jiaofu_tupian_urls = []
            for tupian_record in dashou_tupian_list:
                if tupian_record.ImageURL:
                    jiaofu_tupian_urls.append(tupian_record.ImageURL)

            dingdan_data['dashou_jiaofu'] = jiaofu_tupian_urls

            # 7. 查询商家扩展表信息
            shangjia_info = {}
            try:
                shangjia_kuozhan = dingdan.shangjia_kuozhan
                shangjia_info = {
                    'shangjia_id': shangjia_kuozhan.MerchantID or '',
                    'shangjia_nicheng': shangjia_kuozhan.MerchantNickname or '',
                    'shangjia_liuyan': shangjia_kuozhan.MerchantReview or '',
                    #'tuikuan_liyou':  '',
                    'chufa_liyou': shangjia_kuozhan.PenaltyReason or '',
                    'chufa_zhuangtai': shangjia_kuozhan.PenaltyApplyStatus or 0,
                    #'chufa_jieguo': shangjia_kuozhan.chufa_jieguo or '',
                    'bohui_liyou': shangjia_kuozhan.RejectReason or ''
                }
            except MerchantOrderExt.DoesNotExist:
                # 没有商家扩展信息，返回空值
                shangjia_info = {
                    'shangjia_id': '',
                    'shangjia_nicheng': '',
                    'shangjia_liuyan': '',
                    'tuikuan_liyou': '',
                    'chufa_liyou': '',
                    'chufa_zhuangtai': 0,
                    'chufa_jieguo': '',
                    'bohui_liyou': ''
                }

            # 8. 查询平台扩展表信息（如果有的话）
            pingtai_info = {}
            try:
                pingtai_kuozhan = dingdan.pingtai_kuozhan
                pingtai_info = {
                    'laoban_id': pingtai_kuozhan.BossID or '',
                    'laoban_pingjia': pingtai_kuozhan.BossReview or ''
                }
            except PlatformOrderExt.DoesNotExist:
                pingtai_info = {
                    'laoban_id': '',
                    'laoban_pingjia': ''
                }

            # 9. 合并所有数据
            response_data = {
                **dingdan_data,
                **shangjia_info,
                **pingtai_info
            }

            return Response({
                'code': 0,
                'msg': '成功',
                'data': response_data
            }, status=status.HTTP_200_OK)

        except Exception as e:
            logger.error(f"获取打手订单详情失败: {str(e)}", exc_info=True)

            return Response({
                'code': 5,
                'msg': '服务器内部错误',
                'data': None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)






class DashouHuoquLeixingView(APIView):
    """
    打手获取商品类型接口 - 抢单页面使用
    接口地址：POST /dingdan/dsqdhqddlx
    功能：返回所有正常的商品类型，已按排序权重排序

    返回格式（与前端原数据格式完全一致）:
    {
        "code": 200,
        "msg": "成功",
        "data": {
            "list": [
                {
                    "id": 1,
                    "jieshao": "王者荣耀",
                    "tupian_url": "leixing/wzry.jpg",
                    "yaoqiuleixing": null,
                    "huiyuan_id": null,
                    "yongjin": null,
                    "paixu": 100,
                    "shenhezhuangtai": 1
                },
                // ... 更多类型
            ]
        }
    }
    """

    # 🔴 使用JWT Token认证
    permission_classes = [IsAuthenticated]

    def post(self, request):
        """
        处理POST请求，返回商品类型列表

        请求参数：无特殊参数，只验证用户身份

        安全验证：
        1. JWT Token验证用户身份
        2. 只返回 shenhezhuangtai=1（正常状态）的类型
        3. 数据已排序：paixu降序 → id升序
        """
        try:
            logger.info(f"打手获取商品类型请求 - 用户ID: {request.user.UserUID}")

            from jituan.services.club_context import resolve_effective_club_id
            from jituan.services.club_shangpin_leixing import build_club_leixing_list_for_api

            club_id = resolve_effective_club_id(request, request.user)
            leixing_list = build_club_leixing_list_for_api(club_id)

            badge = {}
            try:
                from orders.services.dashou_badges import dashou_badge_fields, attach_pending_to_leixing_list
                badge = dashou_badge_fields(club_id, user=request.user)
                leixing_list = attach_pending_to_leixing_list(
                    leixing_list, badge.get('type_pending_counts'),
                )
            except Exception as e:
                logger.warning('dsqdhqddlx 角标附加失败: %s', e)

            logger.info(f"返回商品类型数据：{len(leixing_list)}条，俱乐部:{club_id} 用户: {request.user.UserUID}")

            # 🔴 返回成功响应
            # 注意：保持与前端原数据格式完全一致；角标为新增字段，不影响旧客户端
            return Response({
                "code": 200,
                "msg": "成功",
                "data": {
                    "list": leixing_list,  # 🔴 保持原字段名 "list"
                    **badge,
                }
            }, status=status.HTTP_200_OK)

        except Exception as e:
            # 🔴 异常处理
            logger.error(f"打手获取商品类型失败 - 用户ID: {request.user.UserUID}, 错误: {str(e)}", exc_info=True)

            return Response({
                "code": 500,
                "msg": f"服务器内部错误: {str(e)}",
                "data": None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)             









class DashouXiugaiView(APIView):
    """
    打手修改订单交付内容接口
    请求方式：POST
    请求路径：/dingdan/dsxiugaidd
    权限：需携带有效JWT Token，且用户为打手身份
    请求参数：
        dingdan_id      : 订单ID（必填）
        liuyan          : 新的留言内容（可选，最长50字）
        deleted_images  : 要删除的图片URL列表（数组，每个元素为完整COS URL）
        new_images      : 新增的图片URL列表（数组，每个元素为完整COS URL）
    返回：
        成功：{"code":0,"msg":"修改成功","data":null}
        失败：返回相应错误码和提示
    """
    permission_classes = [IsAuthenticated]

    def post(self, request):
        # 获取请求数据
        data = request.data
        dingdan_id = str(data.get('OrderID') or data.get('dingdan_id') or '').strip()
        liuyan = data.get('liuyan', '')
        deleted_images = data.get('deleted_images', [])
        new_images = data.get('new_images', [])

        # ---------- 参数校验 ----------
        if not dingdan_id:
            return Response({'code': 1, 'msg': '订单ID不能为空', 'data': None},
                            status=status.HTTP_400_BAD_REQUEST)

        if not isinstance(deleted_images, list):
            return Response({'code': 2, 'msg': 'deleted_images 必须为数组', 'data': None},
                            status=status.HTTP_400_BAD_REQUEST)

        if not isinstance(new_images, list):
            return Response({'code': 3, 'msg': 'new_images 必须为数组', 'data': None},
                            status=status.HTTP_400_BAD_REQUEST)

        if liuyan and len(liuyan) > 50:
            return Response({'code': 4, 'msg': '留言最多50个字', 'data': None},
                            status=status.HTTP_400_BAD_REQUEST)

        # ---------- 用户身份验证 ----------
        current_user = request.user
        yonghuid = current_user.UserUID

        # 检查是否为打手
        try:
            dashou_profile = current_user.DashouProfile  # User 模型反向 related_name='DashouProfile'
        except UserDashou.DoesNotExist:
            return Response({'code': 5, 'msg': '用户不是打手身份', 'data': None},
                            status=status.HTTP_403_FORBIDDEN)

        # ---------- 订单查询及权限验证（组队仅队长） ----------
        try:
            dingdan = Order.query.get(OrderID=dingdan_id, Status__in=[4, 8])
        except Order.DoesNotExist:
            return Response({'code': 6, 'msg': '订单不存在或没有修改权限', 'data': None},
                            status=status.HTTP_403_FORBIDDEN)
        try:
            from orders.services.team_recruit import ensure_team_leader_can_submit
            deny = ensure_team_leader_can_submit(dingdan, yonghuid)
            if deny:
                return Response({'code': 6, 'msg': deny, 'data': None},
                                status=status.HTTP_403_FORBIDDEN)
        except Exception:
            if dingdan.PlayerID != yonghuid:
                return Response({'code': 6, 'msg': '订单不存在或没有修改权限', 'data': None},
                                status=status.HTTP_403_FORBIDDEN)

        owner_uid = dingdan.PlayerID or yonghuid

        # ---------- 执行修改（使用事务保证原子性） ----------
        try:
            with transaction.atomic():
                # 1. 处理删除的图片：从 Dashoutupian 表中删除记录
                if deleted_images:
                    delete_count, _ = PlayerDeliveryImage.query.filter(
                        OrderID=dingdan_id,
                        ImageURL__in=deleted_images
                    ).delete()
                    logger.info(f"订单 {dingdan_id} 删除图片 {delete_count} 张")

                # 2. 处理新增的图片：插入新记录
                if new_images:
                    # 批量创建
                    new_records = []
                    for url in new_images:
                        new_records.append(PlayerDeliveryImage(
                            OrderID=dingdan_id,
                            PlayerID=owner_uid,
                            ImageURL=url,
                            CreateTime=timezone.now()
                        ))
                    PlayerDeliveryImage.objects.bulk_create(new_records)
                    logger.info(f"订单 {dingdan_id} 新增图片 {len(new_records)} 张")

                # 3. 更新订单留言（如果发生变化）
                # 注意：即使留言为空字符串，也允许更新，表示清空留言
                if 'liuyan' in data:  # 判断是否传了liuyan字段（可能为空字符串）
                    dingdan.PlayerRemark = liuyan
                    dingdan.UpdateTime = timezone.now()
                    dingdan.save(update_fields=['PlayerRemark', 'UpdateTime'])

            # 全部成功，返回成功响应
            return Response({
                'code': 0,
                'msg': '修改成功',
                'data': None
            }, status=status.HTTP_200_OK)

        except Exception as e:
            logger.error(f"修改订单失败: {str(e)}", exc_info=True)
            return Response({
                'code': 7,
                'msg': '服务器内部错误',
                'data': None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)




