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 HqbkxxView(APIView):
    """
    获取板块配置所需全部数据
    POST /houtai/hqbkxx
    Body: { "phone": "管理员手机号" }
    """
    permission_classes = [IsAuthenticated]

    def post(self, request):
        # 1. 从前端获取传递的账号，用于防越权校验
        username_from_frontend = request.data.get('phone', None)

        # 2. 调用公共验证方法
        kefu_obj, permissions = verify_kefu_permission(request, username_from_frontend)

        # 3. 如果第一个返回值为 None，说明验证失败，直接返回第二个值
        if kefu_obj is None:
            return permissions

        # ---------- 验证通过 ----------
        # 4. 检查是否有板块管理权限
        if 'bankuai' not in permissions:
            return Response({'code': 403, 'msg': '无板块管理权限'}, status=403)
        scope_err = block_non_group_catalog_scope(request)
        if scope_err:
            return Response({'code': 400, 'msg': scope_err}, status=400)

        # 5. 查询所有板块
        bankuai_list = []
        for bk in Bankuai.query.all():
            bankuai_list.append({
                'bankuai_id': bk.bankuai_id,
                'mingcheng': bk.mingcheng,
                'CreateTime': bk.CreateTime.strftime('%Y-%m-%d %H:%M:%S') if bk.CreateTime else ''
            })

        # 6. 查询所有商品类型
        shangpin_leixing_list = []
        for sp in ShangpinLeixing.query.all():
            shangpin_leixing_list.append({
                'id': sp.id,
                'jieshao': sp.jieshao,
                'tupian_url': sp.tupian_url or '',
                'bankuai_id': sp.bankuai_id
            })

        # 7. 查询会员（附带当前俱乐部售价）
        from jituan.constants import CLUB_ID_DEFAULT, DATA_SCOPE_ALL
        from jituan.models import ClubHuiyuanPrice
        from jituan.services.club_context import resolve_club_id_from_request, resolve_club_scope

        scope = resolve_club_scope(request)
        club_id = resolve_club_id_from_request(request)
        price_map = {}
        if scope != DATA_SCOPE_ALL:
            for row in ClubHuiyuanPrice.query.filter(club_id=club_id):
                price_map[row.huiyuan_id] = row

        huiyuan_list = []
        # 在受限 scope 下预过滤，避免 Huiyuan 全表遍历
        # 注：当 scope != DATA_SCOPE_ALL 且 club_id != CLUB_ID_DEFAULT 时，
        # 只有 price_map 中存在记录的会员才可能被保留（无记录的会被跳过）
        huiyuan_qs = Huiyuan.query.all()
        if scope != DATA_SCOPE_ALL and club_id != CLUB_ID_DEFAULT:
            huiyuan_qs = huiyuan_qs.filter(huiyuan_id__in=list(price_map.keys()))
        # 仅查询所需字段，减少内存占用（dict 比 model 实例更轻）
        huiyuan_qs = huiyuan_qs.values('huiyuan_id', 'jieshao', 'bankuai_id', 'jiage', 'guanshifc', 'zuzhangfc')
        for hy in huiyuan_qs:
            row = price_map.get(hy['huiyuan_id'])
            if scope != DATA_SCOPE_ALL and club_id != CLUB_ID_DEFAULT and row is None:
                continue
            if row is not None and not row.is_enabled:
                continue
            item = {
                'huiyuan_id': hy['huiyuan_id'],
                'jieshao': hy['jieshao'],
                'bankuai_id': hy['bankuai_id'],
                'jiage': str(row.jiage) if row else str(hy['jiage']),
                'guanshifc': str(row.guanshifc) if row else str(hy['guanshifc']),
                'zuzhangfc': str(row.zuzhangfc) if row else str(hy['zuzhangfc']),
            }
            huiyuan_list.append(item)

        return Response({
            'code': 0,
            'msg': 'ok',
            'data': {
                'bankuai': bankuai_list,
                'shangpin_leixing': shangpin_leixing_list,
                'huiyuan': huiyuan_list,
                'club_id': club_id,
                'scope': scope,
            }
        })


class BkxgView(APIView):
    """
    板块增删改统一接口
    POST /houtai/bkxg
    Body: {
        "phone": "管理员手机号",
        "action": "create | update | delete | add_items | remove_items",
        "bankuai_id": int,
        "bankuai_name": str,
        "item_type": "shangpin_leixing | huiyuan",
        "item_ids": [1,2,3]
    }
    """
    permission_classes = [IsAuthenticated]

    def post(self, request):
        # 1. 从前端获取传递的账号
        username_from_frontend = request.data.get('phone', None)

        # 2. 调用公共验证方法
        kefu_obj, permissions = verify_kefu_permission(request, username_from_frontend)

        # 3. 验证失败直接返回
        if kefu_obj is None:
            return permissions

        # 4. 检查板块管理权限
        if 'bankuai' not in permissions:
            return Response({'code': 403, 'msg': '无板块管理权限'}, status=403)
        scope_err = block_non_group_catalog_scope(request)
        if scope_err:
            return Response({'code': 400, 'msg': scope_err}, status=400)

        # 5. 获取操作类型
        action = request.data.get('action')
        if not action:
            return Response({'code': 1, 'msg': '缺少 action 参数'}, status=400)

        # ==================== 创建板块 ====================
        if action == 'create':
            bankuai_name = request.data.get('bankuai_name', '').strip()
            if not bankuai_name:
                return Response({'code': 1, 'msg': '板块名称不能为空'}, status=400)
            if Bankuai.query.filter(mingcheng=bankuai_name).exists():
                return Response({'code': 1, 'msg': '板块名称已存在'}, status=400)

            shangpin_ids = request.data.get('shangpin_ids', [])
            huiyuan_ids = request.data.get('huiyuan_ids', [])

            with transaction.atomic():
                new_bk = Bankuai.query.create(mingcheng=bankuai_name)
                if shangpin_ids:
                    ShangpinLeixing.query.filter(
                        id__in=shangpin_ids,
                        bankuai__isnull=True
                    ).update(bankuai=new_bk)
                if huiyuan_ids:
                    Huiyuan.query.filter(
                        huiyuan_id__in=huiyuan_ids,
                        bankuai__isnull=True
                    ).update(bankuai=new_bk)

            return Response({
                'code': 0,
                'msg': '创建成功',
                'data': {'bankuai_id': new_bk.bankuai_id}
            })

        # ==================== 以下操作需要 bankuai_id ====================
        raw_bankuai_id = request.data.get('bankuai_id')
        if raw_bankuai_id is None or str(raw_bankuai_id).strip() == '':
            return Response({'code': 1, 'msg': '缺少 bankuai_id'}, status=400)
        try:
            bankuai_id = int(raw_bankuai_id)
        except (TypeError, ValueError):
            return Response({'code': 1, 'msg': '无效的 bankuai_id'}, status=400)

        try:
            bk = Bankuai.query.get(bankuai_id=bankuai_id)
        except Bankuai.DoesNotExist:
            return Response({'code': 1, 'msg': '板块不存在'}, status=404)

        # ==================== 修改板块名称 ====================
        if action == 'update':
            new_name = request.data.get('bankuai_name', '').strip()
            if not new_name:
                return Response({'code': 1, 'msg': '板块名称不能为空'}, status=400)
            if Bankuai.query.filter(mingcheng=new_name).exclude(bankuai_id=bankuai_id).exists():
                return Response({'code': 1, 'msg': '板块名称已存在'}, status=400)
            bk.mingcheng = new_name
            bk.save()
            return Response({'code': 0, 'msg': '修改成功'})

        # ==================== 删除板块 ====================
        elif action == 'delete':
            with transaction.atomic():
                ShangpinLeixing.query.filter(bankuai=bk).update(bankuai=None)
                Huiyuan.query.filter(bankuai=bk).update(bankuai=None)
                bk.delete()
            return Response({'code': 0, 'msg': '删除成功'})

        # ==================== 添加绑定 ====================
        elif action == 'add_items':
            item_type = request.data.get('item_type')
            item_ids = request.data.get('item_ids', [])
            if not item_type or not item_ids:
                return Response({'code': 1, 'msg': '缺少 item_type 或 item_ids'}, status=400)

            if item_type == 'shangpin_leixing':
                ShangpinLeixing.query.filter(
                    id__in=item_ids,
                    bankuai__isnull=True
                ).update(bankuai=bk)
            elif item_type == 'huiyuan':
                Huiyuan.query.filter(
                    huiyuan_id__in=item_ids,
                    bankuai__isnull=True
                ).update(bankuai=bk)
            else:
                return Response({'code': 1, 'msg': '无效的 item_type'}, status=400)
            return Response({'code': 0, 'msg': '添加成功'})

        # ==================== 移除绑定 ====================
        elif action == 'remove_items':
            item_type = request.data.get('item_type')
            item_ids = request.data.get('item_ids', [])
            if not item_type or not item_ids:
                return Response({'code': 1, 'msg': '缺少 item_type 或 item_ids'}, status=400)

            if item_type == 'shangpin_leixing':
                ShangpinLeixing.query.filter(
                    id__in=item_ids,
                    bankuai=bk
                ).update(bankuai=None)
            elif item_type == 'huiyuan':
                Huiyuan.query.filter(
                    huiyuan_id__in=item_ids,
                    bankuai=bk
                ).update(bankuai=None)
            else:
                return Response({'code': 1, 'msg': '无效的 item_type'}, status=400)
            return Response({'code': 0, 'msg': '移除成功'})

        else:
            return Response({'code': 1, 'msg': '未知操作'}, status=400)            









