"""微信支付 Native 扫码支付集成（v2 统一下单 API）"""

import hashlib
import secrets
import time
import xml.etree.ElementTree as ET

import httpx

from app.config import settings

# 微信支付 API 地址
UNIFIED_ORDER_URL = "https://api.mch.weixin.qq.com/pay/unifiedorder"

# 方案定价（元/月）
PLAN_PRICES = {"pro": 3500, "team": 7000}  # 分（微信以分为单位）
PLAN_NAMES = {"pro": "Pro 版", "team": "团队版"}


def _md5(s: str) -> str:
    return hashlib.md5(s.encode("utf-8")).hexdigest().upper()


def _build_xml(params: dict) -> str:
    """构建微信支付 XML"""
    parts = ["<xml>"]
    for k, v in params.items():
        if v is None:
            continue
        if isinstance(v, int):
            parts.append(f"<{k}>{v}</{k}>")
        else:
            parts.append(f"<{k}><![CDATA[{v}]]></{k}>")
    parts.append("</xml>")
    return "".join(parts)


def _parse_xml(xml_str: str) -> dict:
    """解析微信支付 XML 响应"""
    root = ET.fromstring(xml_str)
    return {child.tag: child.text for child in root}


def _sign_params(params: dict, api_key: str) -> str:
    """MD5 签名：参数按字典序排序，拼接 key 后取 MD5 大写"""
    keys = sorted(k for k in params if params[k] is not None)
    pairs = [f"{k}={params[k]}" for k in keys]
    pairs.append(f"key={api_key}")
    return _md5("&".join(pairs))


def generate_out_trade_no() -> str:
    """生成商户订单号：SCL + 时间戳 + 6 位随机数"""
    ts = str(int(time.time()))
    rand = secrets.token_hex(3)  # 6 hex chars
    return f"SCL{ts}{rand}"


def get_notify_url() -> str:
    """获取微信支付回调 URL"""
    if settings.WECHAT_NOTIFY_URL:
        return settings.WECHAT_NOTIFY_URL
    # dev 默认地址
    return "http://localhost:8000/api/v1/subscriptions/wechat-pay/notify"


def is_dev_mode() -> bool:
    """无微信配置时走开发模拟模式"""
    return not settings.WECHAT_APP_ID or not settings.WECHAT_MCH_ID or not settings.WECHAT_API_KEY


async def create_unified_order(
    out_trade_no: str,
    plan: str,
    spbill_create_ip: str = "127.0.0.1",
) -> tuple[str | None, str | None]:
    """调微信支付统一下单，返回 (code_url, prepay_id) 或模拟值"""
    if is_dev_mode():
        # 开发模式：返回模拟二维码
        amount_yuan = PLAN_PRICES.get(plan, 0) // 100
        code_url = (
            f"https://api.qrserver.com/v1/create-qr-code/"
            f"?size=200x200&data=PAY_{plan}_{amount_yuan}CNY"
        )
        return code_url, None

    amount = PLAN_PRICES.get(plan, 3500)
    description = PLAN_NAMES.get(plan, "升级")
    notify_url = get_notify_url()

    params = {
        "appid": settings.WECHAT_APP_ID,
        "mch_id": settings.WECHAT_MCH_ID,
        "nonce_str": secrets.token_hex(16),
        "body": f"Scilit Oncology {description}",
        "out_trade_no": out_trade_no,
        "total_fee": amount,
        "spbill_create_ip": spbill_create_ip,
        "notify_url": notify_url,
        "trade_type": "NATIVE",
    }

    sign = _sign_params(params, settings.WECHAT_API_KEY)
    params["sign"] = sign
    xml_body = _build_xml(params)

    async with httpx.AsyncClient(timeout=10) as client:
        resp = await client.post(UNIFIED_ORDER_URL, content=xml_body)
        result = _parse_xml(resp.text)

    if result.get("return_code") != "SUCCESS":
        raise RuntimeError(f"微信统一下单失败: {result.get('return_msg', '未知错误')}")
    if result.get("result_code") != "SUCCESS":
        err_msg = result.get("err_code_des", result.get("err_code", "未知错误"))
        raise RuntimeError(f"微信统一下单业务失败: {err_msg}")

    return result.get("code_url"), result.get("prepay_id")


def verify_notify(xml_body: str) -> dict:
    """验证微信支付回调签名，返回解析后的结果"""
    params = _parse_xml(xml_body)

    if params.get("return_code") != "SUCCESS":
        return {"verified": False, "reason": "return_code_not_success"}

    # 开发模式：无 key 时跳过签名验证
    if is_dev_mode():
        return {
            "verified": True,
            "out_trade_no": params.get("out_trade_no"),
            "transaction_id": params.get("transaction_id"),
            "total_fee": params.get("total_fee"),
            "time_end": params.get("time_end"),
        }

    sign = params.pop("sign", "")
    expected = _sign_params(params, settings.WECHAT_API_KEY)
    if sign != expected:
        return {"verified": False, "reason": "sign_mismatch"}

    return {
        "verified": params.get("result_code") == "SUCCESS",
        "out_trade_no": params.get("out_trade_no"),
        "transaction_id": params.get("transaction_id"),
        "total_fee": params.get("total_fee"),
        "time_end": params.get("time_end"),
    }


def success_xml() -> str:
    """微信支付回调成功响应"""
    return _build_xml({"return_code": "SUCCESS", "return_msg": "OK"})


def fail_xml(msg: str = "FAIL") -> str:
    """微信支付回调失败响应"""
    return _build_xml({"return_code": "FAIL", "return_msg": msg})
