"""users.views.auth - auto-generated by split script."""
import os
import sys
import json
import re
import time
import uuid
import random
import string
import requests
import hashlib
import traceback
import decimal
import jwt
import ipaddress
import xmltodict
from datetime import datetime, timedelta
from decimal import Decimal
import defusedxml.ElementTree as ET

from django.conf import settings
from django.db import models, transaction, IntegrityError, DatabaseError, connection
from django.db.models import Q, F, Sum, Count, Case, When, IntegerField, Prefetch
from django.core.cache import cache
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.core.exceptions import ObjectDoesNotExist
from django.shortcuts import get_object_or_404
from django.utils import timezone
from django.http import HttpResponse
from django.views import View
from django.views.decorators.csrf import csrf_exempt
from django.contrib.auth.hashers import make_password

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 MultiPartParser, FormParser, JSONParser
from rest_framework.throttling import AnonRateThrottle
from rest_framework_simplejwt.tokens import RefreshToken
from rest_framework_simplejwt.authentication import JWTAuthentication

from gvsdsdk.fluent import db, func, FQ

from utils.oss_utils import validate_image, upload_to_oss, delete_from_oss
from utils.money import yuan_to_fen
from utils.fadan_utils import check_fadan_qiangdan_eligible
from utils.invitationcode_utils import CreateInvitationCode, VerifyInvitationCode
from users.fadan_fenhong_utils import process_fadan_fenhong

from orders.utils import (
    update_daily_payout,
    settle_shangjia_order_guanshi_fenhong
)
from backend.utils import (
    update_dashou_daily_by_action, update_guanshi_daily_by_action,
    update_shangjia_daily, update_zuzhang_daily_by_action,
    verify_kefu_permission
)
from rank.utils import get_tag_fee, create_shenhe_jilu, validate_shenheguan

from ..models import (
    UserBoss, UserDashou, UserShangjia, UserGuanshi,
    UserZuzhang, UserKefu, AdminProfile, OfficialAccountUser,
    TixianAutoRecord, TixianShenheJilu, Tixianjilu, Xiugaijilu,
    RankingRecord
)
from users.business_models import User
from ..tixian_shenhe_services import (
    load_audit_meta_map, refund_balance, sync_audit_and_jilu_status,
    mark_transfer_success, release_collect_quota_for_record,
    close_audit_wechat_failed, query_wechat_transfer_bill,
    check_shijidaozhang_within_limit,
    check_dashou_trial_blocks_commission_withdraw,
    WX_STATE_FAIL, WX_STATE_SUCCESS, WX_STATE_WAIT, WX_STATE_CANCELING,
)
from ..tixian_shenhe_views import process_audit_collect

from orders.models import (
    Order, PlatformOrderExt, MerchantOrderExt, CommissionRate,
    PenaltyRecord, PenaltyEvidenceImage, RefundRecord, PlayerDeliveryImage,
    Penalty, PenaltyAppealImage
)
from products.models import (
    ShangpinLeixing, Huiyuan, Huiyuangoumai, Gsfenhong, Czjilu
)
from config.models import Qunpeizhi
from backend.models import MerchantDailyStats
from rank.models import (
    KaohePayTemp, Chenghao, ShenheJilu,
    KaoheCishuFeiyong, YonghuChenghao
)
from users.models import UserShenheguan
from products.utils import update_shangpin_daily_stat
from shop.utils import update_dianpu_daily_stat
from rank.utils import create_shenhe_jilu_from_temp

import logging

logger = logging.getLogger(__name__)

class WechatMiniProgramLoginView(APIView):
    """
    微信小程序登录接口
    """
    throttle_classes = [AnonRateThrottle]
    permission_classes = [AllowAny]

    def post(self, request):
        try:
            code = request.data.get('code', '').strip()
            if not code:
                return Response({'code': 1, 'msg': '微信授权码不能为空', 'data': None},
                                status=status.HTTP_400_BAD_REQUEST)

            # 获取微信openid和unionid（按俱乐部小程序配置）
            from jituan.services.club_resolver import wechat_jscode2session_for_request
            wechat_data = wechat_jscode2session_for_request(request, code)
            if not wechat_data or 'openid' not in wechat_data:
                error_msg = wechat_data.get('errmsg', '微信授权失败')
                return Response({'code': 2, 'msg': f'微信登录失败: {error_msg}', 'data': None},
                                status=status.HTTP_400_BAD_REQUEST)

            openid = wechat_data['openid']
            session_key = wechat_data.get('session_key', '')
            unionid = wechat_data.get('unionid', '')

            from jituan.services.club_resolver import resolve_club_id_for_wechat_request
            from jituan.services.club_user import ensure_user_club_id, resolve_or_create_wx_user

            club_id = resolve_club_id_for_wechat_request(request)
            kehuduan_ip = self.huoquKehuduanIP(request)

            with transaction.atomic():
                user_main, created = resolve_or_create_wx_user(
                    club_id, openid, self.shengchengYonghuID, unionid=unionid,
                )
                ensure_user_club_id(user_main, club_id)

                if unionid and unionid != (user_main.UnionID or ''):
                    user_main.UnionID = unionid

                user_main.IP = kehuduan_ip
                user_main.UserLastLoginDate = timezone.now()
                user_main.save()

                if created:
                    UserBoss.query.create(user=user_main, nickname='板板大人')
                    # 新用户默认分配消费者角色
                    from users.business_models import UserRole, Role
                    normal_role = Role.objects.filter(RoleName='消费者').first()
                    if normal_role:
                        UserRole.objects.create(
                            UserRoleUUID=uuid.uuid4().bytes,
                            UserUUID=user_main.UserUUID,
                            RoleUUID=normal_role.RoleUUID,
                            CompanyUUID=uuid.UUID('b0000000-0000-0000-0000-000000000001').bytes,
                        )

                # 检查扩展表
                dashou_status = 0
                shangjia_status = 0
                guanshi_status = 0
                boss_nickname = '微信用户'

                try:
                    boss_profile = UserBoss.query.get(user=user_main)
                    boss_nickname = boss_profile.nickname if boss_profile.nickname else '微信用户'
                except UserBoss.DoesNotExist:
                    pass

                try:
                    UserDashou.query.get(user=user_main)
                    dashou_status = 1
                except UserDashou.DoesNotExist:
                    dashou_status = None

                try:
                    UserShangjia.query.get(user=user_main)
                    shangjia_status = 1
                except UserShangjia.DoesNotExist:
                    shangjia_status = None

                try:
                    UserGuanshi.query.get(user=user_main)
                    guanshi_status = 1
                except UserGuanshi.DoesNotExist:
                    guanshi_status = None


                try:
                    UserZuzhang.query.get(user=user_main)
                    zuzhang_status = 1
                except UserZuzhang.DoesNotExist:
                    zuzhang_status = None    


                # 在检查 zuzhang 扩展表之后，插入以下代码
                try:
                    kg = UserShenheguan.query.get(user=user_main)
                    kaoheguan_status = 1 if kg.zhuangtai == 1 else 0
                except UserShenheguan.DoesNotExist:
                    kaoheguan_status = 0    

                # 生成JWT token
                refresh = RefreshToken.for_user(user_main)
                token = str(refresh.access_token)

                # 计算订单数量
                order_counts = self.jisuanOrderShuliang(user_main.UserUID)

                # 获取群配置
                group_info = self.huoquQunPeizhi()

            from merchant_ops.services.authz import staff_fields_for_login
            staff_fields = staff_fields_for_login(user_main)

            # 返回数据
            response_data = {
                'token': token,
                'nicheng': boss_nickname,
                'uid': user_main.UserUID,
                'touxiang': user_main.Avatar or '',
                'shangjiastatus': shangjia_status,
                'dashoustatus': dashou_status,
                'guanshistatus': guanshi_status,
                'zuzhangstatus': zuzhang_status,
                'kaoheguanstatus': kaoheguan_status,
                'dingdantiaoshu': order_counts,
                'dashouqun': group_info.get('dashouqun', ''),
                'dashouqunid': group_info.get('dashouqunid', ''),
                'guanshiqun': group_info.get('guanshiqun', ''),
                'guanshiqunid': group_info.get('guanshiqunid', ''),
                **staff_fields,
            }

            return Response({'code': 0, 'msg': '登录成功', 'data': response_data})

        except Exception as e:
            error_openid = locals().get('openid', 'N/A')
            logger.error(f"微信登录异常 - openid: {error_openid}, 错误类型: {type(e).__name__}, 错误详情: {str(e)}",
                         exc_info=True)

            return Response({'code': 99, 'msg': '系统繁忙，请稍后重试', 'data': None},
                            status=status.HTTP_500_INTERNAL_SERVER_ERROR)

    def get_wechat_openid(self, code):
        """
        调用微信接口获取openid和unionid
        """
        try:
            appid = getattr(settings, 'WEIXIN_APPID', '')
            secret = getattr(settings, 'WEIXIN_SECRET', '')

            if not appid or not secret:
                raise ValueError('微信配置未设置')

            url = 'https://api.weixin.qq.com/sns/jscode2session'
            params = {'appid': appid, 'secret': secret, 'js_code': code, 'grant_type': 'authorization_code'}

            response = requests.get(url, params=params, timeout=10)
            result = response.json()

            if 'openid' in result:
                return {'openid': result['openid'], 'session_key': result.get('session_key', ''),
                        'unionid': result.get('unionid', '')}
            else:
                errcode = result.get('errcode', 'unknown')
                errmsg = result.get('errmsg', '未知错误')
                return {'errmsg': f'[{errcode}]{errmsg}'}

        except requests.exceptions.Timeout:
            return {'errmsg': '请求微信接口超时'}
        except Exception as e:
            return {'errmsg': f'请求微信接口异常: {str(e)}'}

    def shengchengYonghuID(self):
        """
        生成7位数字用户ID
        """
        for _ in range(10):
            timestamp_part = str(int(time.time()))[-5:].zfill(5)
            random_part = str(random.randint(0, 99)).zfill(2)
            user_id = timestamp_part + random_part

            if len(user_id) == 7 and user_id.isdigit():
                if not User.query.filter(UserUID=user_id).exists():
                    return user_id

        raise Exception('生成用户ID失败')

    def huoquKehuduanIP(self, request):
        """
        获取客户端真实IP地址
        """
        x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
        if x_forwarded_for:
            ip = x_forwarded_for.split(',')[0].strip()
            if ip:
                return ip

        ip = request.META.get('REMOTE_ADDR', '')
        return ip if ip else '0.0.0.0'

    def jisuanOrderShuliang(self, yonghuid):
        """
        统计订单数量
        """
        try:
            if not PlatformOrderExt.query.filter(BossID=yonghuid).exists():
                return {'daifuwu': 0, 'fuwuzhong': 0, 'yiwancheng': 0, 'yituikuan': 0}

            dingdan_ids = PlatformOrderExt.query.filter(BossID=yonghuid).values_list('Order__id', flat=True)

            results = Order.query.filter(id__in=dingdan_ids).aggregate(
                daifuwu=Count(Case(When(Q(Status=1) | Q(Status=7), then=1), output_field=IntegerField())),
                fuwuzhong=Count(Case(When(Status=2, then=1), output_field=IntegerField())),
                yiwancheng=Count(Case(When(Status=3, then=1), output_field=IntegerField())),
                yituikuan=Count(Case(When(Status=5, then=1), output_field=IntegerField()))
            )

            return {
                'daifuwu': results['daifuwu'] or 0,
                'fuwuzhong': results['fuwuzhong'] or 0,
                'yiwancheng': results['yiwancheng'] or 0,
                'yituikuan': results['yituikuan'] or 0
            }

        except Exception:
            return {'daifuwu': 0, 'fuwuzhong': 0, 'yiwancheng': 0, 'yituikuan': 0}

    def huoquQunPeizhi(self):
        """
        获取群配置信息
        """
        try:
            qun_configs = Qunpeizhi.query.filter(id__in=[1, 2])

            result = {
                'dashouqun': '',
                'dashouqunid': '',
                'guanshiqun': '',
                'guanshiqunid': ''
            }

            for config in qun_configs:
                if config.id == 1:
                    result['dashouqun'] = config.GroupContent or ''
                    result['dashouqunid'] = config.GroupID or ''
                elif config.id == 2:
                    result['guanshiqun'] = config.GroupContent or ''
                    result['guanshiqunid'] = config.GroupID or ''

            return result

        except Exception:
            return {
                'dashouqun': '',
                'dashouqunid': '',
                'guanshiqun': '',
                'guanshiqunid': ''
            }


class WeixinOfficialCallbackView(APIView):
    """
    微信服务号回调接口
    处理用户关注、取消关注等事件
    核心：有关注事件就存，不管有没有UnionID
    """
    throttle_classes = []
    permission_classes = [AllowAny]
    authentication_classes = []

    def get(self, request):
        """验证服务器配置（微信官方要求）"""
        try:
            signature = request.GET.get('signature', '')
            timestamp = request.GET.get('timestamp', '')
            nonce = request.GET.get('nonce', '')
            echostr = request.GET.get('echostr', '')

            token = getattr(settings, 'WEIXIN_OFFICIAL_TOKEN', '')

            if not token:
                logger.error("服务号Token未配置")
                return HttpResponse('Token not configured', status=500)

            # 验证签名
            tmp_list = sorted([token, timestamp, nonce])
            tmp_str = ''.join(tmp_list)
            hash_str = hashlib.sha1(tmp_str.encode()).hexdigest()

            if hash_str == signature:
                return HttpResponse(echostr)
            else:
                logger.error(f"签名验证失败")
                return HttpResponse('Signature verification failed', status=403)

        except Exception as e:
            logger.error(f"验证服务器异常: {str(e)}")
            return HttpResponse('Internal Server Error', status=500)

    def post(self, request):
        """处理事件推送（关注、取关）"""
        try:
            xml_str = request.body.decode('utf-8')
            logger.info(f"收到服务号事件，原始数据（前200字符）: {xml_str[:200]}")

            root = ET.fromstring(xml_str)

            msg_type = root.find('MsgType').text
            from_user = root.find('FromUserName').text  # 服务号OpenID

            if msg_type == 'event':
                event = root.find('Event').text

                if event == 'subscribe':
                    return self.handle_subscribe_event(root, from_user)
                elif event == 'unsubscribe':
                    return self.handle_unsubscribe_event(root, from_user)
                else:
                    # 其他事件（如菜单点击）直接返回success
                    return HttpResponse('success')

            # 非事件消息也直接返回success
            return HttpResponse('success')

        except Exception as e:
            logger.error(f"处理服务号事件异常: {str(e)}", exc_info=True)
            # 即使异常也返回success，避免微信服务器重试
            return HttpResponse('success')

    def handle_subscribe_event(self, root, from_user):
        """处理用户关注事件 - 简化版：有就存，没有拉倒"""
        try:
            # 尝试获取UnionID（有就有，没有也没关系）
            unionid_elem = root.find('UnionId')
            unionid = unionid_elem.text if unionid_elem is not None else None

            logger.info(f"用户关注，OpenID: {from_user}, UnionID: {unionid}")

            # 核心逻辑：更新或创建记录
            obj, created = OfficialAccountUser.query.update_or_create(
                official_openid=from_user,
                defaults={
                    'unionid': unionid,
                    'is_subscribed': True,
                    'subscribe_time': timezone.now()
                }
            )

            action = "新建" if created else "更新"
            logger.info(f"{action}用户记录成功: OpenID={from_user}")

            # 回复欢迎消息（可选）
            return self.generate_text_response(root, "感谢关注星阙网络服务！平台有新订单时您会收到通知。")

        except Exception as e:
            logger.error(f"处理关注事件异常: {str(e)}", exc_info=True)
            # 依然返回success，不让微信重试
            return HttpResponse('success')

    def handle_unsubscribe_event(self, root, from_user):
        """处理用户取消关注事件 - 简化版：标记为未订阅"""
        try:
            updated_count = OfficialAccountUser.query.filter(
                official_openid=from_user
            ).update(is_subscribed=False)

            if updated_count > 0:
                logger.info(f"用户取消关注，已标记为未订阅: {from_user}")
            else:
                logger.info(f"用户取消关注，但记录不存在（无需处理）: {from_user}")

            return HttpResponse('success')

        except Exception as e:
            logger.error(f"处理取消关注事件异常: {str(e)}", exc_info=True)
            return HttpResponse('success')

    def generate_text_response(self, root, content):
        """生成文本消息响应"""
        try:
            to_user = root.find('ToUserName').text
            from_user = root.find('FromUserName').text
            response_xml = f"""<xml>
<ToUserName><![CDATA[{from_user}]]></ToUserName>
<FromUserName><![CDATA[{to_user}]]></FromUserName>
<CreateTime>{int(time.time())}</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[{content}]]></Content>
</xml>"""
            return HttpResponse(response_xml, content_type='application/xml')

        except Exception as e:
            logger.error(f"生成回复消息异常: {str(e)}")
            # 即使生成回复失败，也返回一个空的success
            return HttpResponse('success')


class DashouZhuceView(APIView):
    """
    打手注册接口 (通过管事邀请码)
    访问路径: /api/yonghu/dashouzhuce/
    请求方法: POST
    权限要求: JWT Token认证通过的用户
    请求体: { "inviteCode": "AbC123..." }
    """
    permission_classes = [IsAuthenticated]

    def post(self, request):
        from jituan.services.api_compat import legacy_miniapp_error

        # 1. 获取并验证邀请码参数（空则用俱乐部默认码）
        yaoqingma = (request.data.get('inviteCode') or '').strip()
        if not yaoqingma:
            from jituan.services.club_resolver import resolve_club_id_for_wechat_request
            from jituan.services.default_invite import get_club_default_dashou_invite
            yaoqingma = get_club_default_dashou_invite(resolve_club_id_for_wechat_request(request))
        if not yaoqingma:
            return legacy_miniapp_error(400, '邀请码不能为空')

        if len(yaoqingma) > 100:
            return legacy_miniapp_error(400, '邀请码长度超过限制')

        current_user = request.user
        # 注意：这里request.user是User实例

        # 2. 检查用户是否已是打手 (使用反向查询，性能最优)
        try:
            dashou_profile = current_user.DashouProfile
            # 用户已是打手，直接返回现有信息
            return self.fanhuiXianyouDashouXinxi(dashou_profile, current_user)
        except UserDashou.DoesNotExist:
            # 用户不是打手，继续注册流程
            pass

        # 3. 根据邀请码查找对应的管事
        try:
            # 使用select_related一次性获取管事及其关联的主表用户信息，性能最高
            guanshi_profile = UserGuanshi.query.select_related('user').get(yaoqingma=yaoqingma)
        except UserGuanshi.DoesNotExist:
            return legacy_miniapp_error(404, '邀请码无效或不存在')

        from jituan.services.invite_guard import assert_invite_same_club
        from jituan.services.club_resolver import resolve_club_id_for_wechat_request
        from jituan.services.club_user import ensure_user_club_id

        ok, msg = assert_invite_same_club(request, guanshi_profile.user, current_user)
        if not ok:
            logger.warning(
                'dashouzhuce 俱乐部校验失败 uid=%s club=%s msg=%s',
                current_user.UserUID, resolve_club_id_for_wechat_request(request), msg,
            )
            return legacy_miniapp_error(403, msg)

        club_id = resolve_club_id_for_wechat_request(request)

        # 4. 验证管事状态

        # 5. 核心：在数据库事务中创建用户的所有身份
        try:
            with transaction.atomic():
                # 获取管事的用户ID (yonghuid)
                guanshi_yonghuid = guanshi_profile.user.UserUID

                # 5.1 创建打手扩展表
                dashou_profile = UserDashou.query.create(
                    user=current_user,
                    nicheng='大手子',  # 默认昵称
                    chenghao='普通大手',  # 默认称号
                    yaoqingren=guanshi_yonghuid,  # 设置邀请人ID
                    # 其他字段全部使用模型定义的默认值
                )

                # 5.2 创建商家扩展表
                try:
                    boss_profile = current_user.BossProfile
                    if boss_profile.nickname:
                        boss_nickname = boss_profile.nickname
                except:
                    pass


                # 5.3 龙先生：同步开通管事，邀请人与打手邀请人相同
                from users.services.lxs_dashou_guanshi import ensure_lxs_guanshi_on_dashou_register
                ensure_lxs_guanshi_on_dashou_register(
                    current_user, guanshi_yonghuid, club_id,
                )

                # 5.4 更新主表的用户类型 (如果需要，可以设为'dashou'，或保持原逻辑)
                # current_user.UserType = 'dashou'  # 根据你的业务逻辑决定
                # current_user.save()

                # 5.5 更新原管事的邀请数量 (使用行锁防止并发问题)
                # 重新查询并锁定该行记录
                locked_guanshi = UserGuanshi.objects.select_for_update().get(pk=guanshi_profile.pk)
                locked_guanshi.yaogingshuliang += 1
                locked_guanshi.save()

                # ========== 新增：管事每日统计（邀请打手） ==========
                try:
                    update_guanshi_daily_by_action(
                        yonghuid=guanshi_yonghuid,
                        action=1,  # 1 = 邀请打手
                        amount=Decimal('0.00')
                    )
                    logger.info(f"管事每日统计更新成功（邀请打手）：管事{guanshi_yonghuid}")
                except Exception as e:
                    logger.error(f"管事每日统计更新失败（邀请打手）：{str(e)}")

        except Exception as e:

            # 事务会自动回滚
            logger.exception('dashouzhuce 注册异常 uid=%s', current_user.UserUID)
            return legacy_miniapp_error(500, f'注册过程中发生系统错误: {str(e)}')

        ensure_user_club_id(current_user, club_id)

        # 6. 注册成功，返回信息 (新注册用户没有会员记录，clumber返回空列表)
        fanhui_data = self.zhuangbeiFanhuiShuju(dashou_profile, current_user, is_new=True)
        if (club_id or '').strip() == 'lxs':
            ok_msg = '注册成功！已开通打手、管事身份。'
        else:
            ok_msg = '注册成功！'
        return Response({
            'code': 200,
            'message': ok_msg,
            'msg': ok_msg,
            'data': fanhui_data
        })

    def fanhuiXianyouDashouXinxi(self, dashou_profile, current_user):
        """处理已是打手的用户，返回其现有信息"""
        fanhui_data = self.zhuangbeiFanhuiShuju(dashou_profile, current_user, is_new=False)
        return Response({
            'code': 200,
            'message': '您已是打手，返回当前信息。',
            'data': fanhui_data
        })

    def zhuangbeiFanhuiShuju(self, dashou_profile, current_user, is_new=False):
        """准备返回给前端的打手数据，字段名严格匹配前端"""



        # 构建基础信息
        data = {
            'dashounicheng': dashou_profile.nicheng,
            'zhanghaostatus': dashou_profile.zhanghaozhuangtai,
            'yongjin': str(dashou_profile.yue),  # Decimal转字符串
            'zonge': str(dashou_profile.zonge),
            'yajin': str(dashou_profile.yajin),
            'chenghao': dashou_profile.chenghao,
            'jinfen': dashou_profile.jifen,
            'chengjiaoliang': dashou_profile.chengjiaozongliang,
            'zaixianzhuangtai': dashou_profile.zaixianzhuangtai,
            'dashouzhuangtai': dashou_profile.zhuangtai,
        }

        # 查询并处理会员列表 (clumber)
        from jituan.services.huiyuan_bundle import build_auth_clumber
        if is_new:
            huiyuan_goumai_list = []
        else:
            cid = getattr(current_user, 'ClubID', None) or None
            huiyuan_goumai_list = build_auth_clumber(current_user.UserUID, club_id=cid)

        data['clumber'] = huiyuan_goumai_list
        data['dashoustatus'] = 1
        data['guanshistatus'] = 1 if UserGuanshi.query.filter(user=current_user).exists() else 0
        data['shangjiastatus'] = 1 if UserShangjia.query.filter(user=current_user).exists() else 0
        return data


class GuanshiYaoqingDashouListView(APIView):
    """
    管事获取已邀请打手列表（支持筛选、搜索、分页）
    POST /api/yonghu/gshqyqds/
    Headers: Authorization: Bearer <token>
    Body:
    {
        "page": 1,                // 页码，从1开始
        "pageSize": 30,           // 每页条数，最大100
        "keyword": "",            // 搜索关键词（用户ID或昵称）
        "zhanghaozhuangtai": 1,  // 账号状态：1=正常，2=封禁（可选）
        "zaixianzhuangtai": 1    // 在线状态：1=在线，2=离线（可选）
    }
    """
    permission_classes = [IsAuthenticated]

    def post(self, request):
        try:
            current_user = request.user
            guanshi_yonghuid = current_user.UserUID

            # 1. 分页参数
            page = int(request.data.get('page', 1))
            page_size = int(request.data.get('pageSize', 30))
            if page < 1 or page_size < 1:
                return Response({'code': 400, 'message': '分页参数必须大于0'}, status=400)
            if page_size > 100:
                page_size = 100

            # 2. 筛选参数
            keyword = request.data.get('keyword', '').strip()
            zhanghaozhuangtai = request.data.get('zhanghaozhuangtai')  # 可选：1=正常，2=封禁
            zaixianzhuangtai = request.data.get('zaixianzhuangtai')    # 可选：1=在线，2=离线

            # 3. 基础查询：当前管事邀请的所有打手
            base_qs = UserDashou.query.select_related('user').filter(
                yaoqingren=guanshi_yonghuid
            )

            # 4. 全局统计（不受筛选影响，直接基于 base_qs）
            total_all = base_qs.count()
            zaixian_all = base_qs.filter(zaixianzhuangtai=1).count()
            zhengchang_all = base_qs.filter(zhanghaozhuangtai=1).count()
            fengjin_all = total_all - zhengchang_all

            # 5. 应用筛选条件
            if keyword:
                base_qs = base_qs.filter(
                    Q(nicheng__icontains=keyword) | Q(user__UserUID__icontains=keyword)
                )
            if zhanghaozhuangtai is not None:
                try:
                    val = int(zhanghaozhuangtai)
                    if val == 1:
                        base_qs = base_qs.filter(zhanghaozhuangtai=1)
                    else:
                        base_qs = base_qs.exclude(zhanghaozhuangtai=1)
                except (ValueError, TypeError):
                    pass
            if zaixianzhuangtai is not None:
                try:
                    val = int(zaixianzhuangtai)
                    if val == 1:
                        base_qs = base_qs.filter(zaixianzhuangtai=1)
                    else:
                        base_qs = base_qs.exclude(zaixianzhuangtai=1)
                except (ValueError, TypeError):
                    pass

            # 6. 排序和分页
            base_qs = base_qs.order_by('-CreateTime')
            paginator = Paginator(base_qs, page_size)
            try:
                page_obj = paginator.page(page)
            except EmptyPage:
                page_obj = []
                has_more = False
                filtered_total = paginator.count if paginator.count else 0
            else:
                has_more = page_obj.has_next()
                filtered_total = paginator.count

            # 7. 构建打手列表
            dashou_list = []
            for dashou in page_obj:
                user_main = dashou.user
                dashou_list.append({
                    'uid': user_main.UserUID,
                    'nicheng': dashou.nicheng or '打手',
                    'zaixianzhuangtai': dashou.zaixianzhuangtai,
                    'zhanghaozhuangtai': dashou.zhanghaozhuangtai,
                    'touxiang': user_main.Avatar or '',
                    'jiedanzongliang': dashou.jiedanzongliang,
                    'chengjiaozongliang': dashou.chengjiaozongliang,
                    'tuikuanliang': dashou.tuikuanliang,
                    'yue': str(dashou.zonge),
                })

            # 8. 获取管事邀请总数（来自管事扩展表）
            try:
                yaoqingzongshu = current_user.GuanshiProfile.yaogingshuliang
            except Exception:
                yaoqingzongshu = total_all

            response_data = {
                'dashouList': dashou_list,
                'yaoqingzongshu': yaoqingzongshu,      # 邀请总数（全局）
                'totalCount': filtered_total,           # 当前筛选条件下的总数
                'zaixianCount': zaixian_all,            # 全局在线
                'zhengchangCount': zhengchang_all,      # 全局正常
                'fengjinCount': fengjin_all,            # 全局封禁
                'currentPage': page,
                'pageSize': page_size,
                'hasMore': has_more,
            }

            return Response({'code': 200, 'message': '获取成功', 'data': response_data})

        except ValueError:
            return Response({'code': 400, 'message': '分页参数格式错误'}, status=400)
        except Exception as e:
            logger.error(f'获取打手列表失败: {str(e)}', exc_info=True)
            return Response({'code': 500, 'message': '系统错误'}, status=500)


class WechatLoginAndDashouRegisterView(APIView):
    """
    微信登录并注册打手一体化接口
    访问路径: /api/yonghu/wdlyhdl
    请求方法: POST
    权限要求: 无需登录
    请求体: { "code": "微信登录code", "inviteCode": "邀请码" }

    功能: 用户扫码进入但未登录时，一次性完成微信登录和打手注册
    """

    throttle_classes = [AnonRateThrottle]
    permission_classes = [AllowAny]

    def post(self, request):
        """
        处理微信登录并注册打手请求

        顺序：先按 openid 认身份；已是打手则直接登录（不校验邀请码）；
        仅新注册才要求邀请码（请求体 / 俱乐部默认码）。
        """
        try:
            from jituan.services.api_compat import legacy_miniapp_error

            # 1. 获取并验证参数（邀请码对新用户才强制）
            code = request.data.get('code', '').strip()
            yaoqingma = request.data.get('inviteCode', '').strip()

            if not code:
                return legacy_miniapp_error(1, '微信授权码不能为空')

            if yaoqingma and len(yaoqingma) > 100:
                return legacy_miniapp_error(3, '邀请码长度超过限制')

            # 2. 获取微信openid（按俱乐部小程序 appid，勿用全局星阙配置）
            from jituan.services.club_resolver import (
                resolve_club_id_for_wechat_request,
                wechat_jscode2session_for_request,
            )
            club_id = resolve_club_id_for_wechat_request(request)
            wechat_data = wechat_jscode2session_for_request(request, code)
            if not wechat_data or 'openid' not in wechat_data:
                error_msg = wechat_data.get('errmsg', '微信授权失败')
                logger.warning('wdlyhdl 微信登录失败 club=%s err=%s', club_id, error_msg)
                return legacy_miniapp_error(4, f'微信登录失败: {error_msg}')

            openid = wechat_data['openid']
            unionid = wechat_data.get('unionid', '')

            # 3. 获取客户端真实IP
            kehuduan_ip = self.huoquKehuduanIP(request)

            from jituan.services.club_user import (
                ensure_user_club_id,
                resolve_or_create_wx_user,
            )
            from jituan.services.default_invite import get_club_default_dashou_invite

            # 4. 开始数据库事务（确保登录和注册的原子性）
            with transaction.atomic():
                user_main, created = resolve_or_create_wx_user(
                    club_id, openid, self.shengchengYonghuID, unionid=unionid,
                )
                if created:
                    UserBoss.query.create(user=user_main, nickname='微信用户')

                # 更新用户IP和最后登录时间
                cunchu_ip = kehuduan_ip
                user_main.IP = cunchu_ip
                user_main.UserLastLoginDate = timezone.now()
                if unionid and unionid != (user_main.UnionID or ''):
                    user_main.UnionID = unionid
                user_main.save()

                ensure_user_club_id(user_main, club_id)

                # 4.1 已是打手：直接登录，不校验邀请码
                dashou_exists = UserDashou.query.filter(user=user_main).exists()
                if dashou_exists:
                    dashou_profile = UserDashou.query.get(user=user_main)
                    if int(getattr(dashou_profile, 'zhanghaozhuangtai', 1) or 0) != 1:
                        reason = (getattr(dashou_profile, 'fengjin_yuanyin', '') or '').strip()
                        msg = '账号状态异常，您的账号已被封禁'
                        if reason:
                            msg = f'{msg}。原因：{reason}'
                        else:
                            msg = f'{msg}，请联系客服'
                        return legacy_miniapp_error(4031, msg)
                    return self.fanhuiDengluZhuceshuju(user_main, dashou_profile)

                # 4.2 新用户注册：邀请码优先用请求体，否则用俱乐部默认码
                if not yaoqingma:
                    yaoqingma = get_club_default_dashou_invite(club_id)
                if not yaoqingma:
                    return legacy_miniapp_error(2, '邀请码不能为空')

                try:
                    guanshi_profile = UserGuanshi.query.select_related('user').get(yaoqingma=yaoqingma)
                except UserGuanshi.DoesNotExist:
                    return legacy_miniapp_error(404, '邀请码无效或不存在')

                from jituan.services.invite_guard import assert_invite_same_club
                from jituan.services.club_user import resolve_invite_party_club

                ok, invite_msg = assert_invite_same_club(
                    request, guanshi_profile.user, user_main,
                )
                if not ok:
                    logger.warning(
                        'wdlyhdl 俱乐部校验失败 uid=%s club=%s invitee_club=%s inviter_club=%s msg=%s invite=%s',
                        user_main.UserUID, club_id,
                        resolve_invite_party_club(user_main, club_id),
                        resolve_invite_party_club(guanshi_profile.user, club_id),
                        invite_msg, yaoqingma[:8],
                    )
                    return legacy_miniapp_error(403, invite_msg)

                # 4.3 创建打手身份
                guanshi_yonghuid = guanshi_profile.user.UserUID

                # 创建打手扩展表
                dashou_profile = UserDashou.query.create(
                    user=user_main,
                    nicheng='大神',
                    chenghao='普通大神',
                    yaoqingren=guanshi_yonghuid,
                    # 其他字段使用模型默认值
                )

                # 创建商家扩展表

                # 龙先生：同步开通管事，邀请人与打手邀请人相同
                from users.services.lxs_dashou_guanshi import ensure_lxs_guanshi_on_dashou_register
                ensure_lxs_guanshi_on_dashou_register(
                    user_main, guanshi_yonghuid, club_id,
                )

                # 更新原管事的邀请数量
                locked_guanshi = UserGuanshi.objects.select_for_update().get(pk=guanshi_profile.pk)
                locked_guanshi.yaogingshuliang += 1
                locked_guanshi.save()

                # ========== 新增：管事每日统计（邀请打手） ==========
                try:
                    update_guanshi_daily_by_action(
                        yonghuid=guanshi_yonghuid,
                        action=1,  # 1 = 邀请打手
                        amount=Decimal('0.00')
                    )
                    logger.info(f"管事每日统计更新成功（邀请打手）：管事{guanshi_yonghuid}")
                except Exception as e:
                    logger.error(f"管事每日统计更新失败（邀请打手）：{str(e)}")

                # 5. 生成JWT token
                refresh = RefreshToken.for_user(user_main)
                token = str(refresh.access_token)

                # 6. 准备返回数据
                response_data = self.zhuangbeiFanhuiShuju(user_main, dashou_profile, token)

                if (club_id or '').strip() == 'lxs':
                    ok_msg = '登录并注册成功！已开通打手、管事等身份。'
                else:
                    ok_msg = '登录并注册成功！'
                return Response({
                    'code': 0,
                    'msg': ok_msg,
                    'data': response_data
                })

        except Exception as e:
            # 记录错误日志
            error_openid = locals().get('openid', 'N/A')
            logger.error(
                f"微信登录注册一体化接口异常 - openid: {error_openid}, "
                f"错误类型: {type(e).__name__}, 错误详情: {str(e)}",
                exc_info=True
            )

            # 返回友好错误信息（HTTP 200 以便老端读出 msg）
            from jituan.services.api_compat import legacy_miniapp_error
            return legacy_miniapp_error(99, '系统繁忙，请稍后重试')

    def get_wechat_openid(self, code):
        """
        调用微信接口获取openid
        """
        try:
            appid = getattr(settings, 'WEIXIN_APPID', '')
            secret = getattr(settings, 'WEIXIN_SECRET', '')

            if not appid or not secret:
                raise ValueError('微信配置未设置')

            url = 'https://api.weixin.qq.com/sns/jscode2session'
            params = {
                'appid': appid,
                'secret': secret,
                'js_code': code,
                'grant_type': 'authorization_code'
            }

            response = requests.get(url, params=params, timeout=10)
            result = response.json()

            if 'openid' in result:
                return result
            else:
                errcode = result.get('errcode', 'unknown')
                errmsg = result.get('errmsg', '未知错误')
                return {'errmsg': f'[{errcode}]{errmsg}'}

        except requests.exceptions.Timeout:
            return {'errmsg': '请求微信接口超时'}
        except Exception as e:
            return {'errmsg': f'请求微信接口异常: {str(e)}'}

    def shengchengYonghuID(self):
        """
        生成7位数字用户ID
        """
        for _ in range(10):
            timestamp_part = str(int(time.time()))[-5:].zfill(5)
            random_part = str(random.randint(0, 99)).zfill(2)
            user_id = timestamp_part + random_part

            if len(user_id) == 7 and user_id.isdigit():
                if not User.query.filter(UserUID=user_id).exists():
                    return user_id

        raise Exception('生成用户ID失败')

    def huoquKehuduanIP(self, request):
        """
        获取客户端真实IP地址
        """
        x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
        if x_forwarded_for:
            ip = x_forwarded_for.split(',')[0].strip()
            if ip:
                return ip

        ip = request.META.get('REMOTE_ADDR', '')
        return ip if ip else '0.0.0.0'

    def huoquQunPeizhi(self):
        """
        获取群配置信息
        """
        try:
            qun_configs = Qunpeizhi.query.filter(id__in=[1, 2])

            result = {
                'dashouqun': '',
                'dashouqunid': '',
                'guanshiqun': '',
                'guanshiqunid': ''
            }

            for config in qun_configs:
                if config.id == 1:
                    result['dashouqun'] = config.GroupContent or ''
                    result['dashouqunid'] = config.GroupID or ''
                elif config.id == 2:
                    result['guanshiqun'] = config.GroupContent or ''
                    result['guanshiqunid'] = config.GroupID or ''

            return result

        except Exception:
            return {
                'dashouqun': '',
                'dashouqunid': '',
                'guanshiqun': '',
                'guanshiqunid': ''
            }

    def fanhuiZhihouDengluXinxi(self, user_main, yaoqingma_wuxiao=False, guanshi_jinyong=False):
        """
        返回只登录成功的信息（当邀请码无效或管事禁用时）
        """
        # 获取老板昵称
        boss_nickname = '微信用户'
        try:
            boss_profile = UserBoss.query.get(user=user_main)
            if boss_profile.nickname:
                boss_nickname = boss_profile.nickname
        except UserBoss.DoesNotExist:
            pass

        # 检查各身份状态
        dashou_status = 1 if UserDashou.query.filter(user=user_main).exists() else 0
        shangjia_status = 1 if UserShangjia.query.filter(user=user_main).exists() else 0
        guanshi_status = 1 if UserGuanshi.query.filter(user=user_main).exists() else 0

        # 生成token
        refresh = RefreshToken.for_user(user_main)
        token = str(refresh.access_token)

        # 获取群配置
        group_info = self.huoquQunPeizhi()

        # 构建返回数据
        response_data = {
            'token': token,
            'nicheng': boss_nickname,
            'uid': user_main.UserUID,
            'touxiang': user_main.Avatar or '',
            'shangjiastatus': shangjia_status,
            'dashoustatus': dashou_status,
            'guanshistatus': guanshi_status,
            # 🟢 注意：这里没有返回dingdantiaoshu（订单数量），与前端需求一致
            'dashouqun': group_info.get('dashouqun', ''),
            'dashouqunid': group_info.get('dashouqunid', ''),
            'guanshiqun': group_info.get('guanshiqun', ''),
            'guanshiqunid': group_info.get('guanshiqunid', '')
        }

        # 根据情况设置返回消息
        if yaoqingma_wuxiao:
            msg = '登录成功，但邀请码无效'
        elif guanshi_jinyong:
            msg = '登录成功，但邀请码对应的管事账号已被禁用'
        else:
            msg = '登录成功'

        return Response({
            'code': 0,
            'msg': msg,
            'data': response_data
        })

    def fanhuiDengluZhuceshuju(self, user_main, dashou_profile):
        """
        返回登录并注册的数据（用户已是打手的情况）
        """
        # 获取老板昵称
        boss_nickname = '微信用户'
        try:
            boss_profile = UserBoss.query.get(user=user_main)
            if boss_profile.nickname:
                boss_nickname = boss_profile.nickname
        except UserBoss.DoesNotExist:
            pass

        # 检查各身份状态（已是打手 ≠ 已是商家/管事/组长，必须按表真实查询）
        dashou_status = 1
        shangjia_status = 1 if UserShangjia.query.filter(user=user_main).exists() else 0
        guanshi_status = 1 if UserGuanshi.query.filter(user=user_main).exists() else 0
        zuzhang_status = 0
        try:
            zz = UserZuzhang.query.filter(user=user_main).first()
            zuzhang_status = 1 if zz and int(getattr(zz, 'zhuangtai', 0) or 0) == 1 else 0
        except Exception:
            zuzhang_status = 0

        # 生成token
        refresh = RefreshToken.for_user(user_main)
        token = str(refresh.access_token)

        # 获取群配置
        group_info = self.huoquQunPeizhi()

        # 准备打手信息
        dashou_data = self.zhuangbeiDashouFanhuiShuju(dashou_profile)

        # 合并所有数据
        response_data = {
            'token': token,
            'nicheng': boss_nickname,
            'uid': user_main.UserUID,
            'touxiang': user_main.Avatar or '',
            'shangjiastatus': shangjia_status,
            'dashoustatus': dashou_status,
            'guanshistatus': guanshi_status,
            'zuzhangstatus': zuzhang_status,
            'dashouqun': group_info.get('dashouqun', ''),
            'dashouqunid': group_info.get('dashouqunid', ''),
            'guanshiqun': group_info.get('guanshiqun', ''),
            'guanshiqunid': group_info.get('guanshiqunid', ''),
            # 合并打手信息
            **dashou_data
        }

        return Response({
            'code': 0,
            'msg': '您已是打手，登录成功',
            'data': response_data
        })

    def zhuangbeiFanhuiShuju(self, user_main, dashou_profile, token):
        """
        准备完整的返回数据（登录+注册成功的情况）
        """
        # 获取老板昵称
        boss_nickname = '微信用户'
        try:
            boss_profile = UserBoss.query.get(user=user_main)
            if boss_profile.nickname:
                boss_nickname = boss_profile.nickname
        except UserBoss.DoesNotExist:
            pass

        # 刚注册成功：仅打手为1；商家/管事按真实身份
        dashou_status = 1
        shangjia_status = 1 if UserShangjia.query.filter(user=user_main).exists() else 0
        guanshi_status = 1 if UserGuanshi.query.filter(user=user_main).exists() else 0

        # 获取群配置
        group_info = self.huoquQunPeizhi()

        # 准备打手信息
        dashou_data = self.zhuangbeiDashouFanhuiShuju(dashou_profile)

        # 合并所有数据
        response_data = {
            'token': token,
            'nicheng': boss_nickname,
            'uid': user_main.UserUID,
            'touxiang': user_main.Avatar or '',
            'shangjiastatus': shangjia_status,
            'dashoustatus': dashou_status,
            'guanshistatus': guanshi_status,
            'club_id': getattr(user_main, 'ClubID', None) or '',
            'dashouqun': group_info.get('dashouqun', ''),
            'dashouqunid': group_info.get('dashouqunid', ''),
            'guanshiqun': group_info.get('guanshiqun', ''),
            'guanshiqunid': group_info.get('guanshiqunid', ''),
            # 合并打手信息
            **dashou_data
        }

        return response_data

    def zhuangbeiDashouFanhuiShuju(self, dashou_profile):
        """
        准备打手返回数据（字段名严格匹配前端）
        """
        # 构建基础信息
        data = {
            'dashounicheng': dashou_profile.nicheng,
            'zhanghaostatus': dashou_profile.zhanghaozhuangtai,
            'yongjin': str(dashou_profile.yue),  # Decimal转字符串
            'zonge': str(dashou_profile.zonge),
            'yajin': str(dashou_profile.yajin),
            'chenghao': dashou_profile.chenghao,
            'jinfen': dashou_profile.jifen,
            'chengjiaoliang': dashou_profile.chengjiaozongliang,
            'zaixianzhuangtai': dashou_profile.zaixianzhuangtai,
            'dashouzhuangtai': dashou_profile.zhuangtai,
        }

        # 查询并处理会员列表 (clumber)
        from jituan.services.huiyuan_bundle import build_auth_clumber
        cid = getattr(dashou_profile.user, 'ClubID', None) or None
        huiyuan_goumai_list = build_auth_clumber(dashou_profile.user.UserUID, club_id=cid)

        data['clumber'] = huiyuan_goumai_list
        return data


class WechatLoginAndGuanshiRegisterView(APIView):
    """
    未登录用户微信登录+管事注册一体化接口
    路径: /api/yonghu/zuzhangyqmzc
    方法: POST
    权限: 允许所有
    请求体: { "code": "微信登录code", "inviteCode": "组长邀请码" }
    成功返回 code: 200，数据同 GuanshiRegisterView
    """
    permission_classes = [AllowAny]

    def post(self, request):
        code = request.data.get('code', '').strip()
        yaoqingma = request.data.get('inviteCode', '').strip()

        if not code:
            return Response({'code': 400, 'msg': '微信授权码不能为空', 'data': None},
                            status=status.HTTP_400_BAD_REQUEST)

        if not yaoqingma:
            return Response({'code': 400, 'msg': '邀请码不能为空', 'data': None},
                            status=status.HTTP_400_BAD_REQUEST)

        if len(yaoqingma) > 100:
            return Response({'code': 400, 'msg': '邀请码长度超过限制', 'data': None},
                            status=status.HTTP_400_BAD_REQUEST)

        from jituan.services.club_resolver import wechat_jscode2session_for_request
        wechat_data = wechat_jscode2session_for_request(request, code)
        if not wechat_data or 'openid' not in wechat_data:
            error_msg = wechat_data.get('errmsg', '微信授权失败')
            return Response({'code': 400, 'msg': f'微信登录失败: {error_msg}', 'data': None},
                            status=status.HTTP_400_BAD_REQUEST)

        openid = wechat_data['openid']
        kehuduan_ip = self._huoqu_kehuduan_ip(request)

        from jituan.services.club_resolver import resolve_club_id_for_wechat_request
        from jituan.services.club_user import ensure_user_club_id, resolve_or_create_wx_user

        club_id = resolve_club_id_for_wechat_request(request)

        with transaction.atomic():
            user_main, created = resolve_or_create_wx_user(
                club_id, openid, self._shengcheng_yonghu_id,
            )
            ensure_user_club_id(user_main, club_id)
            user_main.IP = kehuduan_ip
            user_main.UserLastLoginDate = timezone.now()
            user_main.save()

            if created:
                UserBoss.query.create(user=user_main, nickname='微信用户')

            if hasattr(user_main, 'GuanshiProfile'):
                return self._fanhui_xianyou_guanshi_info(user_main)

            try:
                zuzhang = UserZuzhang.query.select_related('user').get(yaoqingma=yaoqingma)
            except UserZuzhang.DoesNotExist:
                return Response({'code': 404, 'msg': '邀请码无效或不存在', 'data': None},
                                status=status.HTTP_404_NOT_FOUND)

            if zuzhang.zhuangtai != 1:
                return Response({'code': 403, 'msg': '该邀请码对应的组长账号已被禁用', 'data': None},
                                status=status.HTTP_403_FORBIDDEN)

            zuzhang_yonghuid = zuzhang.user.UserUID

            guanshi_yaoqingma = CreateInvitationCode(str(user_main.UserUID))
            guanshi_profile = UserGuanshi.query.create(
                user=user_main,
                yaoqingma=guanshi_yaoqingma,
                yaoqingren=zuzhang_yonghuid,
            )

            UserZuzhang.query.filter(pk=zuzhang.pk).update(
                yaoqing_zongshu=models.F('yaoqing_zongshu') + 1
            )

            # ========== 新增：组长每日统计（邀请管事 action=1） ==========
            try:
                update_zuzhang_daily_by_action(
                    yonghuid=zuzhang_yonghuid,
                    action=1  # 1 = 邀请管事
                )
                logger.info(f"组长每日统计更新成功（邀请管事）：组长{zuzhang_yonghuid}")
            except Exception as e:
                logger.error(f"组长每日统计更新失败（邀请管事）：{str(e)}")
                

            if not hasattr(user_main, 'DashouProfile'):
                dashou_profile = UserDashou.query.create(
                    user=user_main,
                    nicheng='大神',
                    chenghao='普通大神',
                    yaoqingren=zuzhang_yonghuid,
                )
            else:
                dashou_profile = user_main.DashouProfile

        refresh = RefreshToken.for_user(user_main)
        token = str(refresh.access_token)

        response_data = self._zhuangbei_fanhui_shuju(
            user_main, dashou_profile, guanshi_profile, token
        )

        return Response({'code': 0, 'msg': '登录并注册成功！', 'data': response_data})

    # ---------- 辅助方法（与接口1完全相同，完整列出以保证完整性） ----------

    def _get_wechat_openid(self, code):
        try:
            appid = getattr(settings, 'WEIXIN_APPID', '')
            secret = getattr(settings, 'WEIXIN_SECRET', '')
            if not appid or not secret:
                raise ValueError('微信配置未设置')
            url = 'https://api.weixin.qq.com/sns/jscode2session'
            params = {
                'appid': appid,
                'secret': secret,
                'js_code': code,
                'grant_type': 'authorization_code'
            }
            response = requests.get(url, params=params, timeout=10)
            result = response.json()
            if 'openid' in result:
                return result
            else:
                errcode = result.get('errcode', 'unknown')
                errmsg = result.get('errmsg', '未知错误')
                return {'errmsg': f'[{errcode}]{errmsg}'}
        except requests.exceptions.Timeout:
            logger.error('请求微信接口超时')
            return {'errmsg': '请求微信接口超时'}
        except Exception as e:
            logger.error(f'请求微信接口异常: {e}')
            return {'errmsg': f'请求微信接口异常: {str(e)}'}

    def _shengcheng_yonghu_id(self):
        for _ in range(10):
            timestamp_part = str(int(time.time()))[-5:].zfill(5)
            random_part = str(random.randint(0, 99)).zfill(2)
            user_id = timestamp_part + random_part
            if len(user_id) == 7 and user_id.isdigit():
                if not User.query.filter(UserUID=user_id).exists():
                    return user_id
        raise Exception('生成用户ID失败')

    def _huoqu_kehuduan_ip(self, request):
        x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
        if x_forwarded_for:
            ip = x_forwarded_for.split(',')[0].strip()
            if ip:
                return ip
        ip = request.META.get('REMOTE_ADDR', '')
        return ip if ip else '0.0.0.0'

    def _huoqu_qun_peizhi(self):
        try:
            qun_configs = Qunpeizhi.query.filter(id__in=[1, 2])
            result = {
                'dashouqun': '',
                'dashouqunid': '',
                'guanshiqun': '',
                'guanshiqunid': ''
            }
            for config in qun_configs:
                if config.id == 1:
                    result['dashouqun'] = config.GroupContent or ''
                    result['dashouqunid'] = config.GroupID or ''
                elif config.id == 2:
                    result['guanshiqun'] = config.GroupContent or ''
                    result['guanshiqunid'] = config.GroupID or ''
            return result
        except Exception as e:
            logger.error(f"获取群配置失败: {e}")
            return {'dashouqun': '', 'dashouqunid': '', 'guanshiqun': '', 'guanshiqunid': ''}

    def _zhuangbei_dashou_fanhui(self, dashou_profile):
        data = {
            'dashounicheng': dashou_profile.nicheng,
            'zhanghaostatus': dashou_profile.zhanghaozhuangtai,
            'yongjin': str(dashou_profile.yue),
            'zonge': str(dashou_profile.zonge),
            'yajin': str(dashou_profile.yajin),
            'chenghao': dashou_profile.chenghao,
            'jinfen': dashou_profile.jifen,
            'chengjiaoliang': dashou_profile.chengjiaozongliang,
            'zaixianzhuangtai': dashou_profile.zaixianzhuangtai,
            'dashouzhuangtai': dashou_profile.zhuangtai,
        }
        from jituan.services.huiyuan_bundle import build_auth_clumber
        try:
            cid = getattr(dashou_profile.user, 'ClubID', None) or None
            huiyuan_list = build_auth_clumber(dashou_profile.user.UserUID, club_id=cid)
        except Exception as e:
            logger.warning(f"获取会员列表失败: {e}")
            huiyuan_list = []
        data['clumber'] = huiyuan_list
        return data

    def _fanhui_xianyou_guanshi_info(self, user_main):
        guanshi_profile = user_main.GuanshiProfile
        dashou_profile = getattr(user_main, 'DashouProfile', None)
        group_info = self._huoqu_qun_peizhi()
        dashou_status = 1 if dashou_profile else 0
        shangjia_status = 1 if hasattr(user_main, 'ShopProfile') else 0
        guanshi_status = 1
        try:
            nicheng = user_main.BossProfile.nickname or '微信用户'
        except:
            nicheng = '微信用户'
        refresh = RefreshToken.for_user(user_main)
        token = str(refresh.access_token)
        data = {
            'token': token,
            'nicheng': nicheng,
            'uid': user_main.UserUID,
            'touxiang': user_main.Avatar or '',
            'shangjiastatus': shangjia_status,
            'dashoustatus': dashou_status,
            'guanshistatus': guanshi_status,
            **group_info,
        }
        guanshi_data = {
            'gszhstatus': guanshi_profile.zhuangtai,
            'yaoqingzongshu': guanshi_profile.yaogingshuliang,
            'fenyongzonge': str(guanshi_profile.chongzhifenrun),
            'fenyongtixian': str(guanshi_profile.yue),
            'yichongzhiDashou': guanshi_profile.jinrichongzhi,
        }
        data.update(guanshi_data)
        if dashou_profile:
            dashou_data = self._zhuangbei_dashou_fanhui(dashou_profile)
            data.update(dashou_data)
        else:
            data.update({
                'dashounicheng': '',
                'zhanghaostatus': 0,
                'yongjin': '0.00',
                'zonge': '0.00',
                'yajin': '0.00',
                'chenghao': '',
                'jinfen': 0,
                'chengjiaoliang': 0,
                'zaixianzhuangtai': 0,
                'dashouzhuangtai': 0,
                'clumber': []
            })
        return Response({'code': 0, 'msg': '您已是管事', 'data': data})

    def _zhuangbei_fanhui_shuju(self, user_main, dashou_profile, guanshi_profile, token):
        try:
            nicheng = user_main.BossProfile.nickname or '微信用户'
        except:
            nicheng = '微信用户'
        dashou_status = 1
        shangjia_status = 1 if hasattr(user_main, 'ShopProfile') else 0
        guanshi_status = 1
        group_info = self._huoqu_qun_peizhi()
        data = {
            'token': token,
            'nicheng': nicheng,
            'uid': user_main.UserUID,
            'touxiang': user_main.Avatar or '',
            'shangjiastatus': shangjia_status,
            'dashoustatus': dashou_status,
            'guanshistatus': guanshi_status,
            **group_info,
        }
        guanshi_data = {
            'gszhstatus': guanshi_profile.zhuangtai,
            'yaoqingzongshu': guanshi_profile.yaogingshuliang,
            'fenyongzonge': str(guanshi_profile.chongzhifenrun),
            'fenyongtixian': str(guanshi_profile.yue),
            'yichongzhiDashou': guanshi_profile.jinrichongzhi,
        }
        data.update(guanshi_data)
        dashou_data = self._zhuangbei_dashou_fanhui(dashou_profile)
        data.update(dashou_data)
        return data


class GuanshiRegisterView(APIView):
    """
    已登录用户注册管事接口
    路径: /api/yonghu/guanshizhuce
    方法: POST
    权限: JWT认证
    请求体: { "inviteCode": "组长邀请码" }
    成功返回 code: 200
    """
    permission_classes = [IsAuthenticated]

    def post(self, request):
        # 1. 获取并验证邀请码
        yaoqingma = request.data.get('inviteCode', '').strip()
        if not yaoqingma:
            return Response({'code': 400, 'msg': '邀请码不能为空', 'data': None},
                            status=status.HTTP_400_BAD_REQUEST)

        if len(yaoqingma) > 100:
            return Response({'code': 400, 'msg': '邀请码长度超过限制', 'data': None},
                            status=status.HTTP_400_BAD_REQUEST)

        current_user = request.user

        # 2. 检查用户是否已是管事
        if hasattr(current_user, 'GuanshiProfile'):
            # 用户已是管事，直接返回现有信息
            return self._fanhui_xianyou_guanshi_info(current_user)

        # 3. 验证邀请码对应的组长
        try:
            zuzhang = UserZuzhang.query.select_related('user').get(yaoqingma=yaoqingma)
        except UserZuzhang.DoesNotExist:
            return Response({'code': 404, 'msg': '邀请码无效或不存在', 'data': None},
                            status=status.HTTP_404_NOT_FOUND)

        if zuzhang.zhuangtai != 1:
            return Response({'code': 403, 'msg': '该邀请码对应的组长账号已被禁用', 'data': None},
                            status=status.HTTP_403_FORBIDDEN)

        from jituan.services.invite_guard import assert_invite_same_club
        ok, invite_msg = assert_invite_same_club(request, zuzhang.user, current_user)
        if not ok:
            return Response({'code': 403, 'msg': invite_msg, 'data': None},
                            status=status.HTTP_403_FORBIDDEN)

        zuzhang_yonghuid = zuzhang.user.UserUID

        # 4. 事务内创建管事实体和打手（如果需要）
        with transaction.atomic():
            # 创建管事扩展表
            guanshi_yaoqingma = CreateInvitationCode(str(current_user.UserUID))
            guanshi_profile = UserGuanshi.query.create(
                user=current_user,
                yaoqingma=guanshi_yaoqingma,
                yaoqingren=zuzhang_yonghuid,
            )

            # 更新组长的邀请总数
            UserZuzhang.query.filter(pk=zuzhang.pk).update(
                yaoqing_zongshu=models.F('yaoqing_zongshu') + 1
            )

            # ========== 新增：组长每日统计（邀请管事 action=1） ==========
            try:
                update_zuzhang_daily_by_action(
                    yonghuid=zuzhang_yonghuid,
                    action=1  # 1 = 邀请管事
                )
                logger.info(f"组长每日统计更新成功（邀请管事）：组长{zuzhang_yonghuid}")
            except Exception as e:
                logger.error(f"组长每日统计更新失败（邀请管事）：{str(e)}")

            # 检查用户是否已是打手，如果不是则创建
            if not hasattr(current_user, 'DashouProfile'):
                dashou_profile = UserDashou.query.create(
                    user=current_user,
                    nicheng='大手子',
                    chenghao='普通大手',
                    yaoqingren=zuzhang_yonghuid,
                )
            else:
                dashou_profile = current_user.DashouProfile

        # 5. 生成新token
        refresh = RefreshToken.for_user(current_user)
        token = str(refresh.access_token)

        # 6. 准备返回数据（包含所有字段）
        response_data = self._zhuangbei_fanhui_shuju(
            current_user, dashou_profile, guanshi_profile, token
        )

        return Response({'code': 200, 'msg': '注册成功！', 'data': response_data})

    # ---------- 辅助方法 ----------

    def _huoqu_qun_peizhi(self):
        """获取群配置信息"""
        try:
            qun_configs = Qunpeizhi.query.filter(id__in=[1, 2])
            result = {
                'dashouqun': '',
                'dashouqunid': '',
                'guanshiqun': '',
                'guanshiqunid': ''
            }
            for config in qun_configs:
                if config.id == 1:
                    result['dashouqun'] = config.GroupContent or ''
                    result['dashouqunid'] = config.GroupID or ''
                elif config.id == 2:
                    result['guanshiqun'] = config.GroupContent or ''
                    result['guanshiqunid'] = config.GroupID or ''
            return result
        except Exception as e:
            logger.error(f"获取群配置失败: {e}")
            return {'dashouqun': '', 'dashouqunid': '', 'guanshiqun': '', 'guanshiqunid': ''}

    def _zhuangbei_dashou_fanhui(self, dashou_profile):
        """组装打手信息（字段名与前端完全匹配）"""
        data = {
            'dashounicheng': dashou_profile.nicheng,
            'zhanghaostatus': dashou_profile.zhanghaozhuangtai,
            'yongjin': str(dashou_profile.yue),
            'zonge': str(dashou_profile.zonge),
            'yajin': str(dashou_profile.yajin),
            'chenghao': dashou_profile.chenghao,
            'jinfen': dashou_profile.jifen,
            'chengjiaoliang': dashou_profile.chengjiaozongliang,
            'zaixianzhuangtai': dashou_profile.zaixianzhuangtai,
            'dashouzhuangtai': dashou_profile.zhuangtai,
        }

        # 会员列表
        from jituan.services.huiyuan_bundle import build_auth_clumber
        try:
            cid = getattr(dashou_profile.user, 'ClubID', None) or None
            huiyuan_list = build_auth_clumber(dashou_profile.user.UserUID, club_id=cid)
        except Exception as e:
            logger.warning(f"获取会员列表失败: {e}")
            huiyuan_list = []
        data['clumber'] = huiyuan_list
        return data

    def _fanhui_xianyou_guanshi_info(self, user_main):
        """用户已是管事时的返回"""
        guanshi_profile = user_main.GuanshiProfile
        dashou_profile = getattr(user_main, 'DashouProfile', None)

        group_info = self._huoqu_qun_peizhi()

        dashou_status = 1 if dashou_profile else 0
        shangjia_status = 1 if hasattr(user_main, 'ShopProfile') else 0
        guanshi_status = 1

        try:
            nicheng = user_main.BossProfile.nickname or '微信用户'
        except:
            nicheng = '微信用户'

        refresh = RefreshToken.for_user(user_main)
        token = str(refresh.access_token)

        data = {
            'token': token,
            'nicheng': nicheng,
            'uid': user_main.UserUID,
            'touxiang': user_main.Avatar or '',
            'shangjiastatus': shangjia_status,
            'dashoustatus': dashou_status,
            'guanshistatus': guanshi_status,
            **group_info,
        }

        # 管事信息
        guanshi_data = {
            'gszhstatus': guanshi_profile.zhuangtai,
            'yaoqingzongshu': guanshi_profile.yaogingshuliang,
            'fenyongzonge': str(guanshi_profile.chongzhifenrun),
            'fenyongtixian': str(guanshi_profile.yue),
            'yichongzhiDashou': guanshi_profile.jinrichongzhi,
        }
        data.update(guanshi_data)

        if dashou_profile:
            dashou_data = self._zhuangbei_dashou_fanhui(dashou_profile)
            data.update(dashou_data)
        else:
            data.update({
                'dashounicheng': '',
                'zhanghaostatus': 0,
                'yongjin': '0.00',
                'zonge': '0.00',
                'yajin': '0.00',
                'chenghao': '',
                'jinfen': 0,
                'chengjiaoliang': 0,
                'zaixianzhuangtai': 0,
                'dashouzhuangtai': 0,
                'clumber': []
            })

        return Response({'code': 200, 'msg': '您已是管事', 'data': data})

    def _zhuangbei_fanhui_shuju(self, user_main, dashou_profile, guanshi_profile, token):
        """组装完整返回数据（新注册）"""
        try:
            nicheng = user_main.BossProfile.nickname or '微信用户'
        except:
            nicheng = '微信用户'

        dashou_status = 1
        shangjia_status = 1 if hasattr(user_main, 'ShopProfile') else 0
        guanshi_status = 1

        group_info = self._huoqu_qun_peizhi()

        data = {
            'token': token,
            'nicheng': nicheng,
            'uid': user_main.UserUID,
            'touxiang': user_main.Avatar or '',
            'shangjiastatus': shangjia_status,
            'dashoustatus': dashou_status,
            'guanshistatus': guanshi_status,
            **group_info,
        }

        # 管事信息
        guanshi_data = {
            'gszhstatus': guanshi_profile.zhuangtai,
            'yaoqingzongshu': guanshi_profile.yaogingshuliang,
            'fenyongzonge': str(guanshi_profile.chongzhifenrun),
            'fenyongtixian': str(guanshi_profile.yue),
            'yichongzhiDashou': guanshi_profile.jinrichongzhi,
        }
        data.update(guanshi_data)

        dashou_data = self._zhuangbei_dashou_fanhui(dashou_profile)
        data.update(dashou_data)

        return data


class ZuzhangZhuceView(APIView):
    """
    组长注册/激活接口
    POST /yonghu/zuzhangzhuce
    请求体: {"inviteCode": "xxx"}
    返回:
        {
            "code": 200,
            "msg": "success",
            "data": {
                "ketixian": "0.00",        # 可提现金额
                "guanshiCount": 0,          # 邀请的管事数量
                "fenhongZonge": "0.00"      # 分红总额
            }
        }
    或错误码
    """

    permission_classes = [IsAuthenticated]

    # 硬编码激活码（注意转义特殊字符）
    ACTIVATION_CODE = "237huwehdw77e777eyw224fr"

    def post(self, request):
        user = request.user
        invite_code = request.data.get('inviteCode', '').strip()

        if not invite_code:
            return Response({'code': 400, 'msg': '邀请码不能为空'}, status=400)

        # 检查是否已是组长
        try:
            zuzhang = UserZuzhang.query.select_related('user').get(user=user)
            # 已注册，直接返回数据
            data = self._build_response_data(zuzhang, user)
            return Response({'code':200, 'msg': '已注册', 'data': data})
        except UserZuzhang.DoesNotExist:
            pass

        # 比对激活码
        if invite_code != self.ACTIVATION_CODE:
            return Response({'code': 400, 'msg': '邀请码无效'}, status=400)

        from jituan.services.club_user import ensure_user_club_id
        from jituan.services.club_context import resolve_club_id_from_request
        ensure_user_club_id(user, resolve_club_id_from_request(request))

        # 生成唯一组长邀请码：时间戳 + 用户ID后6位 + 随机字符
        yaoqingma = self._generate_unique_yaoqingma(user.UserUID)

        # 创建组长扩展记录
        try:
            with transaction.atomic():
                zuzhang = UserZuzhang.query.create(
                    user=user,
                    yaoqingma=yaoqingma,
                    fenyong_zonge=0.00,
                    ketixian_jine=0.00,
                    yaoqing_zongshu=0,
                    jinri_fenyong=0.00,
                    jinyue_fenyong=0.00,
                    zhuangtai=1,
                    jinri_tixian=0.00,
                    ewai_tixian_xiane=0.00,
                    kaioi_ewai_tixian=False,
                    kaioi_ewai_fenhong=False,
                    ewai_fenhong_jine=0.00
                )
        except IntegrityError:
            # 极低概率重复，重试一次
            yaoqingma = self._generate_unique_yaoqingma(user.UserUID, retry=True)
            zuzhang = UserZuzhang.query.create(
                user=user,
                yaoqingma=yaoqingma,
                # 其他字段默认同上
                fenyong_zonge=0.00,
                ketixian_jine=0.00,
                yaoqing_zongshu=0,
                jinri_fenyong=0.00,
                jinyue_fenyong=0.00,
                zhuangtai=1,
                jinri_tixian=0.00,
                ewai_tixian_xiane=0.00,
                kaioi_ewai_tixian=False,
                kaioi_ewai_fenhong=False,
                ewai_fenhong_jine=0.00
            )

        data = self._build_response_data(zuzhang, user)
        return Response({'code':200, 'msg': '注册成功', 'data': data})

    def _generate_unique_yaoqingma(self, yonghuid, retry=False):
        """生成唯一邀请码：时间戳+用户ID后6位+随机2位字符"""
        timestamp = str(int(time.time()))[-6:]  # 取后6位
        uid_part = yonghuid[-6:] if len(yonghuid) >= 6 else yonghuid.rjust(6, '0')
        rand_str = ''.join(random.choices(string.ascii_uppercase + string.digits, k=2))
        base = f"Z{timestamp}{uid_part}{rand_str}"
        # 确保唯一性（若已存在则追加随机数，最多尝试3次）
        for _ in range(3):
            if not UserZuzhang.query.filter(yaoqingma=base).exists():
                return base
            base = base + random.choice(string.digits)
        # 极端情况，再附加时间戳毫秒
        millis = str(time.time()).replace('.', '')[-4:]
        return base + millis

    def _build_response_data(self, zuzhang, user):
        """组装前端所需数据"""
        # 计算邀请的管事数量（通过UserGuanshi表的yaoqingren字段关联到user的yonghuid）
        guanshi_count = UserGuanshi.query.filter(yaoqingren=user.UserUID).count()
        return {
            'ketixian': str(zuzhang.ketixian_jine),      # 可提现余额
            'dongjie_yue': str(getattr(zuzhang, 'dongjie_yue', 0) or 0),
            'guanshiCount': guanshi_count,                # 邀请管事数
            'fenhongZonge': str(zuzhang.fenyong_zonge)    # 分红总额
        }


class ZuzhangXinxiView(APIView):
    """
    组长信息查询接口
    POST /yonghu/zuzhangxinxi
    请求体: 无
    返回: 同注册接口成功返回格式
    """

    permission_classes = [IsAuthenticated]

    def post(self, request):
        user = request.user
        try:
            zuzhang = UserZuzhang.query.get(user=user)
        except UserZuzhang.DoesNotExist:
            return Response({'code': 404, 'msg': '用户不是组长'}, status=404)

        guanshi_count = UserGuanshi.query.filter(yaoqingren=user.UserUID).count()
        data = {
            'ketixian': str(zuzhang.ketixian_jine),
            'dongjie_yue': str(getattr(zuzhang, 'dongjie_yue', 0) or 0),
            'guanshiCount': guanshi_count,
            'fenhongZonge': str(zuzhang.fenyong_zonge),
            'zhuangtai': zuzhang.zhuangtai,
            'zuzhangstatus': 1 if int(getattr(zuzhang, 'zhuangtai', 0) or 0) == 1 else 0,
            'fengjin_yuanyin': getattr(zuzhang, 'fengjin_yuanyin', '') or '',
        }
        return Response({'code': 200, 'msg': 'success', 'data': data})     
