"""支付宝 Czjilu 类充值统一异步回调视图。

所有基于 Czjilu 表的支付宝支付（押金/积分/会员/商家充值/考核/罚款）
共用一个回调入口，按 Czjilu.leixing 路由到对应履约函数。
"""
import logging
import traceback

from django.http import HttpResponse
from django.views import View
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework import status

from products.models import Czjilu
from products.czjilu_types import (
    CZJILU_LEIXING_HUIYUAN, CZJILU_LEIXING_YAJIN, CZJILU_LEIXING_JIFEN,
    CZJILU_LEIXING_SHANGJIA, CZJILU_LEIXING_KAOHE, CZJILU_LEIXING_FAKUAN,
    CZJILU_LEIXING_ZHUANPAN,
    CZJILU_PAID_STATUS, is_czjilu_fulfillable_status,
)

logger = logging.getLogger(__name__)


def _fulfill_czjilu_by_leixing(out_trade_no, leixing, paid_amount, source='callback'):
    """按 leixing 调幂等履约；入账只在 fulfill_* 内发生一次。"""
    if leixing == CZJILU_LEIXING_HUIYUAN:
        from jituan.services.member_recharge import fulfill_member_recharge
        return fulfill_member_recharge(out_trade_no, paid_amount_yuan=paid_amount, source=source)
    if leixing == CZJILU_LEIXING_YAJIN:
        from jituan.services.czjilu_fulfill import fulfill_yajin_recharge
        return fulfill_yajin_recharge(out_trade_no, paid_amount_yuan=paid_amount)
    if leixing == CZJILU_LEIXING_JIFEN:
        from jituan.services.czjilu_fulfill import fulfill_jifen_recharge
        return fulfill_jifen_recharge(out_trade_no, paid_amount_yuan=paid_amount)
    if leixing == CZJILU_LEIXING_SHANGJIA:
        from jituan.services.czjilu_fulfill import fulfill_shangjia
        return fulfill_shangjia(out_trade_no, paid_amount_yuan=paid_amount)
    if leixing == CZJILU_LEIXING_KAOHE:
        from jituan.services.czjilu_fulfill import fulfill_kaohe
        return fulfill_kaohe(out_trade_no, paid_amount_yuan=paid_amount)
    if leixing == CZJILU_LEIXING_FAKUAN:
        from jituan.services.czjilu_fulfill import fulfill_fakuan
        return fulfill_fakuan(out_trade_no, paid_amount_yuan=paid_amount)
    if leixing == CZJILU_LEIXING_ZHUANPAN:
        from jituan.services.czjilu_fulfill import fulfill_zhuanpan
        return fulfill_zhuanpan(out_trade_no, paid_amount_yuan=paid_amount)
    raise ValueError(f'未知 leixing={leixing}')


class AlipayCzjiluNotifyView(View):
    """支付宝 Czjilu 充值统一回调：验签 + 按 leixing 路由履约。

    路径：/shangpin/alipay-czjilu-notify/
    不需要 JWT 认证，由支付宝服务器调用。
    """

    def post(self, request):
        try:
            # 注意：必须用 .dict() 而不是 dict()
            #   dict(request.POST) 返回 {key: [value_list]}（值是列表）
            #   request.POST.dict() 返回 {key: value}（值是字符串），符合验签需求
            params = request.POST.dict() if request.POST else {}
            if not params:
                logger.warning('[ALIPAY_CZJILU_NOTIFY] 收到空数据')
                return HttpResponse('fail', content_type='text/plain')

            out_trade_no = params.get('out_trade_no', '')
            trade_no = params.get('trade_no', '')
            trade_status = params.get('trade_status', '')
            total_amount = params.get('total_amount', '')

            logger.info(
                '[ALIPAY_CZJILU_NOTIFY] out_trade_no=%s, trade_no=%s, trade_status=%s, total_amount=%s',
                out_trade_no, trade_no, trade_status, total_amount,
            )

            # 验签
            from jituan.services.alipay_pay import verify_notify_params, club_id_from_czjilu
            notify_club_id = club_id_from_czjilu(out_trade_no)
            if not verify_notify_params(params, notify_club_id):
                logger.warning('[ALIPAY_CZJILU_NOTIFY] 验签失败: out_trade_no=%s', out_trade_no)
                return HttpResponse('fail', content_type='text/plain')

            # 仅处理交易成功状态
            if trade_status not in ('TRADE_SUCCESS', 'TRADE_FINISHED'):
                logger.info('[ALIPAY_CZJILU_NOTIFY] 非成功状态 %s: %s', trade_status, out_trade_no)
                return HttpResponse('success', content_type='text/plain')

            # 查询充值单
            order = Czjilu.query.filter(dingdan_id=out_trade_no).first()
            if not order:
                # 找不到单回 fail，让支付宝重试，避免「钱付了永久无履约」
                logger.error('[ALIPAY_CZJILU_NOTIFY] 充值单不存在: %s', out_trade_no)
                return HttpResponse('fail', content_type='text/plain')

            # 已支付：幂等成功（绝不再加余额/会员）
            if order.zhuangtai == CZJILU_PAID_STATUS:
                logger.info('[ALIPAY_CZJILU_NOTIFY] 订单已支付，幂等返回: %s', out_trade_no)
                return HttpResponse('success', content_type='text/plain')

            # 待付(9) 或用户关单(2)：官方已付则履约
            if is_czjilu_fulfillable_status(order.zhuangtai):
                paid_amount = total_amount or order.jine
                leixing = order.leixing
                try:
                    _fulfill_czjilu_by_leixing(out_trade_no, leixing, paid_amount, source='callback')
                except Exception as fulfill_exc:
                    logger.error(
                        '[ALIPAY_CZJILU_NOTIFY] 履约异常 out_trade_no=%s leixing=%s: %s',
                        out_trade_no, leixing, fulfill_exc, exc_info=True,
                    )
                    # 履约异常返回 fail，让支付宝重试
                    return HttpResponse('fail', content_type='text/plain')

                logger.info('[ALIPAY_CZJILU_NOTIFY] 履约完成: %s, leixing=%s', out_trade_no, leixing)
                return HttpResponse('success', content_type='text/plain')

            # 终态异常（如会员履约失败 8、考核业务失败 10）：停止重试，留人工处理
            logger.warning(
                '[ALIPAY_CZJILU_NOTIFY] 订单终态不再履约: %s, zhuangtai=%s',
                out_trade_no, order.zhuangtai,
            )
            return HttpResponse('success', content_type='text/plain')

        except Exception as e:
            logger.error('[ALIPAY_CZJILU_NOTIFY] 回调处理异常: %s', str(e))
            logger.error(traceback.format_exc())
            return HttpResponse('fail', content_type='text/plain')


class CzjiluRepairView(APIView):
    """客服补单：查官方支付结果后走同一幂等履约。

    路径：POST /shangpin/czjilu-budan
    参数：dingdanid
    """
    permission_classes = [IsAuthenticated]

    def post(self, request):
        from backend.utils import verify_kefu_permission
        from jituan.services.czjilu_fulfill import repair_czjilu_payment, CzjiluFulfillError
        from jituan.services.member_recharge import MemberRechargeError

        username = (
            request.data.get('username')
            or request.data.get('phone')
            or getattr(request.user, 'Phone', None)
        )
        kefu, permissions_or_resp = verify_kefu_permission(request, username)
        if not kefu:
            return permissions_or_resp

        dingdanid = (request.data.get('dingdanid') or request.data.get('dingdan_id') or '').strip()
        if not dingdanid:
            return Response({'code': 400, 'message': '订单ID不能为空'}, status=status.HTTP_400_BAD_REQUEST)

        try:
            result = repair_czjilu_payment(dingdanid)
            return Response({
                'code': 200,
                'message': '补单成功' if not result.get('already_done') else '订单已到账（幂等）',
                'data': result,
            })
        except (CzjiluFulfillError, MemberRechargeError) as exc:
            logger.warning('[CZJILU_REPAIR] 补单未完成 dingdan=%s: %s', dingdanid, exc)
            return Response({'code': 400, 'message': str(exc)}, status=status.HTTP_400_BAD_REQUEST)
        except Exception as exc:
            logger.error('[CZJILU_REPAIR] 补单异常 dingdan=%s: %s', dingdanid, exc, exc_info=True)
            return Response({'code': 500, 'message': '补单失败，请稍后重试'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
