"""小程序「微信支付」通道路由：按俱乐部选择微信直连或付呗；前端仍传 pay_method=wechat。"""
from __future__ import annotations

import logging
from decimal import Decimal
from typing import Any, Dict, Optional

from django.conf import settings

from jituan.constants import (
    CLUB_ID_DEFAULT,
    FUBEI_BIZ_CZJILU,
    FUBEI_BIZ_ORDER,
    MINI_PAY_CHANNEL_FUBEI,
    MINI_PAY_CHANNEL_WECHAT,
    PAY_CHANNEL_FUBEI_WX_MINI,
)
from jituan.models import Club, PayChannelLedger
from jituan.services.club_payment_channel import get_fubei_config, invalidate_club_payment_cache
from jituan.services import fubei_client

logger = logging.getLogger(__name__)


def get_club_mini_pay_channel(club_id: Optional[str] = None) -> str:
    """返回 wechat / fubei；缺省 wechat（现网行为）。"""
    cid = (club_id or '').strip() or CLUB_ID_DEFAULT
    club = Club.query.filter(club_id=cid).first()
    if not club:
        return MINI_PAY_CHANNEL_WECHAT
    ch = (getattr(club, 'mini_pay_channel', None) or MINI_PAY_CHANNEL_WECHAT).strip().lower()
    if ch == MINI_PAY_CHANNEL_FUBEI:
        return MINI_PAY_CHANNEL_FUBEI
    return MINI_PAY_CHANNEL_WECHAT


def set_club_mini_pay_channel(club_id: str, channel: str) -> None:
    cid = (club_id or '').strip() or CLUB_ID_DEFAULT
    ch = (channel or '').strip().lower()
    if ch not in (MINI_PAY_CHANNEL_WECHAT, MINI_PAY_CHANNEL_FUBEI):
        raise ValueError('mini_pay_channel 仅支持 wechat / fubei')
    club = Club.query.filter(club_id=cid).first()
    if not club:
        raise ValueError(f'俱乐部 {cid} 不存在')
    club.mini_pay_channel = ch
    club.save(update_fields=['mini_pay_channel'])
    invalidate_club_payment_cache(cid)


def _default_fubei_notify_url(club_id: Optional[str] = None) -> str:
    base = 'https://www.abas.asia'
    club = Club.query.filter(club_id=(club_id or CLUB_ID_DEFAULT)).first()
    if club and (club.h5_domain or '').strip():
        base = club.h5_domain.strip().rstrip('/')
    return f'{base}/hqhd/dingdan/fubei-notify/'


def _remember_ledger(
    *,
    out_trade_no: str,
    club_id: str,
    channel: str,
    channel_config_id: Optional[int],
    biz_type: str,
    provider_order_sn: str,
    amount_yuan,
) -> None:
    row = PayChannelLedger.query.filter(out_trade_no=out_trade_no).first()
    fields = {
        'club_id': club_id or CLUB_ID_DEFAULT,
        'channel': channel,
        'channel_config_id': channel_config_id,
        'biz_type': biz_type or '',
        'provider_order_sn': provider_order_sn or '',
        'amount_yuan': Decimal(str(amount_yuan or 0)),
    }
    if row:
        for k, v in fields.items():
            setattr(row, k, v)
        row.save()
    else:
        PayChannelLedger.objects.create(out_trade_no=out_trade_no, **fields)


def get_pay_ledger(out_trade_no: str) -> Optional[PayChannelLedger]:
    if not out_trade_no:
        return None
    return PayChannelLedger.query.filter(out_trade_no=out_trade_no).first()


def maybe_create_fubei_jsapi_params(
    *,
    club_id: Optional[str],
    out_trade_no: str,
    amount_yuan,
    body: str,
    openid: str,
    notify_url: str = '',
    biz_type: str = FUBEI_BIZ_ORDER,
) -> Optional[Dict[str, Any]]:
    """若俱乐部选用付呗则下单并返回 wx.requestPayment 参数；否则返回 None（走原微信逻辑）。"""
    cid = (club_id or '').strip() or CLUB_ID_DEFAULT
    if get_club_mini_pay_channel(cid) != MINI_PAY_CHANNEL_FUBEI:
        return None

    cfg = get_fubei_config(cid)
    if not cfg or not cfg.app_id or not cfg.api_key:
        raise Exception('俱乐部已切换付呗收款，但付呗开放平台 ID/密钥未配置完整')
    store_id = cfg.store_id
    if store_id in (None, '', 0, '0'):
        raise Exception('俱乐部已切换付呗收款，但门店 store_id 未配置')
    if not openid:
        raise Exception('付呗支付缺少用户 openid')

    cb = (notify_url or '').strip() or (cfg.notify_url or '').strip() or _default_fubei_notify_url(cid)
    # 强制走付呗专用回调（原微信 XML 回调无法解析付呗 form）
    if 'fubei-notify' not in cb:
        cb = _default_fubei_notify_url(cid)

    attach = f'biz={biz_type or FUBEI_BIZ_ORDER}'
    data = fubei_client.mina_prepay(
        gateway_url=cfg.gateway_url,
        app_id=cfg.app_id,
        app_secret=cfg.api_key,
        merchant_order_sn=out_trade_no,
        sub_openid=openid,
        total_fee=amount_yuan,
        store_id=int(store_id),
        call_back_url=cb,
        body=body or '',
        attach=attach,
    )
    sign_params = data.get('sign_params') or {}
    if isinstance(sign_params, str):
        import json
        sign_params = json.loads(sign_params)
    pay_params = fubei_client.extract_jsapi_pay_params(sign_params)

    _remember_ledger(
        out_trade_no=out_trade_no,
        club_id=cid,
        channel=PAY_CHANNEL_FUBEI_WX_MINI,
        channel_config_id=cfg.config_id,
        biz_type=biz_type or FUBEI_BIZ_ORDER,
        provider_order_sn=str(data.get('order_sn') or ''),
        amount_yuan=amount_yuan,
    )
    logger.info(
        '[FUBEI_PAY] club=%s out_trade_no=%s biz=%s order_sn=%s',
        cid, out_trade_no, biz_type, data.get('order_sn'),
    )
    return pay_params
