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

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

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

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

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

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

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

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

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

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

# 序列化器
from ..serializers import PopupPageSerializer

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

class GetGuanliListView(APIView):
    """
    获取管事列表
    权限：4400a,4400b,4400c,4400d,4400e,4400f 任一
    POST /houtai/hthqgslb
    参数：
        username, keyword(可选), balance_op/balance_value, commission_op/commission_value,
        invite_count_op/invite_count_value, status, page, page_size
    返回：
        code:0, data: { list: [...], total }
    """
    permission_classes = []
    parser_classes = [JSONParser]

    def post(self, request):
        username = request.data.get('username', '').strip()
        if not username:
            return Response({'code': 401, 'msg': '缺少username'})

        # 权限校验（需要任一权限）
        kefu, permissions = verify_kefu_permission(request, username)
        if kefu is None:
            return permissions
        required_perms = {'4400a', '4400b', '4400c', '4400d', '4400e', '4400f'}
        if not any(p in permissions for p in required_perms):
            return Response({'code': 403, 'msg': '您没有权限查看管事列表'})

        # 分页参数
        try:
            page = int(request.data.get('page', 1))
            page_size = int(request.data.get('page_size', 20))
            if page < 1 or page_size < 1:
                raise ValueError
        except:
            return Response({'code': 400, 'msg': '分页参数错误'})

        # 筛选参数
        keyword = request.data.get('keyword', '').strip()
        balance_op = request.data.get('balance_op', '').strip().lower()
        balance_value = request.data.get('balance_value')
        commission_op = request.data.get('commission_op', '').strip().lower()
        commission_value = request.data.get('commission_value')
        invite_count_op = request.data.get('invite_count_op', '').strip().lower()
        invite_count_value = request.data.get('invite_count_value')
        status = request.data.get('status')

        # 构建查询：从 User 开始，关联 UserGuanshi 和 UserBoss（左连接获取昵称）
        qs = filter_user_qs_by_club(
            User.query.filter(
                GuanshiProfile__isnull=False  # 确保是管事
            ).select_related('GuanshiProfile').select_related('BossProfile'),
            request,
        )

        # 关键词搜索（用户ID 或 昵称来自 boss_profile.nickname）
        if keyword:
            qs = qs.filter(
                Q(UserUID__icontains=keyword) |
                Q(BossProfile__nickname__icontains=keyword)
            )

        # 余额筛选（使用 guanshi_profile.yue）
        if balance_op and balance_value is not None and balance_value != '':
            try:
                balance_val = Decimal(str(balance_value))
                if balance_op == 'gte':
                    qs = qs.filter(GuanshiProfile__yue__gte=balance_val)
                elif balance_op == 'lte':
                    qs = qs.filter(GuanshiProfile__yue__lte=balance_val)
                else:
                    return Response({'code': 400, 'msg': '余额比较符无效'})
            except:
                return Response({'code': 400, 'msg': '余额数值格式错误'})

        # 分佣总额筛选（guanshi_profile.chongzhifenrun）
        if commission_op and commission_value is not None and commission_value != '':
            try:
                commission_val = Decimal(str(commission_value))
                if commission_op == 'gte':
                    qs = qs.filter(GuanshiProfile__chongzhifenrun__gte=commission_val)
                elif commission_op == 'lte':
                    qs = qs.filter(GuanshiProfile__chongzhifenrun__lte=commission_val)
                else:
                    return Response({'code': 400, 'msg': '分佣比较符无效'})
            except:
                return Response({'code': 400, 'msg': '分佣数值格式错误'})

        # 邀请打手总数筛选（guanshi_profile.yaogingshuliang）
        if invite_count_op and invite_count_value is not None and invite_count_value != '':
            try:
                invite_val = int(invite_count_value)
                if invite_count_op == 'gte':
                    qs = qs.filter(GuanshiProfile__yaogingshuliang__gte=invite_val)
                elif invite_count_op == 'lte':
                    qs = qs.filter(GuanshiProfile__yaogingshuliang__lte=invite_val)
                else:
                    return Response({'code': 400, 'msg': '邀请数量比较符无效'})
            except:
                return Response({'code': 400, 'msg': '邀请数量格式错误'})

        # 状态筛选
        if status is not None and status != '':
            try:
                status_val = int(status)
                if status_val not in (0, 1):
                    raise ValueError
                qs = qs.filter(GuanshiProfile__zhuangtai=status_val)
            except:
                return Response({'code': 400, 'msg': '状态值无效'})

        # 计算总数
        total = qs.count()

        # 分页
        offset = (page - 1) * page_size
        users = qs.order_by('-UserCreateTime')[offset:offset + page_size]

        # 构建返回数据
        result = []
        for user in users:
            guanshi = user.GuanshiProfile
            boss = user.BossProfile if hasattr(user, 'BossProfile') else None
            result.append({
                'yonghuid': user.UserUID,
                'avatar': user.Avatar or '',
                'nickname': boss.nickname if boss else '',
                'zhuangtai': guanshi.zhuangtai,
                'yaogingshuliang': guanshi.yaogingshuliang,
                'yue': str(guanshi.yue),
                'chongzhifenrun': str(guanshi.chongzhifenrun),
            })

        return Response({
            'code': 0,
            **list_response_meta(request),
            'data': {'list': result, 'total': total},
        })








class GetGuanliDetailView(APIView):
    """
    获取管事详情
    权限：4400a,4400b,4400c,4400d,4400e,4400f 任一
    POST /houtai/hthqgsxq
    参数：username, yonghuid
    返回：
        code:0, data: {
            base: {...},
            balance: {...},
            permanent_enabled, permanent_amount,
            custom_first_dividend: {},
            extra_dividend_map: {},
            all_members: []
        }
    """
    permission_classes = []
    parser_classes = [JSONParser]

    def post(self, request):
        username = request.data.get('username', '').strip()
        yonghuid = request.data.get('yonghuid', '').strip()

        if not username:
            return Response({'code': 401, 'msg': '缺少username'})
        if not yonghuid:
            return Response({'code': 400, 'msg': '缺少用户ID'})

        # 权限校验（需要任一权限）
        kefu, permissions = verify_kefu_permission(request, username)
        if kefu is None:
            return permissions
        required_perms = {'4400a', '4400b', '4400c', '4400d', '4400e', '4400f'}
        if not any(p in permissions for p in required_perms):
            return Response({'code': 403, 'msg': '您没有权限查看管事详情'})

        # 查询用户主表和管事扩展表
        try:
            user = User.query.select_related('GuanshiProfile', 'BossProfile').get(UserUID=yonghuid)
            guanshi = user.GuanshiProfile
            boss = user.BossProfile if hasattr(user, 'BossProfile') else None
        except User.DoesNotExist:
            return Response({'code': 404, 'msg': '管事不存在'})
        except UserGuanshi.DoesNotExist:
            return Response({'code': 404, 'msg': '用户不是管事'})

        denied = forbid_if_user_out_of_scope(request, user)
        if denied:
            return denied

        # 基础信息
        is_zuzhang = UserZuzhang.query.filter(user=user).exists()
        base_data = {
            'yonghuid': user.UserUID,
            'nickname': boss.nickname if boss else '',
            'avatar': user.Avatar or '',
            'dianhua': guanshi.dianhua or '',
            'wechat': guanshi.wechat or '',
            'zhuangtai': guanshi.zhuangtai,
            'yaoqingma': guanshi.yaoqingma,
            'yaoqingren': guanshi.yaoqingren,
            'invite_qrcode_url': guanshi.invite_qrcode_url or '',
            'yaogingshuliang': guanshi.yaogingshuliang,
            'jinrichongzhi': guanshi.jinrichongzhi,
            'jinyuechongzhi': guanshi.jinyuechongzhi,
            'chongzhifenrun': str(guanshi.chongzhifenrun),
            'create_time': guanshi.CreateTime.isoformat() if guanshi.CreateTime else None,
            'CreateTime': guanshi.CreateTime.isoformat() if guanshi.CreateTime else None,
        }

        # 余额提现相关
        balance_data = {
            'yue': str(guanshi.yue),
            'jinritixian_jine': str(guanshi.jinritixian_jine),
            'last_tixian_date': guanshi.last_tixian_date.isoformat() if guanshi.last_tixian_date else None,
            'kaioi_ewai_xiane': guanshi.kaioi_ewai_xiane,
            'ewai_xiane': str(guanshi.ewai_xiane),
        }

        # 永久分红（二次分红）
        permanent_enabled = guanshi.fenghong_erci_enabled
        permanent_amount = str(guanshi.fenghong_erci) if guanshi.fenghong_erci else '0'

        # 获取所有会员（用于前端选择）
        all_members = list(Huiyuan.query.all().values('huiyuan_id', 'jieshao', 'jiage', 'guanshifc'))
        for m in all_members:
            m['jiage'] = str(m['jiage'])
            m['guanshifc'] = str(m['guanshifc'])

        # 获取多次分红配置（按次数和会员组织，按俱乐部隔离）
        from jituan.services.club_penalty import resolve_gsfenhong_club_id
        guanshi_club = resolve_gsfenhong_club_id(dashouid=yonghuid)
        duoci_records = DuociFenhong.query.filter(
            yonghuid=yonghuid, club_id=guanshi_club,
        ).order_by('cishu')
        custom_first = {}      # 首次分红定制（cishu=1）
        extra_map = {}         # 其他次数 { cishu: { huiyuan_id: { guanshi_fenhong, jieshao, jiage } } }

        # 批量预取会员信息
        _huiyuan_ids = [r.huiyuan for r in duoci_records]
        _huiyuan_map = {
            h.huiyuan_id: h
            for h in Huiyuan.query.filter(huiyuan_id__in=_huiyuan_ids).only('huiyuan_id', 'jieshao', 'jiage')
        }

        for record in duoci_records:
            # 获取会员信息
            member = _huiyuan_map.get(record.huiyuan)
            if not member:
                continue
            member_info = {
                'jieshao': member.jieshao,
                'jiage': str(member.jiage),
            }
            if record.cishu == 1:
                custom_first[record.huiyuan] = float(record.guanshi_fenhong)
            else:
                times = record.cishu
                if times not in extra_map:
                    extra_map[times] = {}
                extra_map[times][record.huiyuan] = {
                    'guanshi_fenhong': float(record.guanshi_fenhong),
                    **member_info
                }

        # 注意：首次分红定制只存储有定制记录的会员，没有定制的会员使用默认值（前端通过会员表展示）
        # 额外次数分红按次数返回

        from jituan.services.club_context import resolve_club_id_from_request, resolve_club_scope
        from jituan.constants import DATA_SCOPE_ALL
        from jituan.services.club_user import get_user_club_id
        from users.services.change_leader import get_or_create_quota, quota_payload, list_change_logs

        if resolve_club_scope(request) == DATA_SCOPE_ALL:
            quota_club = get_user_club_id(user)
        else:
            quota_club = resolve_club_id_from_request(request)
        quota = get_or_create_quota(quota_club, yonghuid)
        change_leader_quota = quota_payload(quota)
        change_leader_logs = list_change_logs(quota_club, yonghuid, page=1, page_size=20)

        return Response({
            'code': 0,
            'data': {
                'base': base_data,
                'balance': balance_data,
                'permanent_enabled': permanent_enabled,
                'permanent_amount': permanent_amount,
                'custom_first_dividend': custom_first,
                'extra_dividend_map': extra_map,
                'all_members': all_members,
                'is_zuzhang': is_zuzhang,
                'change_leader_quota': change_leader_quota,
                'change_leader_logs': change_leader_logs,
            }
        })




def _generate_unique_zuzhang_yaoqingma(yonghuid):
    """生成唯一组长邀请码（与小程序组长注册逻辑一致）"""
    timestamp = str(int(time.time()))[-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}"
    for _ in range(5):
        if not UserZuzhang.query.filter(yaoqingma=base).exists():
            return base
        base = base + random.choice(string.digits)
    return base + str(int(time.time() * 1000))[-4:]


def _create_zuzhang_profile(user):
    """为已有用户创建组长扩展记录（默认字段与小程序注册一致）"""
    invite_guanshi_count = UserGuanshi.query.filter(yaoqingren=user.UserUID).count()
    yaoqingma = _generate_unique_zuzhang_yaoqingma(user.UserUID)
    return UserZuzhang.query.create(
        user=user,
        yaoqingma=yaoqingma,
        fenyong_zonge=Decimal('0.00'),
        ketixian_jine=Decimal('0.00'),
        yaoqing_zongshu=invite_guanshi_count,
        jinri_fenyong=Decimal('0.00'),
        jinyue_fenyong=Decimal('0.00'),
        zhuangtai=1,
        jinri_tixian=Decimal('0.00'),
        ewai_tixian_xiane=Decimal('0.00'),
        kaioi_ewai_tixian=False,
        kaioi_ewai_fenhong=False,
        ewai_fenhong_jine=Decimal('0.00'),
    )


class PromoteGuanshiToZuzhangView(APIView):
    """
    后台将管事用户升级为组长（写入 user_zuzhang 扩展表）
    POST /houtai/htgssjzz
    权限：sjzz666
    参数：username, yonghuid
    """
    permission_classes = [IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        username = request.data.get('username', '').strip()
        yonghuid = request.data.get('yonghuid', '').strip()

        if not username:
            return Response({'code': 401, 'msg': '缺少username'})
        if not yonghuid:
            return Response({'code': 400, 'msg': '缺少用户ID'})

        kefu, permissions = verify_kefu_permission(request, username)
        if kefu is None:
            return permissions
        if 'sjzz666' not in permissions:
            return Response({'code': 403, 'msg': '无权限升级组长（需要 sjzz666）'})

        try:
            user = User.query.select_related('GuanshiProfile').get(UserUID=yonghuid)
            guanshi = user.GuanshiProfile
        except User.DoesNotExist:
            return Response({'code': 404, 'msg': '用户不存在'})
        except UserGuanshi.DoesNotExist:
            return Response({'code': 404, 'msg': '用户不是管事，无法升级组长'})

        if UserZuzhang.query.filter(user=user).exists():
            zuzhang = user.ZuzhangProfile
            return Response({
                'code': 400,
                'msg': '该用户已是组长',
                'data': {
                    'yonghuid': user.UserUID,
                    'yaoqingma': zuzhang.yaoqingma,
                },
            })

        if guanshi.zhuangtai != 1:
            return Response({'code': 400, 'msg': '管事账号已禁用，无法升级组长'})

        try:
            with transaction.atomic():
                zuzhang = _create_zuzhang_profile(user)
        except IntegrityError:
            return Response({'code': 400, 'msg': '升级失败，请稍后重试'})

        write_xiugai_log(
            yonghuid=yonghuid,
            xiugaiid=kefu.user.Phone,
            leixing=XIUGAI_LEIXING_GUANSHI,
            qitashuoming=(
                f'【后台】管事升级组长：用户ID={yonghuid}，'
                f'生成组长邀请码={zuzhang.yaoqingma}，操作人={kefu.user.Phone}'
            ),
        )

        logger.info(f"管事升级组长成功: yonghuid={yonghuid}, yaoqingma={zuzhang.yaoqingma}")
        return Response({
            'code': 0,
            'msg': '已升级为组长',
            'data': {
                'yonghuid': user.UserUID,
                'nickname': getattr(user.BossProfile, 'nickname', '') if hasattr(user, 'BossProfile') else '',
                'yaoqingma': zuzhang.yaoqingma,
                'yaoqing_zongshu': zuzhang.yaoqing_zongshu,
                'ketixian_jine': str(zuzhang.ketixian_jine),
            },
        })




class UpdateGuanliView(APIView):
    """
    修改管事信息（基础信息、余额、提现限额、分红策略）
    权限细分：
        - 修改状态（封禁/解封）及昵称/电话/微信：需要4400a
        - 增加余额：需要4400c
        - 减少余额：需要4400b
        - 修改提现限额（kaioi_ewai_xiane/ewai_xiane）：需要4400e
        - 修改分红相关（永久分红、定制首次、额外次数）：需要4400f
    POST /houtai/htxggsxx
    """
    permission_classes = []
    parser_classes = [JSONParser]

    def post(self, request):
        username = request.data.get('username', '').strip()
        yonghuid = request.data.get('yonghuid', '').strip()

        if not username:
            return Response({'code': 401, 'msg': '缺少username'})
        if not yonghuid:
            return Response({'code': 400, 'msg': '缺少用户ID'})

        # 权限校验（先获取权限列表）
        kefu, permissions = verify_kefu_permission(request, username)
        if kefu is None:
            return permissions

        # 查询管事对象（不在事务外加锁，事务内加锁）
        try:
            user = User.query.get(UserUID=yonghuid)
            guanshi = user.GuanshiProfile
            boss = user.BossProfile if hasattr(user, 'BossProfile') else None
        except User.DoesNotExist:
            return Response({'code': 404, 'msg': '用户不存在'})
        except UserGuanshi.DoesNotExist:
            return Response({'code': 404, 'msg': '用户不是管事'})

        # 开始事务，内部使用 select_for_update
        with transaction.atomic():
            # 重新获取加锁对象
            user = User.objects.select_for_update().get(UserUID=yonghuid)
            guanshi = user.GuanshiProfile
            boss = user.BossProfile if hasattr(user, 'BossProfile') else None
            operator = kefu.user.Phone

            # ---------- 1. 基础信息修改（需要4400a）----------
            nickname = request.data.get('nickname')
            dianhua = request.data.get('dianhua')
            wechat = request.data.get('wechat')
            zhuangtai = request.data.get('zhuangtai')
            avatar = request.data.get('avatar')

            if any(v is not None for v in [nickname, dianhua, wechat, zhuangtai, avatar]):
                if '4400a' not in permissions:
                    return Response({'code': 403, 'msg': '无权限修改管事基础信息（需要4400a）'})
                base_changes = []
                old_nickname = boss.nickname if boss else ''
                old_dianhua = guanshi.dianhua
                old_wechat = guanshi.wechat
                old_zhuangtai = guanshi.zhuangtai
                # 处理昵称（在老板扩展表中）
                if nickname is not None:
                    if not boss:
                        boss = UserBoss.query.create(user=user, nickname=nickname)
                    else:
                        boss.nickname = nickname
                        boss.save()
                    if str(nickname) != str(old_nickname):
                        base_changes.append(f'昵称：{old_nickname or "无"}→{nickname}')
                # 处理其他字段
                if dianhua is not None:
                    guanshi.dianhua = dianhua
                    if str(dianhua) != str(old_dianhua):
                        base_changes.append(f'电话：{old_dianhua or "无"}→{dianhua}')
                if wechat is not None:
                    guanshi.wechat = wechat
                    if str(wechat) != str(old_wechat):
                        base_changes.append(f'微信：{old_wechat or "无"}→{wechat}')
                if zhuangtai is not None:
                    try:
                        zt = int(zhuangtai)
                        if zt in (0, 1):
                            guanshi.zhuangtai = zt
                            if zt != old_zhuangtai:
                                zt_map = {0: '禁用', 1: '正常'}
                                base_changes.append(f'状态：{zt_map.get(old_zhuangtai, old_zhuangtai)}→{zt_map.get(zt, zt)}')
                    except:
                        pass
                if avatar is not None:
                    user.Avatar = avatar
                    user.save()
                    base_changes.append('更新了头像')
                guanshi.save()
                if base_changes:
                    write_xiugai_log(
                        yonghuid=yonghuid,
                        xiugaiid=operator,
                        leixing=XIUGAI_LEIXING_GUANSHI,
                        qitashuoming=(
                            f'【后台】修改管事基础信息：{"；".join(base_changes)}，'
                            f'管事ID={yonghuid}，操作人={operator}'
                        ),
                    )

            # ---------- 2. 余额修改（加：4400c；减：4400b）----------
            new_yue = request.data.get('yue')
            if new_yue is not None:
                try:
                    new_yue = Decimal(str(new_yue))
                    if new_yue < 0:
                        return Response({'code': 400, 'msg': '余额不能为负数'})
                except:
                    return Response({'code': 400, 'msg': '余额格式错误'})

                old_yue = guanshi.yue
                if new_yue > old_yue:
                    if '4400c' not in permissions:
                        return Response({'code': 403, 'msg': '无权限增加余额（需要4400c）'})
                    from jituan.services.group_finance_gate import deny_balance_add_exec
                    deny = deny_balance_add_exec(
                        request, permissions=permissions, target_user=user,
                    )
                    if deny:
                        return deny
                    action_desc = f'增加{new_yue - old_yue}元'
                elif new_yue < old_yue:
                    if '4400b' not in permissions:
                        return Response({'code': 403, 'msg': '无权限减少余额（需要4400b）'})
                    action_desc = f'减少{old_yue - new_yue}元'
                else:
                    action_desc = '无变动'
                if new_yue != old_yue:
                    guanshi.yue = new_yue
                    guanshi.save()
                    from jituan.services.club_context import resolve_club_id_from_request
                    club_id = resolve_club_id_from_request(request) or ''
                    write_xiugai_log(
                        yonghuid=yonghuid,
                        xiugaiid=operator,
                        leixing=XIUGAI_LEIXING_GUANSHI,
                        guanshiyue=new_yue,
                        guanshiyueq=old_yue,
                        qitashuoming=(
                            f'【后台】修改管事可提现余额：{old_yue}元 → {new_yue}元（{action_desc}），'
                            f'管事ID={yonghuid}，俱乐部={club_id}，操作人={operator}'
                        ),
                    )

            # ---------- 3. 提现限额修改（需要4400e）----------
            kaioi_ewai = request.data.get('kaioi_ewai_xiane')
            ewai_val = request.data.get('ewai_xiane')
            if kaioi_ewai is not None or ewai_val is not None:
                if '4400e' not in permissions:
                    return Response({'code': 403, 'msg': '无权限修改提现限额（需要4400e）'})
                limit_changes = []
                old_kaioi = guanshi.kaioi_ewai_xiane
                old_ewai = guanshi.ewai_xiane
                if kaioi_ewai is not None:
                    guanshi.kaioi_ewai_xiane = bool(kaioi_ewai)
                    if bool(kaioi_ewai) != old_kaioi:
                        limit_changes.append(f'额外限额开关：{"开" if old_kaioi else "关"}→{"开" if kaioi_ewai else "关"}')
                if ewai_val is not None:
                    try:
                        guanshi.ewai_xiane = Decimal(str(ewai_val))
                        if guanshi.ewai_xiane != old_ewai:
                            limit_changes.append(f'额外限额金额：{old_ewai}→{guanshi.ewai_xiane}')
                    except:
                        return Response({'code': 400, 'msg': '额外限额金额格式错误'})
                guanshi.save()
                if limit_changes:
                    write_xiugai_log(
                        yonghuid=yonghuid,
                        xiugaiid=operator,
                        leixing=XIUGAI_LEIXING_GUANSHI,
                        qitashuoming=(
                            f'【后台】修改管事提现限额：{"；".join(limit_changes)}，'
                            f'管事ID={yonghuid}，操作人={operator}'
                        ),
                    )

            # ---------- 4. 分红相关修改（需要4400f）----------
            perm_enabled = request.data.get('permanent_enabled')
            perm_amount = request.data.get('permanent_amount')
            custom_first = request.data.get('custom_first_dividend')
            extra_map = request.data.get('extra_dividend_map')

            if any(v is not None for v in [perm_enabled, perm_amount, custom_first, extra_map]):
                if '4400f' not in permissions:
                    return Response({'code': 403, 'msg': '无权限修改分红策略（需要4400f）'})

                # 4.1 永久分红
                if perm_enabled is not None:
                    guanshi.fenghong_erci_enabled = bool(perm_enabled)
                if perm_amount is not None:
                    try:
                        guanshi.fenghong_erci = Decimal(str(perm_amount))
                    except:
                        return Response({'code': 400, 'msg': '永久分红金额格式错误'})
                guanshi.save()

                # 4.2 首次定制分红（cishu=1）
                if custom_first is not None and isinstance(custom_first, dict):
                    from jituan.services.club_penalty import resolve_gsfenhong_club_id
                    guanshi_club = resolve_gsfenhong_club_id(dashouid=yonghuid)
                    # 批量预取当前所有首次定制记录（避免循环内 N+1）
                    existing_first_list = list(
                        DuociFenhong.query.filter(
                            club_id=guanshi_club, yonghuid=yonghuid, cishu=1,
                        )
                    )
                    _existing_map = {r.huiyuan: r for r in existing_first_list}
                    _to_create = []
                    _to_update = []
                    _to_delete_ids = []
                    # 前端传来的定制字典 {会员ID: 金额}
                    for huiyuan_id, amount in custom_first.items():
                        try:
                            amount = Decimal(str(amount))
                        except:
                            continue
                        if amount <= 0:
                            rec = _existing_map.get(huiyuan_id)
                            if rec is not None:
                                _to_delete_ids.append(rec.id)
                        else:
                            rec = _existing_map.get(huiyuan_id)
                            if rec is not None:
                                rec.guanshi_fenhong = amount
                                rec.zuzhang_fenhong = Decimal('0')
                                _to_update.append(rec)
                            else:
                                _to_create.append(DuociFenhong(
                                    club_id=guanshi_club,
                                    yonghuid=yonghuid,
                                    huiyuan=huiyuan_id,
                                    cishu=1,
                                    guanshi_fenhong=amount,
                                    zuzhang_fenhong=Decimal('0'),
                                ))
                    # 删除那些在前端字典中不存在的首次定制记录（即已取消定制）
                    for rec in existing_first_list:
                        if rec.huiyuan not in custom_first and rec.id not in _to_delete_ids:
                            _to_delete_ids.append(rec.id)
                    if _to_create:
                        DuociFenhong.objects.bulk_create(_to_create)
                    if _to_update:
                        DuociFenhong.objects.bulk_update(_to_update, ['guanshi_fenhong', 'zuzhang_fenhong'])
                    if _to_delete_ids:
                        DuociFenhong.objects.filter(id__in=_to_delete_ids).delete()

                # 4.3 额外次数分红（cishu >= 2）
                if extra_map is not None and isinstance(extra_map, dict):
                    from jituan.services.club_penalty import resolve_gsfenhong_club_id
                    guanshi_club = resolve_gsfenhong_club_id(dashouid=yonghuid)
                    # 收集需要保留的记录
                    keep_set = set()
                    # 解析前端数据，先汇总 keep_set 与目标金额
                    _extra_targets = []  # [(cishu, huiyuan_id, amount)]
                    for times_str, members in extra_map.items():
                        try:
                            cishu = int(times_str)
                            if cishu < 2:
                                continue
                        except:
                            continue
                        if not isinstance(members, dict):
                            continue
                        for huiyuan_id, data in members.items():
                            if not isinstance(data, dict):
                                continue
                            amount = data.get('guanshi_fenhong')
                            if amount is None:
                                continue
                            try:
                                amount = Decimal(str(amount))
                            except:
                                continue
                            keep_set.add((cishu, huiyuan_id))
                            _extra_targets.append((cishu, huiyuan_id, amount))
                    # 批量预取已有额外次数记录
                    existing_extra_list = list(
                        DuociFenhong.query.filter(
                            club_id=guanshi_club, yonghuid=yonghuid, cishu__gte=2,
                        )
                    )
                    _extra_map = {(r.cishu, r.huiyuan): r for r in existing_extra_list}
                    _to_create = []
                    _to_update = []
                    _to_delete_ids = []
                    for cishu, huiyuan_id, amount in _extra_targets:
                        rec = _extra_map.get((cishu, huiyuan_id))
                        if rec is not None:
                            rec.guanshi_fenhong = amount
                            rec.zuzhang_fenhong = Decimal('0')
                            _to_update.append(rec)
                        else:
                            _to_create.append(DuociFenhong(
                                club_id=guanshi_club,
                                yonghuid=yonghuid,
                                huiyuan=huiyuan_id,
                                cishu=cishu,
                                guanshi_fenhong=amount,
                                zuzhang_fenhong=Decimal('0'),
                            ))
                    # 删除不在 keep_set 中的额外次数记录
                    for rec in existing_extra_list:
                        if (rec.cishu, rec.huiyuan) not in keep_set:
                            _to_delete_ids.append(rec.id)
                    if _to_create:
                        DuociFenhong.objects.bulk_create(_to_create)
                    if _to_update:
                        DuociFenhong.objects.bulk_update(_to_update, ['guanshi_fenhong', 'zuzhang_fenhong'])
                    if _to_delete_ids:
                        DuociFenhong.objects.filter(id__in=_to_delete_ids).delete()

                dividend_parts = []
                if perm_enabled is not None:
                    dividend_parts.append(f'永久分红开关→{"开" if perm_enabled else "关"}')
                if perm_amount is not None:
                    dividend_parts.append(f'永久分红金额→{perm_amount}')
                if custom_first is not None:
                    dividend_parts.append(f'更新首次定制分红({len(custom_first)}项)')
                if extra_map is not None:
                    dividend_parts.append(f'更新额外次数分红({len(extra_map)}组)')
                write_xiugai_log(
                    yonghuid=yonghuid,
                    xiugaiid=operator,
                    leixing=XIUGAI_LEIXING_GUANSHI,
                    qitashuoming=(
                        f'【后台】修改管事分红策略：{"；".join(dividend_parts) or "配置已更新"}，'
                        f'管事ID={yonghuid}，操作人={operator}'
                    ),
                )

        return Response({'code': 0, 'msg': '修改成功'})


def _admin_quota_club_id(request, user):
    from jituan.services.club_context import resolve_club_id_from_request, resolve_club_scope
    from jituan.constants import DATA_SCOPE_ALL
    from jituan.services.club_user import get_user_club_id
    if resolve_club_scope(request) == DATA_SCOPE_ALL:
        return get_user_club_id(user)
    return resolve_club_id_from_request(request)


class GuanshiChangeLeaderQuotaView(APIView):
    """
    后台设置/追加管事换组长次数
    POST /houtai/htgs_huan_zz_quota
    参数：username, yonghuid,
          action=set|add,
          total_quota（set）或 add_count（add）
    权限：4400a
    """
    permission_classes = []
    parser_classes = [JSONParser]

    def post(self, request):
        username = request.data.get('username', '').strip()
        yonghuid = request.data.get('yonghuid', '').strip()
        action = (request.data.get('action') or 'add').strip().lower()

        if not username:
            return Response({'code': 401, 'msg': '缺少username'})
        if not yonghuid:
            return Response({'code': 400, 'msg': '缺少用户ID'})

        kefu, permissions = verify_kefu_permission(request, username)
        if kefu is None:
            return permissions
        if '4400a' not in permissions and '000001' not in permissions:
            return Response({'code': 403, 'msg': '无权限修改换组长次数（需要4400a）'})

        try:
            user = User.query.select_related('GuanshiProfile').get(UserUID=yonghuid)
            _ = user.GuanshiProfile
        except User.DoesNotExist:
            return Response({'code': 404, 'msg': '管事不存在'})
        except UserGuanshi.DoesNotExist:
            return Response({'code': 404, 'msg': '用户不是管事'})

        denied = forbid_if_user_out_of_scope(request, user)
        if denied:
            return denied

        from users.services.change_leader import set_total_quota, add_quota
        club_id = _admin_quota_club_id(request, user)
        if action == 'set':
            result = set_total_quota(club_id, yonghuid, request.data.get('total_quota'))
        else:
            result = add_quota(
                club_id,
                yonghuid,
                request.data.get('add_count') or request.data.get('add'),
            )
        if not result.get('ok'):
            return Response({'code': result.get('code', 400), 'msg': result.get('msg', '失败')})
        return Response({'code': 0, 'msg': result.get('msg', 'ok'), 'data': result.get('data')})


class GuanshiChangeLeaderLogView(APIView):
    """
    后台查询管事换组长记录
    POST /houtai/htgs_huan_zz_logs
    参数：username, yonghuid, page, page_size
    权限：4400a-f 任一
    """
    permission_classes = []
    parser_classes = [JSONParser]

    def post(self, request):
        username = request.data.get('username', '').strip()
        yonghuid = request.data.get('yonghuid', '').strip()

        if not username:
            return Response({'code': 401, 'msg': '缺少username'})
        if not yonghuid:
            return Response({'code': 400, 'msg': '缺少用户ID'})

        kefu, permissions = verify_kefu_permission(request, username)
        if kefu is None:
            return permissions
        required_perms = {'4400a', '4400b', '4400c', '4400d', '4400e', '4400f', '000001'}
        if not any(p in permissions for p in required_perms):
            return Response({'code': 403, 'msg': '您没有权限查看换组长记录'})

        try:
            user = User.query.select_related('GuanshiProfile').get(UserUID=yonghuid)
            _ = user.GuanshiProfile
        except User.DoesNotExist:
            return Response({'code': 404, 'msg': '管事不存在'})
        except UserGuanshi.DoesNotExist:
            return Response({'code': 404, 'msg': '用户不是管事'})

        denied = forbid_if_user_out_of_scope(request, user)
        if denied:
            return denied

        from users.services.change_leader import list_change_logs
        club_id = _admin_quota_club_id(request, user)
        data = list_change_logs(
            club_id,
            yonghuid,
            page=request.data.get('page', 1),
            page_size=request.data.get('page_size', 20),
        )
        return Response({'code': 0, 'data': data})






