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']

def _serialize_permission_row(perm_row):
    """gvsdsdk Permission → 后台 Vue 约定的小写字段"""
    if isinstance(perm_row, dict):
        code = perm_row.get('PermCode') or perm_row.get('perm_code') or ''
        name = perm_row.get('PermName') or perm_row.get('perm_name') or code
        desc = perm_row.get('PermDesc') or perm_row.get('perm_desc') or ''
    else:
        code = perm_row.PermCode or ''
        name = perm_row.PermName or code
        desc = perm_row.PermDesc or ''
    return {'perm_code': code, 'perm_name': name, 'perm_desc': desc}


class GetRolePermissionView(APIView):
    """
    获取所有角色、权限以及角色关联的用户数
    权限要求：用户必须拥有 000001 权限
    """
    permission_classes = [IsAuthenticated]

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

        # 1. 权限校验（验证客服身份，并获取权限列表）
        kefu, permissions = verify_kefu_permission(request, username)
        if kefu is None:
            return permissions  # 直接返回错误响应

        from jituan.services.admin_context import can_access_admin_user_management
        if not can_access_admin_user_management(request.user, permissions):
            return Response({'code': 403, 'msg': '您无权访问此页面'})

        # 3. 获取所有权限
        all_perms = Permission.objects.filter(PermStatus=1).values('PermCode', 'PermName', 'PermDesc')
        permissions_list = [_serialize_permission_row(p) for p in all_perms]

        from jituan.services.club_rbac import count_role_users_in_scope, filter_roles_for_request

        kefu_user_uuids = list(
            User.objects.filter(KefuProfile__isnull=False).values_list('UserUUID', flat=True)
        )
        roles = list(filter_roles_for_request(request))
        # 批量预取 RolePermission + Permission（避免循环内 N+1）
        _role_uuids = [r.RoleUUID for r in roles]
        _rp_pairs = list(
            RolePermission.objects.filter(RoleUUID__in=_role_uuids)
            .values_list('RoleUUID', 'PermUUID')
        ) if _role_uuids else []
        _perm_uuids = list({p for _, p in _rp_pairs})
        _perm_rows_by_uuid = {
            p['PermUUID']: p
            for p in Permission.objects.filter(PermUUID__in=_perm_uuids)
            .values('PermUUID', 'PermCode', 'PermName', 'PermDesc')
        } if _perm_uuids else {}
        _perms_by_role = {}
        for role_uuid, perm_uuid in _rp_pairs:
            perm_row = _perm_rows_by_uuid.get(perm_uuid)
            if perm_row is not None:
                _perms_by_role.setdefault(role_uuid, []).append(_serialize_permission_row(perm_row))

        roles_data = []
        for role in roles:
            user_count = count_role_users_in_scope(role, request, kefu_user_uuids)
            perms_of_role = _perms_by_role.get(role.RoleUUID, [])
            roles_data.append({
                'role_code': role.RoleName,
                'role_name': role.RoleName,
                'description': role.RoleDesc or '',
                'club_id': getattr(role, 'ClubID', '') or '',
                'user_count': user_count,
                'permissions': perms_of_role
            })

        return Response({
            'code': 0,
            'data': {
                'roles': roles_data,
                'permissions': permissions_list
            }
        })


class ModifyRolePermissionView(APIView):
    """
    通用接口：支持删除角色、为角色添加权限、移除角色权限
    操作类型通过 action 字段区分
    """
    permission_classes = [IsAuthenticated]

    def post(self, request):
        username = request.data.get('username', '').strip()
        action = request.data.get('action')  # delete_role, add_permission, remove_permission
        if not username or not action:
            return Response({'code': 400, 'msg': '缺少必要参数'})

        # 权限校验
        kefu, permissions = verify_kefu_permission(request, username)
        if kefu is None:
            return permissions
        if '000001' not in permissions:
            return Response({'code': 403, 'msg': '您无权进行此操作'})

        # 获取角色（按当前俱乐部解析，避免多俱乐部同名角色冲突）
        role_code = request.data.get('role_code')
        if not role_code:
            return Response({'code': 400, 'msg': '缺少角色编码'})

        from jituan.services.admin_context import can_manage_admin_assignments, can_manage_roles_for_club
        from jituan.services.club_rbac import resolve_role_by_name, resolve_role_club_id
        explicit_club = (request.data.get('target_club_id') or request.data.get('club_id') or '').strip() or None
        bind_club_id = resolve_role_club_id(request, explicit_club)
        if bind_club_id:
            if not can_manage_roles_for_club(request.user, permissions, bind_club_id):
                return Response({'code': 403, 'msg': '您无权管理该俱乐部的角色'})
        elif not can_manage_admin_assignments(request.user, permissions):
            return Response({'code': 403, 'msg': '您无权管理全局角色'})
        role = resolve_role_by_name(role_code, bind_club_id)
        if not role:
            return Response({'code': 404, 'msg': '角色不存在或与当前俱乐部不匹配'})

        # 超级管理员角色的特殊限制
        if role.RoleName == '管理员':
            if action in ['delete_role']:
                return Response({'code': 403, 'msg': '超级管理员角色不能删除'})

        # 根据 action 处理
        if action == 'delete_role':
            # 删除角色：同时删除角色权限关联、用户角色关联
            with transaction.atomic():
                RolePermission.objects.filter(RoleUUID=role.RoleUUID).delete()
                UserRole.objects.filter(RoleUUID=role.RoleUUID).delete()
                role.delete()
            return Response({'code': 0, 'msg': '角色删除成功'})

        elif action == 'add_permission':
            perm_code = request.data.get('perm_code')
            if not perm_code:
                return Response({'code': 400, 'msg': '缺少权限编码'})
            if role.RoleName == '管理员' and perm_code == '000001':
                return Response({'code': 403, 'msg': '此权限已存在，不能重复添加'})
            try:
                perm = Permission.objects.get(PermCode=perm_code)
            except Permission.DoesNotExist:
                return Response({'code': 404, 'msg': '权限不存在'})
            # 检查是否已存在
            if RolePermission.objects.filter(RoleUUID=role.RoleUUID, PermUUID=perm.PermUUID).exists():
                return Response({'code': 400, 'msg': '该角色已拥有此权限'})
            RolePermission.objects.create(
                RolePermUUID=uuid.uuid4().bytes,
                RoleUUID=role.RoleUUID,
                PermUUID=perm.PermUUID,
                CreateTime=timezone.now(),
            )
            return Response({'code': 0, 'msg': '权限添加成功'})

        elif action == 'remove_permission':
            perm_code = request.data.get('perm_code')
            if not perm_code:
                return Response({'code': 400, 'msg': '缺少权限编码'})
            if role.RoleName == '管理员' and perm_code == '000001':
                return Response({'code': 403, 'msg': '不能移除超级管理员的此权限'})
            try:
                perm = Permission.objects.get(PermCode=perm_code)
            except Permission.DoesNotExist:
                return Response({'code': 404, 'msg': '权限不存在'})
            deleted, _ = RolePermission.objects.filter(RoleUUID=role.RoleUUID, PermUUID=perm.PermUUID).delete()
            if deleted == 0:
                return Response({'code': 400, 'msg': '该角色未拥有此权限'})
            return Response({'code': 0, 'msg': '权限移除成功'})

        elif action == 'update_role':
            role_name = (request.data.get('role_name') or '').strip()
            description = (request.data.get('description') or '').strip()
            perm_codes = request.data.get('perm_codes') or []
            if role.RoleName == '管理员':
                role_name = role.RoleName
            elif role_name and role_name != role.RoleName:
                role_club_id = getattr(role, 'ClubID', '') or ''
                if Role.objects.filter(
                    RoleName=role_name, ClubID=role_club_id,
                ).exclude(RoleUUID=role.RoleUUID).exists():
                    return Response({'code': 400, 'msg': '该俱乐部下角色名称已存在'})
            with transaction.atomic():
                if role.RoleName != '管理员':
                    if role_name:
                        role.RoleName = role_name
                    role.RoleDesc = description
                    role.save(update_fields=['RoleName', 'RoleDesc'])
                RolePermission.objects.filter(RoleUUID=role.RoleUUID).delete()
                for pc in perm_codes:
                    if pc == '000001' and role.RoleName != '管理员':
                        continue
                    try:
                        perm = Permission.objects.get(PermCode=pc, PermStatus=1)
                    except Permission.DoesNotExist:
                        continue
                    RolePermission.objects.create(
                        RolePermUUID=uuid.uuid4().bytes,
                        RoleUUID=role.RoleUUID,
                        PermUUID=perm.PermUUID,
                        CreateTime=timezone.now(),
                    )
                if role.RoleName == '管理员':
                    try:
                        super_perm = Permission.objects.get(PermCode='000001', PermStatus=1)
                        if not RolePermission.objects.filter(
                            RoleUUID=role.RoleUUID, PermUUID=super_perm.PermUUID,
                        ).exists():
                            RolePermission.objects.create(
                                RolePermUUID=uuid.uuid4().bytes,
                                RoleUUID=role.RoleUUID,
                                PermUUID=super_perm.PermUUID,
                                CreateTime=timezone.now(),
                            )
                    except Permission.DoesNotExist:
                        pass
            return Response({'code': 0, 'msg': '角色保存成功'})

        else:
            return Response({'code': 400, 'msg': '无效的 action'})


class AddRoleView(APIView):
    """
    添加角色：自动生成角色编码，前端提供角色名称、描述、选择的权限列表
    """
    permission_classes = [IsAuthenticated]

    def post(self, request):
        username = request.data.get('username', '').strip()
        role_name = request.data.get('role_name', '').strip()
        description = request.data.get('description', '').strip()
        perm_codes = request.data.get('perm_codes', [])  # 列表

        if not username or not role_name:
            return Response({'code': 400, 'msg': '缺少必要参数'})

        # 权限校验
        kefu, permissions = verify_kefu_permission(request, username)
        if kefu is None:
            return permissions
        if '000001' not in permissions:
            return Response({'code': 403, 'msg': '您无权进行此操作'})

        # 检查角色名称是否已存在（同俱乐部内唯一）；单俱乐部视图强制写入当前顶栏俱乐部
        from jituan.services.admin_context import can_manage_admin_assignments, can_manage_roles_for_club
        from jituan.services.club_rbac import resolve_role_club_id, role_name_exists
        target_club_id = resolve_role_club_id(
            request, (request.data.get('target_club_id') or '').strip() or None,
        )
        if target_club_id:
            if not can_manage_roles_for_club(request.user, permissions, target_club_id):
                return Response({'code': 403, 'msg': '您无权在该俱乐部下创建角色'})
        elif not can_manage_admin_assignments(request.user, permissions):
            return Response({'code': 403, 'msg': '仅集团权限可创建全局角色'})
        if role_name_exists(role_name, target_club_id):
            return Response({'code': 400, 'msg': '该俱乐部下角色名称已存在'})

        # 生成唯一角色编码（格式：ROLE_ + 8位随机字母数字）
        role_code = f"ROLE_{''.join(random.choices(string.ascii_uppercase + string.digits, k=8))}"

        # 创建角色
        with transaction.atomic():
            role = Role.objects.create(
                RoleUUID=uuid.uuid4().bytes,
                TenantUUID=b'\x00' * 16,
                RoleName=role_name,
                RoleType=2,
                RoleStatus=1,
                AssignScope=0,
                RoleDesc=description,
                ClubID=target_club_id,
                CreateTime=timezone.now(),
            )
            # 绑定权限（过滤掉不存在的权限编码）
            for pc in perm_codes:
                # 不允许添加 000001 权限（此权限仅供超级管理员）
                if pc == '000001':
                    continue
                try:
                    perm = Permission.objects.get(PermCode=pc)
                    RolePermission.objects.create(
                        RolePermUUID=uuid.uuid4().bytes,
                        RoleUUID=role.RoleUUID,
                        PermUUID=perm.PermUUID,
                        CreateTime=timezone.now(),
                    )
                except Permission.DoesNotExist:
                    logger.warning(f"添加角色时忽略不存在的权限编码: {pc}")

        return Response({'code': 0, 'msg': '角色添加成功', 'data': {'role_code': role_code}})



class GetAdminUserListView(APIView):
    permission_classes = [IsAuthenticated]

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

            kefu, permissions = verify_kefu_permission(request, username)
            if kefu is None:
                return permissions
            from jituan.services.admin_context import can_access_admin_user_management
            if not can_access_admin_user_management(request.user, permissions):
                return Response({'code': 403, 'msg': '您无权访问此页面'})

            phone = request.data.get('phone', '').strip()
            nicheng = request.data.get('nicheng', '').strip()
            role_code = request.data.get('roleCode', '').strip()
            page = int(request.data.get('page', 1))
            page_size = int(request.data.get('pageSize', 20))

            # UserType 是 @property 非数据库字段，不能用 filter；
            # KefuProfile__isnull=False 已确保只查到客服用户
            users = User.query.filter(
                KefuProfile__isnull=False
            ).select_related('KefuProfile')

            from jituan.models import AdminAssignment, Club
            from jituan.constants import ADMIN_ROLE_LABELS
            from jituan.services.club_rbac import filter_kefu_users_by_admin_scope
            users = filter_kefu_users_by_admin_scope(users, request)

            if phone:
                users = users.filter(Phone__icontains=phone)
            if nicheng:
                users = users.filter(KefuProfile__nicheng__icontains=nicheng)

            # 关键修正：先求值为列表，再传入 phone__in
            if role_code:
                from jituan.services.club_rbac import resolve_role_by_name, resolve_role_club_id
                filter_club_id = resolve_role_club_id(request)
                target_role = resolve_role_by_name(role_code, filter_club_id)
                if target_role:
                    user_uuids = list(
                        UserRole.objects.filter(RoleUUID=target_role.RoleUUID)
                        .values_list('UserUUID', flat=True)
                    )
                    users = users.filter(UserUUID__in=user_uuids)
                else:
                    users = users.none()

            users = users.order_by('-UserCreateTime')
            paginator = Paginator(users, page_size)
            page_obj = paginator.get_page(page)

            # 批量预取本页所有用户的 UserRole + Role（避免循环内 N+1）
            _page_users = list(page_obj)
            _page_user_uuids = [u.UserUUID for u in _page_users]
            _ur_pairs = list(
                UserRole.objects.filter(UserUUID__in=_page_user_uuids)
                .values_list('UserUUID', 'RoleUUID')
            ) if _page_user_uuids else []
            _role_uuids_in_page = list({r for _, r in _ur_pairs})
            _role_info_by_uuid = {
                r.RoleUUID: {'role_name': r.RoleName, 'club_id': getattr(r, 'ClubID', '') or ''}
                for r in Role.objects.filter(RoleUUID__in=_role_uuids_in_page)
            } if _role_uuids_in_page else {}
            _roles_by_user = {}
            for user_uuid, role_uuid in _ur_pairs:
                info = _role_info_by_uuid.get(role_uuid)
                if info is not None:
                    _roles_by_user.setdefault(user_uuid, []).append({
                        'role_code': info['role_name'],
                        'role_name': info['role_name'],
                        'club_id': info['club_id'],
                    })

            _page_yonghuids = [u.UserUID for u in _page_users]
            _club_name_map = {c.club_id: c.name for c in Club.query.filter(status=1)}
            _assignments_by_user = {}
            if _page_yonghuids:
                for a in AdminAssignment.query.filter(yonghuid__in=_page_yonghuids, status=1):
                    if a.club_id:
                        club_label = _club_name_map.get(a.club_id, a.club_id)
                    else:
                        club_label = '集团（全部子公司）'
                    _assignments_by_user.setdefault(a.yonghuid, []).append({
                        'id': a.id,
                        'club_id': a.club_id,
                        'club_label': club_label,
                        'role_code': a.role_code,
                        'role_name': ADMIN_ROLE_LABELS.get(a.role_code, a.role_code),
                        'is_primary': a.is_primary,
                    })

            from jituan.constants import DATA_SCOPE_ALL
            from jituan.services.club_context import resolve_club_id_from_request, resolve_club_scope
            from jituan.services.club_rbac import filter_roles_for_request

            scope = resolve_club_scope(request)
            curr_club = (resolve_club_id_from_request(request) or '').strip()
            # 单俱乐部视图：角色下拉/展示只允许「本俱乐部角色」；若本店无角色则仅全局
            allowed_role_club_ids = None
            if scope != DATA_SCOPE_ALL:
                scoped_roles = list(filter_roles_for_request(request).values_list('ClubID', flat=True))
                allowed_role_club_ids = {(c or '').strip() for c in scoped_roles}

            def _roles_in_view(roles_data):
                if scope == DATA_SCOPE_ALL or allowed_role_club_ids is None:
                    return roles_data
                return [
                    r for r in roles_data
                    if (r.get('club_id') or '').strip() in allowed_role_club_ids
                ]

            def _assignments_in_view(assignments):
                if scope == DATA_SCOPE_ALL:
                    return assignments
                # 本俱乐部任职 + 集团级（club_id 空）；绝不展示其他子公司任职
                return [
                    a for a in assignments
                    if not a.get('club_id') or a.get('club_id') == curr_club
                ]

            data_list = []
            for user in _page_users:
                roles_data = _roles_in_view(_roles_by_user.get(user.UserUUID, []))
                data_list.append({
                    'phone': user.Phone or '',
                    'yonghuid': user.UserUID or '',
                    'nicheng': user.KefuProfile.nicheng,
                    'club_id': getattr(user, 'ClubID', '') or '',
                    'roles': roles_data,
                    'assignments': _assignments_in_view(_assignments_by_user.get(user.UserUID, [])),
                    'status': user.KefuProfile.zhuangtai,
                    'create_time': user.UserCreateTime.strftime('%Y-%m-%d %H:%M:%S') if getattr(user, 'UserCreateTime', None) else '',
                    'update_time': user.KefuProfile.UpdateTime.strftime('%Y-%m-%d %H:%M:%S') if getattr(user.KefuProfile, 'UpdateTime', None) else '',
                    'CreateTime': user.UserCreateTime.strftime('%Y-%m-%d %H:%M:%S') if getattr(user, 'UserCreateTime', None) else '',
                    'UpdateTime': user.KefuProfile.UpdateTime.strftime('%Y-%m-%d %H:%M:%S') if getattr(user.KefuProfile, 'UpdateTime', None) else '',
                })

            from jituan.services.admin_context import can_manage_admin_assignments, get_manageable_club_ids
            manageable = sorted(get_manageable_club_ids(
                request.user, permissions, current_club_id=curr_club,
            ))
            if scope != DATA_SCOPE_ALL:
                # 顶栏在具体俱乐部时，可管理集合收敛到当前店（含超级管理 000001）
                manageable = [c for c in manageable if c == curr_club]
                # 兜底：本店超级管理一定能管本店用户（不依赖集团任职）
                if not manageable and curr_club and permissions and '000001' in permissions:
                    manageable = [curr_club]
            return Response({
                'code': 0,
                'data': {
                    'list': data_list,
                    'total': paginator.count,
                    'page': page,
                    'pageSize': page_size,
                    'can_manage_club_assignments': can_manage_admin_assignments(request.user, permissions),
                    'can_manage_club_users': bool(manageable) or (
                        bool(permissions) and '000001' in permissions and scope != DATA_SCOPE_ALL
                    ),
                    'manageable_club_ids': manageable,
                    'current_club_id': curr_club,
                    'scope': scope,
                }
            })

        except Exception as e:
            logger.error(f"GetAdminUserListView 异常: {e}\n{traceback.format_exc()}")
            return Response({'code': 500, 'msg': f'服务器内部错误: {str(e)}'})



class GetAdminRolesView(APIView):
    """获取所有角色（用于筛选和分配）"""
    permission_classes = [IsAuthenticated]

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

        kefu, permissions = verify_kefu_permission(request, username)
        if kefu is None:
            return permissions
        from jituan.services.admin_context import can_access_admin_user_management
        if not can_access_admin_user_management(request.user, permissions):
            return Response({'code': 403, 'msg': '您无权访问此页面'})

        from jituan.constants import DATA_SCOPE_ALL
        from jituan.services.admin_context import can_manage_admin_assignments
        from jituan.services.club_context import resolve_club_scope
        from jituan.services.club_rbac import filter_roles_for_request

        scope = resolve_club_scope(request)
        all_clubs = request.data.get('all_clubs') in (True, 1, '1', 'true', 'yes')
        # 仅集团汇总视图 + 集团任职管理权 才可拉全量子公司角色；
        # 顶栏在具体俱乐部时（含集团账号切到某店），绝不容许其他俱乐部角色泄露。
        if (
            scope == DATA_SCOPE_ALL
            and all_clubs
            and can_manage_admin_assignments(request.user, permissions)
        ):
            roles = Role.objects.filter(RoleStatus=1).order_by('ClubID', 'RoleName').values('RoleName', 'ClubID')
        else:
            roles = filter_roles_for_request(request).order_by('ClubID', 'RoleName').values('RoleName', 'ClubID')
        return Response({
            'code': 0,
            'data': {
                'roles': [
                    {
                        'role_code': r['RoleName'],
                        'role_name': r['RoleName'],
                        'club_id': r.get('ClubID') or '',
                    }
                    for r in roles
                ]
            }
        })






'''class GetAdminUserListView(APIView):
    """获取后台用户列表（支持分页、筛选）"""
    permission_classes = [IsAuthenticated]

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

        kefu, permissions = verify_kefu_permission(request, username)
        if kefu is None:
            return permissions
        from jituan.services.admin_context import can_access_admin_user_management
        if not can_access_admin_user_management(request.user, permissions):
            return Response({'code': 403, 'msg': '您无权访问此页面'})

        # 筛选条件
        phone = request.data.get('phone', '').strip()
        nicheng = request.data.get('nicheng', '').strip()
        role_code = request.data.get('roleCode', '').strip()
        page = int(request.data.get('page', 1))
        page_size = int(request.data.get('pageSize', 20))

        # 基础查询：存在客服扩展表
        users = User.query.filter(KefuProfile__isnull=False).select_related('KefuProfile')
        if phone:
            users = users.filter(Phone__icontains=phone)
        if nicheng:
            users = users.filter(KefuProfile__nicheng__icontains=nicheng)
        if role_code:
            # 筛选拥有该角色的用户
            user_ids_with_role = UserRole.query.filter(role__role_code=role_code).values_list('account_id', flat=True)
            users = users.filter(phone__in=user_ids_with_role)

        # 排序
        users = users.order_by('-CreateTime')

        # 分页
        paginator = Paginator(users, page_size)
        page_obj = paginator.get_page(page)

        # 构建返回数据
        data_list = []
        for user in page_obj:
            # 获取用户的所有角色
            user_roles = UserRole.query.filter(account_id=user.Phone).select_related('role')
            roles_data = [{'role_code': ur.role.role_code, 'role_name': ur.role.role_name} for ur in user_roles]
            data_list.append({
                'phone': user.Phone,
                'nicheng': user.KefuProfile.nicheng,
                'roles': roles_data,
                'status': user.KefuProfile.zhuangtai,
                'CreateTime': user.UserCreateTime.strftime('%Y-%m-%d %H:%M:%S'),
                'UpdateTime': user.UpdateTime.strftime('%Y-%m-%d %H:%M:%S'),
            })

        return Response({
            'code': 0,
            'data': {
                'list': data_list,
                'total': paginator.count,
                'page': page,
                'pageSize': page_size
            }
        })'''





class ModifyAdminUserView(APIView):
    """修改后台用户信息（昵称、密码、二级密码、状态、角色）"""
    permission_classes = [IsAuthenticated]

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

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

        from jituan.services.admin_context import (
            can_manage_admin_assignments,
            can_manage_roles_for_club,
            can_access_admin_user_management,
        )

        club_assign_actions = {'add_club_assignment', 'remove_club_assignment'}
        role_manage_actions = {'add_user_roles', 'remove_user_role'}
        if action in club_assign_actions:
            # 跨店任职仍需集团权限；本店超级管理只管功能角色与账号，不分配其他俱乐部任职
            if not can_manage_admin_assignments(request.user, permissions):
                return Response({'code': 403, 'msg': '无权分配俱乐部任职（需集团权限）'})
        elif action in role_manage_actions:
            # 本店超级管理 000001 可给本俱乐部用户增删功能角色
            if not can_access_admin_user_management(request.user, permissions):
                return Response({'code': 403, 'msg': '您无权管理角色分配'})
        elif not can_manage_admin_assignments(request.user, permissions) and '000001' not in permissions:
            return Response({'code': 403, 'msg': '您无权进行此操作'})

        target_yonghuid = request.data.get('yonghuid', '').strip()
        target_phone = request.data.get('phone', '').strip()
        if not target_yonghuid and not target_phone:
            return Response({'code': 400, 'msg': '缺少目标用户（yonghuid 或 phone）'})

        from jituan.services.club_rbac import resolve_kefu_admin_user
        target_user = resolve_kefu_admin_user(yonghuid=target_yonghuid, phone=target_phone)
        if not target_user:
            return Response({'code': 404, 'msg': '用户不存在或非后台账号'})
        try:
            target_kefu = target_user.KefuProfile
        except UserKefu.DoesNotExist:
            return Response({'code': 404, 'msg': '用户扩展信息缺失'})

        with transaction.atomic():
            if action == 'update_user_info':
                # 修改昵称、状态、密码、二级密码
                nicheng = request.data.get('nicheng')
                status = request.data.get('status')
                password = request.data.get('password')
                erjimima = request.data.get('erjimima')
                if nicheng is not None:
                    target_kefu.nicheng = nicheng
                if status is not None:
                    new_status = int(status)
                    target_kefu.zhuangtai = new_status
                    if new_status != 1:
                        # 禁用账号：停用全部集团/俱乐部任职，并摘掉非白名单的 IsSuperuser
                        from jituan.constants import SUPER_ADMIN_PHONES
                        from jituan.services.admin_assignments import deactivate_all_assignments_for_user
                        deactivate_all_assignments_for_user(target_user.UserUID)
                        if (target_user.Phone or '') not in SUPER_ADMIN_PHONES:
                            if target_user.IsSuperuser:
                                target_user.IsSuperuser = False
                                target_user.save(update_fields=['IsSuperuser'])
                if password:
                    if len(password) < 6:
                        return Response({'code': 400, 'msg': '密码至少6位'})
                    target_user.SetPassword(password)
                if erjimima:
                    if len(erjimima) < 6:
                        return Response({'code': 400, 'msg': '二级密码至少6位'})
                    import bcrypt as _bcrypt
                    target_kefu.erjimima = _bcrypt.hashpw(erjimima.encode('utf-8'), _bcrypt.gensalt(rounds=12)).decode('utf-8')
                target_user.save()
                target_kefu.save()
                return Response({'code': 0, 'msg': '修改成功'})

            elif action == 'add_user_roles':
                role_codes = request.data.get('role_codes', [])
                if not role_codes:
                    return Response({'code': 400, 'msg': '请选择角色'})
                from jituan.services.club_rbac import resolve_role_by_name, resolve_role_club_id
                bind_club_id = resolve_role_club_id(
                    request, (request.data.get('target_club_id') or '').strip() or None,
                )
                if not bind_club_id:
                    return Response({'code': 400, 'msg': '请先切换到具体俱乐部再分配角色'})
                if not (
                    can_manage_roles_for_club(request.user, permissions, bind_club_id)
                    or ('000001' in permissions)
                ):
                    return Response({'code': 403, 'msg': '您无权管理该俱乐部的角色分配'})
                added, missing = [], []
                for rc in role_codes:
                    role = resolve_role_by_name(rc, bind_club_id)
                    if not role:
                        missing.append(rc)
                        continue
                    role_club = (getattr(role, 'ClubID', None) or '').strip()
                    if role_club and role_club != bind_club_id:
                        missing.append(rc)
                        continue
                    _, created = UserRole.objects.get_or_create(
                        UserUUID=target_user.UserUUID,
                        RoleUUID=role.RoleUUID,
                        defaults={
                            'UserRoleUUID': uuid.uuid4().bytes,
                            'CompanyUUID': uuid.UUID('b0000000-0000-0000-0000-000000000001').bytes,
                        },
                    )
                    if created:
                        added.append(role.RoleName)
                    elif role.RoleName not in added:
                        added.append(role.RoleName)
                if not added:
                    return Response({
                        'code': 400,
                        'msg': f'未找到可绑定的角色：{", ".join(missing or role_codes)}。请确认顶栏俱乐部与角色所属俱乐部一致',
                    })
                if missing:
                    return Response({
                        'code': 0,
                        'msg': f'已绑定：{", ".join(added)}；未找到：{", ".join(missing)}',
                    })
                return Response({'code': 0, 'msg': '角色添加成功'})

            elif action == 'remove_user_role':
                role_code = request.data.get('role_code')
                if not role_code:
                    return Response({'code': 400, 'msg': '缺少角色编码'})
                from jituan.services.club_rbac import resolve_role_by_name, resolve_role_club_id
                bind_club_id = resolve_role_club_id(
                    request, (request.data.get('target_club_id') or '').strip() or None,
                )
                if not bind_club_id:
                    return Response({'code': 400, 'msg': '请先切换到具体俱乐部再操作角色'})
                if not (
                    can_manage_roles_for_club(request.user, permissions, bind_club_id)
                    or ('000001' in permissions)
                ):
                    return Response({'code': 403, 'msg': '您无权管理该俱乐部的角色分配'})
                role = resolve_role_by_name(role_code, bind_club_id)
                if not role:
                    return Response({'code': 404, 'msg': '角色不存在或与所选俱乐部不匹配'})
                UserRole.objects.filter(UserUUID=target_user.UserUUID, RoleUUID=role.RoleUUID).delete()
                return Response({'code': 0, 'msg': '角色移除成功'})

            elif action == 'add_club_assignment':
                club_id = (request.data.get('club_id') or '').strip()
                if not club_id:
                    return Response({'code': 400, 'msg': '请选择俱乐部'})
                from jituan.services.admin_assignments import create_or_reactivate_assignment
                from jituan.constants import DATA_SCOPE_SINGLE
                role_code = (request.data.get('role_code') or 'CLUB_ADMIN').strip()
                is_primary = bool(request.data.get('is_primary', False))
                _, err = create_or_reactivate_assignment(
                    yonghuid=target_user.UserUID,
                    club_id=club_id,
                    role_code=role_code,
                    data_scope=DATA_SCOPE_SINGLE,
                    is_primary=is_primary,
                    granted_by=request.user.UserUID,
                )
                if err:
                    return Response({'code': 400, 'msg': err})
                return Response({'code': 0, 'msg': '俱乐部任职已添加'})

            elif action == 'remove_club_assignment':
                assignment_id = request.data.get('assignment_id')
                if not assignment_id:
                    return Response({'code': 400, 'msg': '缺少任职 id'})
                from jituan.services.admin_assignments import deactivate_assignment
                from jituan.models import AdminAssignment
                row = AdminAssignment.query.filter(
                    id=assignment_id, yonghuid=target_user.UserUID, status=1,
                ).first()
                if not row:
                    return Response({'code': 404, 'msg': '任职记录不存在'})
                ok, err = deactivate_assignment(assignment_id)
                if not ok:
                    return Response({'code': 404, 'msg': err or '停用失败'})
                return Response({'code': 0, 'msg': '俱乐部任职已移除'})

            else:
                return Response({'code': 400, 'msg': '无效的action'})





class AddAdminUserView(APIView):
    """添加后台用户（客服账号）"""
    permission_classes = [IsAuthenticated]

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

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

        from jituan.services.admin_context import (
            can_manage_admin_assignments,
            can_manage_roles_for_club,
        )
        from jituan.services.club_context import resolve_club_id_from_request, resolve_club_scope
        from jituan.constants import DATA_SCOPE_ALL

        target_club_id = resolve_club_id_from_request(request)
        if resolve_club_scope(request) == DATA_SCOPE_ALL or not target_club_id:
            return Response({'code': 400, 'msg': '请先切换到具体俱乐部再添加用户'})
        # 俱乐部超级管理 000001 即可添加本店后台用户，无需集团权限
        if not (
            can_manage_admin_assignments(request.user, permissions)
            or can_manage_roles_for_club(request.user, permissions, target_club_id)
            or ('000001' in permissions)
        ):
            return Response({'code': 403, 'msg': '您无权在该俱乐部添加用户'})

        phone = request.data.get('phone', '').strip()
        password = request.data.get('password', '').strip()
        erjimima = request.data.get('erjimima', '').strip()
        nicheng = request.data.get('nicheng', '').strip()
        role_codes = request.data.get('role_codes', [])

        if not all([phone, password, erjimima, nicheng]):
            return Response({'code': 400, 'msg': '请填写完整信息'})
        if len(password) < 6 or len(erjimima) < 6:
            return Response({'code': 400, 'msg': '密码和二级密码至少6位'})

        from jituan.services.club_rbac import resolve_roles_for_binding

        # 校验手机号是否已被后台客服占用（同俱乐部优先）
        existing_kefu = User.query.filter(
            Phone=phone, KefuProfile__isnull=False
        ).order_by('-UserCreateTime').first()
        if existing_kefu:
            return Response({'code': 400, 'msg': '该账号已存在'})

        if not isinstance(role_codes, list):
            return Response({'code': 400, 'msg': 'role_codes 格式错误'})
        if not role_codes:
            return Response({'code': 400, 'msg': '请至少选择一个角色'})

        # 仅绑定前端所选角色（各俱乐部角色名不同，勿硬编码「客服」）
        role_names_to_bind = []
        seen_names = set()
        for name in role_codes:
            n = (name or '').strip()
            if n and n not in seen_names:
                seen_names.add(n)
                role_names_to_bind.append(n)

        roles_to_bind, missing_roles = resolve_roles_for_binding(role_names_to_bind, target_club_id)
        if missing_roles:
            return Response({
                'code': 400,
                'msg': f'角色不存在或与当前俱乐部不匹配：{", ".join(missing_roles)}',
            })
        if not roles_to_bind:
            return Response({'code': 400, 'msg': '请至少选择一个有效角色'})

        with transaction.atomic():
            # 事务内二次校验，防止并发重复创建
            if User.query.filter(Phone=phone, KefuProfile__isnull=False).exists():
                return Response({'code': 400, 'msg': '该账号已存在'})

            # 生成唯一的 yonghuid（7位数字）
            while True:
                yonghuid = str(random.randint(1000000, 9999999))
                if not User.query.filter(UserUID=yonghuid).exists():
                    break

            # 生成唯一的 openid（格式：admin_{时间戳}_{随机6位}）
            timestamp = str(int(time.time() * 1000))
            random_suffix = ''.join(random.choices(string.ascii_lowercase + string.digits, k=6))
            openid = f"admin_{timestamp}_{random_suffix}"
            while User.query.filter(OpenID=openid).exists():
                random_suffix = ''.join(random.choices(string.ascii_lowercase + string.digits, k=6))
                openid = f"admin_{timestamp}_{random_suffix}"

            user_main = User.query.create(
                UserUID=yonghuid,
                UserName=openid,
                OpenID=openid,
                Phone=phone,
                ClubID=target_club_id,
            )
            user_main.SetPassword(password)
            user_main.save(update_fields=['UserPassword', 'ClubID'])
            # 创建客服扩展表（后台用户扩展）
            import bcrypt as _bcrypt
            erjimima_hashed = _bcrypt.hashpw(erjimima.encode('utf-8'), _bcrypt.gensalt(rounds=12)).decode('utf-8')
            UserKefu.query.create(
                user=user_main,
                nicheng=nicheng,
                erjimima=erjimima_hashed,
                zhuangtai=1
            )
            for role in roles_to_bind:
                UserRole.objects.get_or_create(
                    UserUUID=user_main.UserUUID,
                    RoleUUID=role.RoleUUID,
                    defaults={
                        'UserRoleUUID': uuid.uuid4().bytes,
                        'CompanyUUID': uuid.UUID('b0000000-0000-0000-0000-000000000001').bytes,
                    },
                )

            from jituan.services.admin_assignments import create_or_reactivate_assignment
            from jituan.constants import DATA_SCOPE_SINGLE
            create_or_reactivate_assignment(
                yonghuid=yonghuid,
                club_id=target_club_id,
                role_code='CLUB_ADMIN',
                data_scope=DATA_SCOPE_SINGLE,
                is_primary=True,
                granted_by=request.user.UserUID,
            )

        return Response({'code': 0, 'msg': '添加成功'})








