"""付呗支付异步回调：验签后按订单/充值单履约（前端无感知）。"""
from __future__ import annotations

import json
import logging
import traceback

from django.http import HttpResponse
from django.views import View

from jituan.constants import FUBEI_BIZ_CZJILU, FUBEI_BIZ_ORDER
from jituan.services.club_payment_channel import get_fubei_config
from jituan.services import fubei_client
from jituan.services.mini_pay_router import get_pay_ledger
from jituan.services.wechat_pay import club_id_from_czjilu, club_id_from_order

logger = logging.getLogger(__name__)


class FubeiPayNotifyView(View):
    """
    付呗异步通知。
    GET：回调 URL 有效性验证，必须返回小写 success。
    POST：支付成功通知。
    路径：/dingdan/fubei-notify/
    """

    def get(self, request):
        return HttpResponse('success', content_type='text/plain')

    def post(self, request):
        try:
            raw_preview = ''
            try:
                raw_preview = (request.body or b'')[:800].decode('utf-8', errors='replace')
            except Exception:
                raw_preview = ''
            post = request.POST.dict() if request.POST else {}
            if not post and request.body:
                # 偶发 JSON
                try:
                    post = json.loads(request.body.decode('utf-8'))
                except Exception:
                    post = {}

            logger.info('[FUBEI_NOTIFY] raw=%s post_keys=%s', raw_preview, list(post.keys()))

            params, data = fubei_client.parse_callback_form(post)
            merchant_order_sn = str(data.get('merchant_order_sn') or '').strip()
            result_code = str(params.get('result_code') or '')

            logger.info(
                '[FUBEI_NOTIFY] result_code=%s merchant_order_sn=%s trade_no=%s',
                result_code, merchant_order_sn, data.get('trade_no') or data.get('platform_order_no'),
            )

            if not merchant_order_sn:
                logger.warning('[FUBEI_NOTIFY] 缺少 merchant_order_sn')
                return HttpResponse('fail', content_type='text/plain')

            club_id = self._resolve_club_id(merchant_order_sn, data)
            cfg = get_fubei_config(club_id)
            if not cfg or not cfg.api_key:
                logger.error('[FUBEI_NOTIFY] 无付呗密钥 club=%s order=%s', club_id, merchant_order_sn)
                return HttpResponse('fail', content_type='text/plain')

            if not fubei_client.verify_callback_sign(params, cfg.api_key):
                # 验签失败仍记录，便于排查；同时尝试用 data 字符串原样参与（部分网关会改写）
                logger.error(
                    '[FUBEI_NOTIFY] 验签失败 order=%s params=%s',
                    merchant_order_sn,
                    {k: params.get(k) for k in ('result_code', 'result_message', 'sign') if k in params},
                )
                return HttpResponse('fail', content_type='text/plain')

            if result_code not in ('200', '200.0'):
                logger.info('[FUBEI_NOTIFY] 非成功 result_code=%s order=%s', result_code, merchant_order_sn)
                return HttpResponse('success', content_type='text/plain')

            transaction_id = str(
                data.get('trade_no')
                or data.get('platform_order_no')
                or data.get('order_sn')
                or ''
            )
            total_fee = data.get('total_fee') or data.get('cash_fee') or data.get('order_price')
            attach = str(data.get('attach') or '')
            biz = self._biz_type(merchant_order_sn, attach)

            if biz == FUBEI_BIZ_ORDER:
                ok = self._fulfill_order(merchant_order_sn, transaction_id)
            else:
                ok = self._fulfill_czjilu(merchant_order_sn, total_fee, transaction_id)

            return HttpResponse('success' if ok else 'fail', content_type='text/plain')
        except Exception as exc:
            logger.error('[FUBEI_NOTIFY] 异常: %s', exc)
            logger.error(traceback.format_exc())
            return HttpResponse('fail', content_type='text/plain')

    def _resolve_club_id(self, merchant_order_sn: str, data: dict) -> str:
        ledger = get_pay_ledger(merchant_order_sn)
        if ledger and ledger.club_id:
            return ledger.club_id
        # 先试订单，再试充值单
        try:
            cid = club_id_from_order(merchant_order_sn)
            if cid:
                return cid
        except Exception:
            pass
        try:
            cid = club_id_from_czjilu(merchant_order_sn)
            if cid:
                return cid
        except Exception:
            pass
        return 'xq'

    def _biz_type(self, merchant_order_sn: str, attach: str) -> str:
        ledger = get_pay_ledger(merchant_order_sn)
        if ledger and ledger.biz_type:
            return ledger.biz_type
        if 'biz=order' in attach:
            return FUBEI_BIZ_ORDER
        if 'biz=czjilu' in attach:
            return FUBEI_BIZ_CZJILU
        # 启发式：点单 Order 表优先
        try:
            from orders.models import Order
            if Order.query.filter(OrderID=merchant_order_sn).exists():
                return FUBEI_BIZ_ORDER
        except Exception:
            pass
        return FUBEI_BIZ_CZJILU

    def _fulfill_order(self, out_trade_no: str, transaction_id: str) -> bool:
        try:
            from orders.views.payment import WechatPayNotifyView
            view = WechatPayNotifyView()
            view._handle_success(out_trade_no, transaction_id, None)
            return True
        except Exception as exc:
            logger.error('[FUBEI_NOTIFY] 订单履约失败 %s: %s', out_trade_no, exc, exc_info=True)
            return False

    def _fulfill_czjilu(self, out_trade_no: str, total_fee, transaction_id: str) -> bool:
        from products.models import Czjilu
        from products.czjilu_types import (
            CZJILU_PAID_STATUS,
            is_czjilu_fulfillable_status,
        )
        from products.views.alipay_czjilu_notify import _fulfill_czjilu_by_leixing

        order = Czjilu.query.filter(dingdan_id=out_trade_no).first()
        if not order:
            logger.error('[FUBEI_NOTIFY] 充值单不存在: %s', out_trade_no)
            return False
        if order.zhuangtai == CZJILU_PAID_STATUS:
            return True
        if not is_czjilu_fulfillable_status(order.zhuangtai):
            logger.warning('[FUBEI_NOTIFY] 充值单终态不再履约 %s zhuangtai=%s', out_trade_no, order.zhuangtai)
            return True
        paid_amount = total_fee if total_fee not in (None, '') else order.jine
        try:
            _fulfill_czjilu_by_leixing(out_trade_no, order.leixing, paid_amount, source='fubei_callback')
            return True
        except Exception as exc:
            logger.error('[FUBEI_NOTIFY] 充值履约失败 %s: %s', out_trade_no, exc, exc_info=True)
            return False
