"""商家充值与充值抵扣视图。

包含商家充值支付参数/回调/失败/成功轮询，以及充值打手抵押查询与抵扣接口。
含模块级常量 INTEGRAL_PRICE / INTEGRAL_INCREMENT / MAX_INTEGRAL / IDENTITY_CONFIG。
"""
# ==================== 标准库 ====================
import os
import json
import time
import random
import string
import uuid
import hashlib
import requests
import logging
import decimal
from datetime import timedelta
from decimal import Decimal, InvalidOperation, ROUND_CEILING
import defusedxml.ElementTree as ET

# ==================== Django 内置 ====================
from django.conf import settings
from django.db import transaction, connection
from django.db.models import Q
from gvsdsdk.fluent import db, func, FQ
from django.shortcuts import render, get_object_or_404
from django.http import HttpResponse
from django.utils import timezone

# ==================== DRF 框架 ====================
from rest_framework.views import APIView, View
from rest_framework.response import Response
from rest_framework import permissions, status
from rest_framework.permissions import AllowAny, IsAuthenticated
from rest_framework.parsers import MultiPartParser, FormParser, JSONParser
from rest_framework.throttling import AnonRateThrottle

# ==================== 项目工具函数 ====================
from utils.oss_utils import validate_image, upload_to_oss, delete_from_oss
from utils.money import format_yuan, quantize_yuan, yuan_to_fen
from backend.utils import (
    update_guanshi_daily_by_action,
    update_guanshi_xufei_daily,
    update_zuzhang_daily_by_action
)
from users.fadan_fenhong_utils import process_fadan_fenhong

# ==================== 各App模型 ====================
from ..models import (
    ShangpinLeixing, ShangpinZhuanqu, Shangpin, Huiyuan,
    Czjilu, Gsfenhong, Huiyuangoumai, DuociFenhong
)
from users.models import (
    AdminProfile, UserDashou, UserGuanshi, UserZuzhang, UserShangjia
)
from users.business_models import User

from orders.models import CommissionRate
from config.models import Gonggao, Lunbo

from orders.models import Penalty  # 用于罚款类型
from jituan.services.club_config import (
    get_commission_rate,
    get_commission_rate_object,
    get_huiyuan_price,
    get_huiyuan_fenchong,
)
from jituan.services.club_context import resolve_effective_club_id
from jituan.services.club_write import resolve_club_id_for_write
from jituan.services.club_user import get_payment_openid
from jituan.services.club_penalty import resolve_gsfenhong_club_id

import traceback

# ==================== 日志实例 ====================
logger = logging.getLogger(__name__)


class ShangjiaChongzhi(APIView):
    """
    商家余额充值支付参数接口
    路径：/shangpin/sjcz
    请求方式：POST
    权限：JWT认证
    参数：jine（金额，1-10000元）
    返回：支付参数(payParams)和订单ID(dingdanid)
    """
    permission_classes = [IsAuthenticated]

    def post(self, request):
        try:
            # 1. 验证用户身份和商家状态
            try:
                shangjia = request.user.ShopProfile
            except UserShangjia.DoesNotExist:
                logger.warning(f"用户{request.user.UserUID}尝试充值但不是商家")
                return Response({
                    'code': 400,
                    'message': '用户不是商家，无法充值'
                }, status=status.HTTP_400_BAD_REQUEST)

            # 检查商家状态
            if shangjia.zhuangtai != 1:
                logger.warning(f"商家{shangjia.nicheng}状态异常: {shangjia.zhuangtai}")
                return Response({
                    'code': 400,
                    'message': '商家状态异常，无法进行充值'
                }, status=status.HTTP_400_BAD_REQUEST)

            # 2. 获取并验证金额参数
            jine = request.data.get('jine')
            if not jine:
                return Response({
                    'code': 400,
                    'message': '请填写充值金额'
                }, status=status.HTTP_400_BAD_REQUEST)

            try:
                jine = quantize_yuan(jine)
            except (ValueError, TypeError, InvalidOperation):
                return Response({
                    'code': 400,
                    'message': '金额格式错误，请填写有效的数字'
                }, status=status.HTTP_400_BAD_REQUEST)

            # 验证金额范围
            if jine < settings.SHANGJIA_CZ_MIN_AMOUNT or jine > settings.SHANGJIA_CZ_MAX_AMOUNT:
                return Response({
                    'code': 400,
                    'message': f'充值金额必须在{settings.SHANGJIA_CZ_MIN_AMOUNT}-{settings.SHANGJIA_CZ_MAX_AMOUNT}元之间'
                }, status=status.HTTP_400_BAD_REQUEST)

            pay_method = (request.data.get('pay_method') or request.data.get('payMethod') or 'wechat').lower()
            from jituan.services.alipay_pay import alipay_pay_method_block_reason
            pay_club = resolve_club_id_for_write(request, request.user)
            _alipay_block = alipay_pay_method_block_reason(pay_method, pay_club)
            if _alipay_block:
                return Response({
                    'code': 400,
                    'message': _alipay_block,
                }, status=status.HTTP_400_BAD_REQUEST)

            # 3. 生成订单ID（使用配置的前缀）
            timestamp_ms = int(time.time() * 1000)
            timestamp_ns = int(time.time_ns() // 1000) % 1000000
            random_num = random.randint(0, 99)

            dingdanid = f"{settings.SHANGJIA_CZ_PREFIX}{timestamp_ms:011d}{timestamp_ns:06d}{random_num:02d}"

            # 4. 创建充值记录订单
            try:
                chongzhi_jilu = Czjilu.query.create(
                    dingdan_id=dingdanid,
                    zhuangtai=9,  # 未支付状态
                    yonghuid=request.user.UserUID,
                    jine=jine,
                    leixing=4,  # 充值类型：4=商家充值
                    shuoming=settings.SHANGJIA_CZ_PAY_DESCRIPTION,
                    club_id=pay_club,
                )
                logger.info(f"创建商家充值订单: 商家{shangjia.nicheng}, 订单{dingdanid}, 金额{jine}元")
            except Exception as e:
                logger.error(f"创建订单失败: {str(e)}")
                return Response({
                    'code': 500,
                    'message': '订单创建失败，请重试'
                }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

            # 5. 生成支付参数（支持支付宝/微信）
            if pay_method == 'alipay':
                try:
                    from jituan.services.alipay_pay import generate_alipay_czjilu_pay_params
                    pay_params = generate_alipay_czjilu_pay_params(
                        dingdanid=dingdanid,
                        jine=jine,
                        subject=settings.SHANGJIA_CZ_PAY_DESCRIPTION,
                        club_id=pay_club,
                    )
                except Exception as e:
                    chongzhi_jilu.delete()
                    logger.error(f"生成支付宝支付参数失败: {str(e)}")
                    return Response({
                        'code': 500,
                        'message': f'支付参数生成失败: {str(e)}'
                    }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
            else:
                try:
                    pay_openid, _ = get_payment_openid(request, club_id=pay_club)
                    if not pay_openid:
                        chongzhi_jilu.delete()
                        return Response({
                            'code': 400,
                            'message': '当前小程序未绑定微信openid，请退出后重新登录再支付',
                        }, status=status.HTTP_400_BAD_REQUEST)
                    pay_params = self.generate_wechat_pay_params(
                        dingdanid=dingdanid,
                        jine=jine,
                        openid=pay_openid,
                        pay_type='shangjia'
                    )
                except Exception as e:
                    # 支付参数生成失败，删除订单记录
                    chongzhi_jilu.delete()
                    logger.error(f"生成微信支付参数失败: {str(e)}")
                    return Response({
                        'code': 500,
                        'message': f'支付参数生成失败: {str(e)}'
                    }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

            # 6. 返回支付参数和订单ID
            logger.info(f"商家{shangjia.nicheng}支付参数生成成功: {dingdanid}")
            return Response({
                'code': 200,
                'message': '支付参数生成成功',
                'payParams': pay_params,
                'dingdanid': dingdanid
            }, status=status.HTTP_200_OK)

        except Exception as e:
            logger.error(f"商家充值接口异常: {str(e)}", exc_info=True)
            return Response({
                'code': 500,
                'message': '服务器内部错误，请稍后重试'
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

    def generate_wechat_pay_params(self, dingdanid, jine, openid, pay_type):
        """生成微信小程序支付参数"""
        # 获取配置
        from jituan.services.club_write import resolve_club_id_for_write
        from jituan.services.wechat_pay import get_wechat_v2_config
        pay_cfg = get_wechat_v2_config(resolve_club_id_for_write(self.request, self.request.user))
        APPID = pay_cfg['appid']
        MCHID = pay_cfg['mch_id']
        KEY = pay_cfg['key']

        # 根据支付类型获取对应的配置
        if pay_type == 'shangjia':
            PAY_DESCRIPTION = settings.SHANGJIA_CZ_PAY_DESCRIPTION
            NOTIFY_URL = settings.SHANGJIA_CZ_PAY_NOTIFY_URL
        else:
            raise Exception('未知的支付类型')

        from jituan.constants import FUBEI_BIZ_CZJILU
        from jituan.services.mini_pay_router import maybe_create_fubei_jsapi_params
        _club = resolve_club_id_for_write(self.request, self.request.user)
        fb_params = maybe_create_fubei_jsapi_params(
            club_id=_club,
            out_trade_no=dingdanid,
            amount_yuan=jine,
            body=PAY_DESCRIPTION,
            openid=openid,
            notify_url=NOTIFY_URL,
            biz_type=FUBEI_BIZ_CZJILU,
        )
        if fb_params is not None:
            return fb_params

        # 生成随机字符串
        nonce_str = ''.join(random.choices(string.ascii_letters + string.digits, k=32))

        # 金额转换（元转分）
        total_fee = yuan_to_fen(jine)

        # 交易类型（小程序支付使用JSAPI）
        trade_type = 'JSAPI'

        # 获取客户端IP
        user_ip = self.get_client_ip()

        # 1. 第一次签名（统一下单接口）
        sign_data = {
            'appid': APPID,
            'mch_id': MCHID,
            'nonce_str': nonce_str,
            'body': PAY_DESCRIPTION,
            'out_trade_no': dingdanid,
            'total_fee': total_fee,
            'spbill_create_ip': user_ip,
            'notify_url': NOTIFY_URL,
            'trade_type': trade_type,
            'openid': openid  # 小程序支付必须传openid
        }

        # 按照参数名ASCII码从小到大排序
        sorted_sign_data = sorted(sign_data.items(), key=lambda x: x[0])

        # 拼接字符串
        sign_string = '&'.join([f"{key}={value}" for key, value in sorted_sign_data if value])
        sign_string += f'&key={KEY}'

        # MD5签名
        sign = hashlib.md5(sign_string.encode('utf-8')).hexdigest().upper()

        # 构造XML数据
        xml_data = f"""<xml>
<appid>{APPID}</appid>
<body>{PAY_DESCRIPTION}</body>
<mch_id>{MCHID}</mch_id>
<nonce_str>{nonce_str}</nonce_str>
<notify_url>{NOTIFY_URL}</notify_url>
<openid>{openid}</openid>
<out_trade_no>{dingdanid}</out_trade_no>
<spbill_create_ip>{user_ip}</spbill_create_ip>
<total_fee>{total_fee}</total_fee>
<trade_type>{trade_type}</trade_type>
<sign>{sign}</sign>
</xml>"""

        # 调用微信统一下单接口
        response = requests.post(
            'https://api.mch.weixin.qq.com/pay/unifiedorder',
            data=xml_data.encode('utf-8'),
            headers={'Content-Type': 'application/xml'},
            timeout=10
        )

        # 解析返回的XML
        root = ET.fromstring(response.content)

        return_code = root.find('return_code').text
        result_code = root.find('result_code').text

        if return_code == 'SUCCESS' and result_code == 'SUCCESS':
            # 获取prepay_id
            prepay_id = root.find('prepay_id').text

            # 2. 第二次签名（小程序支付参数）
            timestamp = str(int(time.time()))
            nonce_str = ''.join(random.choices(string.ascii_letters + string.digits, k=32))
            package = f'prepay_id={prepay_id}'
            sign_type = 'MD5'

            # 生成支付签名
            pay_sign_data = {
                'appId': APPID,
                'timeStamp': timestamp,
                'nonceStr': nonce_str,
                'package': package,
                'signType': sign_type
            }

            sorted_pay_sign_data = sorted(pay_sign_data.items(), key=lambda x: x[0])
            pay_sign_string = '&'.join([f"{key}={value}" for key, value in sorted_pay_sign_data])
            pay_sign_string += f'&key={KEY}'
            pay_sign = hashlib.md5(pay_sign_string.encode('utf-8')).hexdigest().upper()

            # 返回前端需要的支付参数
            return {
                'appId': APPID,
                'timeStamp': timestamp,
                'nonceStr': nonce_str,
                'package': package,
                'signType': sign_type,
                'paySign': pay_sign
            }
        else:
            # 获取错误信息
            err_code = root.find('err_code')
            err_code_des = root.find('err_code_des')
            return_msg = root.find('return_msg')

            error_details = f"return_code: {return_code}"
            if err_code is not None:
                error_details += f", err_code: {err_code.text}"
            if err_code_des is not None:
                error_details += f", err_code_des: {err_code_des.text}"
            if return_msg is not None:
                error_details += f", return_msg: {return_msg.text}"

            raise Exception(f"微信支付下单失败: {error_details}")

    def get_client_ip(self):
        """获取客户端IP"""
        request = self.request
        x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
        if x_forwarded_for:
            ip = x_forwarded_for.split(',')[0]
        else:
            ip = request.META.get('REMOTE_ADDR')
        return ip if ip else '127.0.0.1'





class ShangjiaHuitiao(View):
    """
    商家支付回调接口
    路径：/shangpin/sjhuitiao
    注意：这个接口不需要JWT认证，由微信服务器调用
    """

    def post(self, request):
        try:
            # 1. 解析微信回调XML数据
            request_body = request.body
            logger.info(f"收到商家支付回调，原始数据: {request_body.decode('utf-8')}")

            root = ET.fromstring(request_body)

            # 获取关键字段
            return_code = root.find('return_code').text
            result_code = root.find('result_code').text
            out_trade_no = root.find('out_trade_no').text  # 订单ID
            transaction_id = root.find('transaction_id').text  # 微信交易号
            total_fee = int(root.find('total_fee').text)  # 支付金额（分）

            logger.info(f"商家回调数据解析: 订单{out_trade_no}, 状态{return_code}/{result_code}, 金额{total_fee}分")

            # 2. 验证基本返回状态
            if return_code != 'SUCCESS' or result_code != 'SUCCESS':
                logger.warning(f"商家支付回调状态异常: {return_code}/{result_code}")
                return self.wechat_response('FAIL', '支付失败')

            # 3. 验证签名（确保是微信发来的）
            from jituan.services.wechat_pay import club_id_from_czjilu, verify_wechat_v2_signature
            notify_club = club_id_from_czjilu(out_trade_no)
            if not verify_wechat_v2_signature(request_body, notify_club):
                logger.error(f"商家支付签名验证失败: {out_trade_no}")
                return self.wechat_response('FAIL', '签名验证失败')

            # 4. 查询订单
            try:
                order = Czjilu.query.get(dingdan_id=out_trade_no)
                logger.info(f"找到商家订单: {order.dingdan_id}, 状态: {order.zhuangtai}, 金额: {order.jine}")
            except Czjilu.DoesNotExist:
                logger.error(f"商家订单不存在: {out_trade_no}")
                return self.wechat_response('FAIL', '订单不存在')

            from products.czjilu_types import is_merchant_recharge_czjilu
            if not is_merchant_recharge_czjilu(order):
                logger.error(
                    '非商家充值订单误入商家回调: %s, leixing=%s, shuoming=%s',
                    out_trade_no, order.leixing, order.shuoming,
                )
                return self.wechat_response('FAIL', '订单类型错误')

            # 5. 检查订单状态是否为未支付（9）
            if order.zhuangtai != 9:
                logger.warning(f"商家订单状态不是未支付: {order.dingdan_id}, 当前状态: {order.zhuangtai}")
                try:
                    from jituan.services.szjilu_accounting import repair_wechat_income_if_missing
                    repair_wechat_income_if_missing(
                        Decimal(str(order.jine)),
                        getattr(order, 'club_id', None),
                        biz_ref=f'cz:{order.dingdan_id}',
                    )
                except Exception as exc:
                    logger.error('商家回调补记收支失败 %s: %s', out_trade_no, exc, exc_info=True)
                return self.wechat_response('SUCCESS', 'OK')

            # 6. 验证金额（微信返回的是分，需要转换）
            wechat_amount_yuan = total_fee / 100  # 转换为元
            order_amount_yuan = float(order.jine)  # 订单金额（元）

            # 允许1分钱的误差（浮点数比较）
            if abs(wechat_amount_yuan - order_amount_yuan) > 0.01:
                logger.error(f"商家订单金额不一致: 订单金额{order_amount_yuan}元, 支付金额{wechat_amount_yuan}元")
                return self.wechat_response('FAIL', '金额不一致')

            # 7. 调用统一履约函数（事务 + 行锁 + 幂等 + 收支记录）
            from jituan.services.czjilu_fulfill import fulfill_shangjia, CzjiluFulfillError
            try:
                fulfill_shangjia(out_trade_no, paid_amount_yuan=wechat_amount_yuan)
            except CzjiluFulfillError as exc:
                logger.error('商家充值回调履约失败 %s: %s', out_trade_no, exc)
                return self.wechat_response('FAIL', str(exc))

            # 8. 返回成功响应给微信
            logger.info(f"商家支付回调处理完成: {out_trade_no}")
            return self.wechat_response('SUCCESS', 'OK')

        except ET.ParseError as e:
            logger.error(f"XML解析失败: {str(e)}")
            return self.wechat_response('FAIL', '数据格式错误')
        except Exception as e:
            logger.error(f"商家支付回调处理异常: {str(e)}", exc_info=True)
            # 返回FAIL让微信重试
            return self.wechat_response('FAIL', '处理异常')

    def verify_signature(self, xml_data):
        """验证微信支付签名"""
        try:
            root = ET.fromstring(xml_data)
            sign = root.find('sign').text

            if not sign:
                logger.error("签名字段不存在")
                return False

            # 获取所有参数并排除sign
            params = {}
            for child in root:
                if child.tag != 'sign' and child.text is not None:
                    params[child.tag] = child.text

            # 按照参数名ASCII码从小到大排序
            sorted_params = sorted(params.items(), key=lambda x: x[0])

            # 拼接字符串
            sign_string = '&'.join([f"{key}={value}" for key, value in sorted_params if value])
            sign_string += f'&key={settings.WEIXIN_SHANGHUMIYAO}'

            # 计算签名
            calculated_sign = hashlib.md5(sign_string.encode('utf-8')).hexdigest().upper()

            is_valid = sign == calculated_sign
            if not is_valid:
                logger.error(f"商家支付签名验证失败: 计算签名{calculated_sign}, 收到签名{sign}")

            return is_valid

        except Exception as e:
            logger.error(f"验证签名异常: {str(e)}")
            return False

    def wechat_response(self, return_code, return_msg):
        """返回微信支付回调响应"""
        xml_response = f"""<xml>
<return_code><![CDATA[{return_code}]]></return_code>
<return_msg><![CDATA[{return_msg}]]></return_msg>
</xml>"""

        logger.info(f"返回微信响应: {return_code} - {return_msg}")
        return HttpResponse(xml_response, content_type='application/xml')




# views.py
class ShangjiaShibai(APIView):
    """
    商家支付失败处理接口
    路径：/shangpin/sjshibai
    请求方式：POST
    权限：JWT认证
    参数：dingdanid（订单ID）
    返回：删除结果
    """
    permission_classes = [IsAuthenticated]

    def post(self, request):
        try:
            # 1. 获取订单ID
            dingdanid = request.data.get('dingdanid')
            if not dingdanid:
                return Response({
                    'code': 400,
                    'message': '订单ID不能为空'
                }, status=status.HTTP_400_BAD_REQUEST)

            # 2. 查询订单（确保是当前用户的订单）
            try:
                order = Czjilu.query.get(
                    dingdan_id=dingdanid,
                    yonghuid=request.user.UserUID,
                    leixing=4  # 确保是商家充值订单
                )
            except Czjilu.DoesNotExist:
                logger.warning(f"商家订单不存在或不属于当前用户: {dingdanid}, 用户{request.user.UserUID}")
                return Response({
                    'code': 400,
                    'message': '订单不存在或不属于当前用户'
                }, status=status.HTTP_400_BAD_REQUEST)

            # 3. 检查订单状态是否为未支付（9）：关单不删
            if order.zhuangtai == 9:
                from products.czjilu_types import close_unpaid_czjilu
                close_unpaid_czjilu(order, reason='用户取消支付')
                logger.info(f"商家{request.user.ShopProfile.nicheng}关闭未支付订单(不删): {dingdanid}")

                return Response({
                    'code': 200,
                    'message': '订单已取消'
                }, status=status.HTTP_200_OK)
            else:
                return Response({
                    'code': 400,
                    'message': '订单状态不是未支付，无法取消'
                }, status=status.HTTP_400_BAD_REQUEST)

        except UserShangjia.DoesNotExist:
            return Response({
                'code': 400,
                'message': '用户不是商家'
            }, status=status.HTTP_400_BAD_REQUEST)
        except Exception as e:
            logger.error(f"商家支付失败处理异常: {str(e)}", exc_info=True)
            return Response({
                'code': 500,
                'message': '服务器内部错误'
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)



# views.py
class ShangjiaChenggong(APIView):
    """
    商家支付成功轮询接口
    路径：/shangpin/sjcg
    请求方式：POST
    权限：JWT认证
    参数：dingdanid（订单ID）
    返回：订单状态和当前商家余额
    """
    permission_classes = [IsAuthenticated]

    def post(self, request):
        try:
            # 1. 获取订单ID
            dingdanid = request.data.get('dingdanid')
            if not dingdanid:
                return Response({
                    'code': 400,
                    'message': '订单ID不能为空'
                }, status=status.HTTP_400_BAD_REQUEST)

            # 2. 查询订单（确保是当前用户的商家订单）
            try:
                order = Czjilu.query.get(
                    dingdan_id=dingdanid,
                    yonghuid=request.user.UserUID,
                    leixing=4  # 商家充值类型
                )
            except Czjilu.DoesNotExist:
                logger.warning(f"商家订单不存在: {dingdanid}, 用户{request.user.UserUID}")
                return Response({
                    'code': 400,
                    'message': '订单不存在或不属于当前用户'
                }, status=status.HTTP_400_BAD_REQUEST)

            # 3. 未支付/已关单时，尝试补偿履约（回调延迟/失败时通过轮询兜底）
            from products.czjilu_types import is_czjilu_fulfillable_status
            if is_czjilu_fulfillable_status(order.zhuangtai):
                from jituan.services.czjilu_fulfill import confirm_czjilu_paid, CzjiluFulfillError
                try:
                    confirm_czjilu_paid(dingdanid, request.user.UserUID, expected_leixing=4)
                    order = Czjilu.query.get(
                        dingdan_id=dingdanid,
                        yonghuid=request.user.UserUID,
                        leixing=4
                    )
                except CzjiluFulfillError as exc:
                    logger.info(f"商家充值确认未就绪 {dingdanid}: {exc}")
                    return Response({
                        'code': 400,
                        'message': '订单尚未支付完成'
                    }, status=status.HTTP_200_OK)

            # 4. 检查订单状态是否为已支付（3）
            if order.zhuangtai != 3:
                logger.info(f"商家订单{dingdanid}尚未支付完成，当前状态: {order.zhuangtai}")
                return Response({
                    'code': 400,
                    'message': '订单尚未支付完成'
                }, status=status.HTTP_200_OK)

            # 5. 获取商家余额（通过反向查询）
            try:
                shangjia = request.user.ShopProfile
                yue = float(shangjia.yue)  # 转为浮点数方便前端处理

                logger.info(f"商家轮询成功: 订单{dingdanid}已支付，商家{shangjia.nicheng}余额为{yue}元")

                return Response({
                    'code': 200,
                    'message': '支付流程全部完成',
                    'yue': yue  # 返回当前商家余额（前端需要更新全局变量）
                }, status=status.HTTP_200_OK)

            except UserShangjia.DoesNotExist:
                logger.error(f"商家信息不存在: 用户{request.user.UserUID}")
                return Response({
                    'code': 400,
                    'message': '商家信息不存在'
                }, status=status.HTTP_400_BAD_REQUEST)

        except Exception as e:
            logger.error(f"商家轮询异常: {str(e)}", exc_info=True)
            return Response({
                'code': 500,
                'message': '服务器内部错误'
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)


# 管事分红记录查询API



INTEGRAL_PRICE = Decimal('5.00')  # 积分购买固定价格（元）


class CzhqdyView(APIView):
    """
    获取可用抵扣身份接口
    路径：/shangpin/czhqdy
    方法：POST
    权限：JWT认证
    请求参数：
        leixing: int  # 1=会员，2=押金，3=积分，4=罚款
        huiyuan_id: str  # 当 leixing=1 时必传，会员ID
        yajin_jine: decimal  # 当 leixing=2 时必传，押金金额（元）
        fadan_id: int      # 当 leixing=4 时必传，罚单ID
    返回：
        {
            "code": 200,
            "msg": "success",
            "data": [
                {
                    "id": 1,               # 身份ID：1打手佣金 2管事分红 3组长分红 4打手押金
                    "jieshao": "打手佣金抵扣",
                    "xuyao": "22.22"         # 所需抵扣金额（保留两位小数）
                },
                ...
            ]
        }
    """
    permission_classes = [permissions.IsAuthenticated]

    # 身份ID与对应扩展表模型、余额字段、费率查询条件的映射
    IDENTITY_CONFIG = [
        {
            'id': 1,
            'name': '打手佣金抵扣',
            'profile_attr': 'DashouProfile',  # User 的反向 related_name
            'balance_field': 'yue',
            'rate_key': '5',
            'model': UserDashou,
        },
        {
            'id': 2,
            'name': '管事分红抵扣',
            'profile_attr': 'GuanshiProfile',
            'balance_field': 'yue',
            'rate_key': '6',
            'model': UserGuanshi,
        },
        {
            'id': 3,
            'name': '组长分红抵扣',
            'profile_attr': 'ZuzhangProfile',
            'balance_field': 'ketixian_jine',
            'rate_key': '8',
            'model': UserZuzhang,
        },
        # 新增打手押金抵扣
        {
            'id': 4,
            'name': '打手押金抵扣',
            'profile_attr': 'DashouProfile',   # 与打手佣金共用扩展表
            'balance_field': 'yajin',           # 押金字段
            'rate_key': '11',                   # 押金提现费率对应的 Platform
            'model': UserDashou,
        },
    ]

    def post(self, request):
        # 获取参数
        leixing = request.data.get('leixing')
        huiyuan_id = request.data.get('huiyuan_id')
        yajin_jine = request.data.get('yajin_jine')
        fadan_id = request.data.get('fadan_id')
        is_trial = bool(request.data.get('is_trial') or request.data.get('isTrial'))

        # 参数校验
        if leixing not in [1, 2, 3, 4]:
            return Response({'code': 400, 'msg': 'leixing 必须为 1,2,3,4'}, status=status.HTTP_400_BAD_REQUEST)

        if leixing == 1 and not huiyuan_id:
            return Response({'code': 400, 'msg': '购买会员时必须提供 huiyuan_id'}, status=status.HTTP_400_BAD_REQUEST)

        if leixing == 1 and is_trial:
            return Response({
                'code': 400,
                'msg': '体验会员仅支持微信支付，不可用佣金、分红或押金抵扣',
            }, status=status.HTTP_400_BAD_REQUEST)

        if leixing == 2:
            if not yajin_jine:
                return Response({'code': 400, 'msg': '购买押金时必须提供 yajin_jine'}, status=status.HTTP_400_BAD_REQUEST)
            try:
                yajin_jine = Decimal(str(yajin_jine))
                if yajin_jine <= 0:
                    raise ValueError
            except:
                return Response({'code': 400, 'msg': 'yajin_jine 必须为正数'}, status=status.HTTP_400_BAD_REQUEST)

        if leixing == 4 and not fadan_id:
            return Response({'code': 400, 'msg': '缴纳罚款时必须提供 fadan_id'}, status=status.HTTP_400_BAD_REQUEST)

        # 获取当前用户
        user = request.user

        # 获取目标价格（需支付的原价）
        target_price = None
        if leixing == 1:
            # 会员
            try:
                huiyuan = Huiyuan.query.get(huiyuan_id=huiyuan_id)
                club_id = resolve_effective_club_id(request, request.user)
                target_price = get_huiyuan_price(club_id, huiyuan_id, huiyuan)
            except Huiyuan.DoesNotExist:
                return Response({'code': 404, 'msg': '会员不存在'}, status=status.HTTP_404_NOT_FOUND)
        elif leixing == 2:
            # 押金
            target_price = yajin_jine
        elif leixing == 3:
            # 积分（固定价格）
            target_price = INTEGRAL_PRICE
        elif leixing == 4:
            # 罚款缴纳
            try:
                fadan = Penalty.query.get(id=fadan_id, PenalizedUserID=user.UserUID)
                target_price = fadan.FineAmount
            except Penalty.DoesNotExist:
                return Response({'code': 404, 'msg': '罚单不存在或不属于当前用户'}, status=status.HTTP_404_NOT_FOUND)

        # 获取所有费率（打手佣金、管事分红、组长分红、打手押金）
        rates = {}
        club_id = resolve_effective_club_id(request, request.user)
        for key in ['5', '6', '8', '11']:
            rates[key] = get_commission_rate(club_id, key)

        # 构建可用身份列表
        available_list = []

        for ident in self.IDENTITY_CONFIG:
            # 检查用户是否有该扩展表
            profile = getattr(user, ident['profile_attr'], None)
            if not profile:
                continue

            # 获取余额
            balance = getattr(profile, ident['balance_field'], Decimal('0.00'))

            # 获取费率
            rate = rates.get(ident['rate_key'])
            if rate is None:
                continue  # 费率未配置，跳过该身份

            # 计算所需抵扣金额： target_price / (1 - rate) ，向上取整到分
            try:
                if rate >= 1:
                    continue  # 防止除零及不合理费率
                required = target_price / (Decimal('1.0') - rate)
                # 向上取整到分（保留两位小数，最后一位进位）
                required = required.quantize(Decimal('0.01'), rounding=ROUND_CEILING)
            except Exception:
                continue  # 计算异常，跳过

            # 余额是否足够
            if balance >= required:
                available_list.append({
                    'id': ident['id'],
                    'jieshao': ident['name'],
                    'xuyao': str(required),
                })

        return Response({
            'code': 200,
            'msg': 'success',
            'data': available_list
        })



INTEGRAL_INCREMENT = 5
MAX_INTEGRAL = 10

IDENTITY_CONFIG = {
    1: {
        'name': '打手佣金',
        'model': UserDashou,
        'balance_field': 'yue',
        'status_field': 'zhanghaozhuangtai',
        'rate_key': '5',
    },
    2: {
        'name': '管事分红',
        'model': UserGuanshi,
        'balance_field': 'yue',
        'status_field': 'zhuangtai',
        'rate_key': '6',
    },
    3: {
        'name': '组长分红',
        'model': UserZuzhang,
        'balance_field': 'ketixian_jine',
        'status_field': 'zhuangtai',
        'rate_key': '8',
    },
    4: {
        'name': '打手押金',
        'model': UserDashou,
        'balance_field': 'yajin',
        'status_field': 'zhanghaozhuangtai',
        'rate_key': '11',
    },
}


class DsqrgmdhView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    def post(self, request):
        from jituan.services.member_recharge import MemberRechargeError
        try:
            leixing = request.data.get('leixing')
            shenfen_id = request.data.get('shenfen_id')
            huiyuan_id = request.data.get('huiyuan_id')
            yajin_jine = request.data.get('yajin_jine')
            fadan_id = request.data.get('fadan_id')

            is_trial = bool(request.data.get('is_trial') or request.data.get('isTrial'))

            logger.info(f"抵扣支付请求: leixing={leixing}, shenfen_id={shenfen_id}, huiyuan_id={huiyuan_id}, yajin_jine={yajin_jine}, fadan_id={fadan_id}, is_trial={is_trial}")

            if leixing not in [1, 2, 3, 4]:
                return Response({'code': 400, 'msg': 'leixing 必须为 1/2/3/4'}, status=status.HTTP_400_BAD_REQUEST)
            if shenfen_id not in [1, 2, 3, 4]:
                return Response({'code': 400, 'msg': 'shenfen_id 必须为 1/2/3/4'}, status=status.HTTP_400_BAD_REQUEST)

            if leixing == 1 and is_trial:
                return Response({
                    'code': 400,
                    'msg': '体验会员仅支持微信支付，不可用佣金、分红或押金抵扣',
                }, status=status.HTTP_400_BAD_REQUEST)
            if leixing == 2:
                if not yajin_jine:
                    return Response({'code': 400, 'msg': '购买押金时必须提供 yajin_jine'}, status=status.HTTP_400_BAD_REQUEST)
                try:
                    yajin_jine = Decimal(str(yajin_jine))
                    if yajin_jine <= 0:
                        raise ValueError
                    if yajin_jine > Decimal('10000'):
                        return Response({'code': 400, 'msg': '押金金额不能超过10000元'}, status=status.HTTP_400_BAD_REQUEST)
                except:
                    return Response({'code': 400, 'msg': 'yajin_jine 必须为正数'}, status=status.HTTP_400_BAD_REQUEST)

            target_price = None
            club_id = resolve_effective_club_id(request, request.user)
            if leixing == 1:
                try:
                    huiyuan = Huiyuan.query.get(huiyuan_id=huiyuan_id)
                    target_price = get_huiyuan_price(club_id, huiyuan_id, huiyuan)
                except Huiyuan.DoesNotExist:
                    return Response({'code': 404, 'msg': '会员不存在'}, status=status.HTTP_404_NOT_FOUND)
            elif leixing == 2:
                target_price = yajin_jine
            elif leixing == 3:
                target_price = INTEGRAL_PRICE
            elif leixing == 4:
                if not fadan_id:
                    return Response({'code': 400, 'msg': '缺少罚单ID'}, status=status.HTTP_400_BAD_REQUEST)
                try:
                    fadan_obj = Penalty.query.get(id=fadan_id, PenalizedUserID=request.user.UserUID)
                    target_price = fadan_obj.FineAmount
                except Penalty.DoesNotExist:
                    return Response({'code': 404, 'msg': '罚单不存在或不属于当前用户'}, status=status.HTTP_404_NOT_FOUND)

            identity = IDENTITY_CONFIG.get(shenfen_id)
            from jituan.services.club_config import get_commission_rate
            try:
                rate = get_commission_rate(club_id, identity['rate_key'])
                if rate >= 1:
                    return Response({'code': 400, 'msg': f"{identity['name']}费率异常"}, status=status.HTTP_400_BAD_REQUEST)
            except Exception:
                return Response({'code': 400, 'msg': f"{identity['name']}费率未配置"}, status=status.HTTP_400_BAD_REQUEST)

            logger.info(f"目标价格={target_price}, 费率={rate}")

            try:
                required = target_price / (Decimal('1.0') - rate)
                required = required.quantize(Decimal('0.01'), rounding=ROUND_CEILING)
                logger.info(f"所需抵扣金额={required}")
            except Exception as e:
                logger.error(f"金额计算错误: {str(e)}", exc_info=True)
                return Response({'code': 500, 'msg': f'金额计算错误: {str(e)}'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

            user = request.user
            yonghuid = user.UserUID

            try:
                profile = identity['model'].query.get(user=user)
            except identity['model'].DoesNotExist:
                return Response({'code': 403, 'msg': f'您不是{identity["name"]}身份'})

            status_value = getattr(profile, identity['status_field'])
            if status_value != 1:
                return Response({'code': 403, 'msg': f'{identity["name"]}账号状态异常，无法使用'})

            balance = getattr(profile, identity['balance_field'])
            if balance < required:
                return Response({'code': 400, 'msg': f'{identity["name"]}余额不足，需要{required}元，当前{balance}元'}, status=status.HTTP_400_BAD_REQUEST)

            try:
                fulfill_error = None
                with transaction.atomic():
                    locked_profile = identity['model'].objects.select_for_update().get(id=profile.id)
                    current_balance = getattr(locked_profile, identity['balance_field'])
                    if current_balance < required:
                        raise ValueError(f"{identity['name']}余额不足，需要{required}元，当前{current_balance}元")

                    setattr(locked_profile, identity['balance_field'], current_balance - required)
                    locked_profile.save(update_fields=[identity['balance_field']])
                    logger.info(f"扣款成功: {identity['name']} 扣除 {required} 元，剩余 {current_balance - required} 元")

                    timestamp = str(int(time.time() * 1000))[-12:]
                    rand_str = ''.join(random.choices(string.ascii_uppercase + string.digits, k=4))
                    dingdan_id = f"CZ{timestamp}{rand_str}"

                    if leixing == 1:
                        action_desc = f"购买会员 {huiyuan.jieshao}"
                    elif leixing == 2:
                        action_desc = f"充值押金 {yajin_jine}元"
                    elif leixing == 3:
                        action_desc = "补充积分"
                    elif leixing == 4:
                        action_desc = f"缴纳罚款 {target_price}元"

                    shuoming = f"{identity['name']}抵扣 {action_desc}，抵扣金额{required}元"
                    cz_leixing = leixing
                    cz_club_id = club_id
                    from jituan.services.member_recharge import MEMBER_PENDING_STATUS, MEMBER_FAILED_STATUS, MEMBER_PAID_STATUS
                    cz_zhuangtai = MEMBER_PENDING_STATUS
                    if leixing == 4:
                        from jituan.services.club_penalty import penalty_cz_club_id
                        from products.czjilu_types import (
                            CZJILU_LEIXING_FAKUAN,
                            CZJILU_PAID_STATUS,
                            PENALTY_FADAN_TAG,
                        )
                        cz_leixing = CZJILU_LEIXING_FAKUAN
                        cz_club_id = penalty_cz_club_id(fadan_obj)
                        cz_zhuangtai = CZJILU_PAID_STATUS
                        shuoming = f"{shuoming}{PENALTY_FADAN_TAG}{fadan_obj.id}"

                    member_purchase_days = 0
                    czjilu_kwargs = {
                        'dingdan_id': dingdan_id,
                        'zhuangtai': cz_zhuangtai,
                        'yonghuid': yonghuid,
                        'jine': required,
                        'leixing': cz_leixing,
                        'shuoming': shuoming,
                        'club_id': cz_club_id,
                    }
                    if leixing == 1:
                        from jituan.services.member_recharge import club_huiyuan_sellable
                        _, _, member_purchase_days = club_huiyuan_sellable(
                            club_id, huiyuan_id, is_trial=False,
                        )
                        czjilu_kwargs.update({
                            'huiyuan_id': huiyuan_id,
                            'is_trial': False,
                            'purchase_days': member_purchase_days,
                        })

                    czjilu = Czjilu.query.create(**czjilu_kwargs)

                    response_data = {'dingdan_id': dingdan_id}
                    fulfill_error = None

                    if leixing == 1:
                        from jituan.services.member_recharge import (
                            fulfill_member_balance_purchase,
                            validate_member_purchase,
                        )
                        try:
                            ok, err_msg, _, _ = validate_member_purchase(
                                yonghuid, huiyuan_id, club_id, is_trial=False,
                            )
                            if not ok:
                                raise MemberRechargeError(err_msg or '会员不可购买', 'purchase_not_allowed')
                            huiyuan_record, new_jifen = fulfill_member_balance_purchase(
                                czjilu, huiyuan, club_id=club_id,
                            )
                            response_data['huiyuan'] = {
                                'huiyuanid': huiyuan_id,
                                'huiyuanming': huiyuan.jieshao,
                                'daoqi': huiyuan_record.daoqi_time.strftime('%Y-%m-%d %H:%M:%S') if hasattr(huiyuan_record, 'daoqi_time') else '',
                            }
                            response_data['jifen'] = new_jifen
                        except MemberRechargeError as exc:
                            setattr(locked_profile, identity['balance_field'], current_balance)
                            locked_profile.save(update_fields=[identity['balance_field']])
                            czjilu.zhuangtai = MEMBER_FAILED_STATUS
                            czjilu.shuoming = f"{shuoming} | 履约失败:{str(exc)[:40]}"[:100]
                            czjilu.save(update_fields=['zhuangtai', 'shuoming'])
                            fulfill_error = exc

                    elif leixing == 2:
                        try:
                            dashou = UserDashou.objects.select_for_update().get(user=user)
                            dashou.yajin += yajin_jine
                            dashou.save(update_fields=['yajin'])
                            czjilu.zhuangtai = MEMBER_PAID_STATUS
                            czjilu.save(update_fields=['zhuangtai'])
                            response_data['yajin'] = dashou.yajin
                        except UserDashou.DoesNotExist:
                            setattr(locked_profile, identity['balance_field'], current_balance)
                            locked_profile.save(update_fields=[identity['balance_field']])
                            czjilu.zhuangtai = MEMBER_FAILED_STATUS
                            czjilu.shuoming = f"{shuoming} | 履约失败:打手不存在"[:100]
                            czjilu.save(update_fields=['zhuangtai', 'shuoming'])
                            fulfill_error = MemberRechargeError('打手信息不存在，无法充值押金', 'dashou_not_found')

                    elif leixing == 4:
                        if fadan_obj.Status not in [1, 3]:
                            return Response({'code': 400, 'msg': '罚单状态不可缴纳'}, status=status.HTTP_400_BAD_REQUEST)
                        fadan_obj.Status = 2
                        fadan_obj.save(update_fields=['Status'])
                        response_data['fadan_id'] = fadan_obj.id
                        response_data['fadan_status'] = fadan_obj.Status

                        # ========== 修改点2: 使用最新的分红处理方法 ==========
                        success, msg = process_fadan_fenhong(fadan_obj.id)
                        if not success:
                            logger.error(f"罚单 {fadan_obj.id} 分红处理失败: {msg}")
                        else:
                            logger.info(f"罚单 {fadan_obj.id} 分红处理成功: {msg}")

                    else:  # leixing == 3
                        try:
                            dashou = UserDashou.objects.select_for_update().get(user=user)
                            new_jifen = dashou.jifen + INTEGRAL_INCREMENT
                            dashou.jifen = min(new_jifen, MAX_INTEGRAL)
                            dashou.save(update_fields=['jifen'])
                            czjilu.zhuangtai = MEMBER_PAID_STATUS
                            czjilu.save(update_fields=['zhuangtai'])
                            response_data['jifen'] = dashou.jifen
                        except UserDashou.DoesNotExist:
                            setattr(locked_profile, identity['balance_field'], current_balance)
                            locked_profile.save(update_fields=[identity['balance_field']])
                            czjilu.zhuangtai = MEMBER_FAILED_STATUS
                            czjilu.shuoming = f"{shuoming} | 履约失败:打手不存在"[:100]
                            czjilu.save(update_fields=['zhuangtai', 'shuoming'])
                            fulfill_error = MemberRechargeError('打手信息不存在，无法补充积分', 'dashou_not_found')

            except Exception as e:
                logger.error(f"事务处理异常: {str(e)}", exc_info=True)
                return Response({'code': 500, 'msg': f'支付处理失败: {str(e)}'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

            if fulfill_error:
                logger.warning('余额抵扣履约失败 dingdan=%s err=%s', dingdan_id, fulfill_error)
                return Response({
                    'code': 400,
                    'msg': str(fulfill_error),
                    'data': response_data,
                }, status=status.HTTP_400_BAD_REQUEST)

            final_profile = identity['model'].query.get(user=user)
            response_data['balance'] = str(getattr(final_profile, identity['balance_field']))

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

        except Exception as e:
            logger.error(f"接口顶层异常: {str(e)}", exc_info=True)
            return Response({'code': 500, 'msg': f'系统错误: {str(e)}'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

