"""Latipay 支付集成

路由列表（均挂在 /store/payment/latipay 前缀下）：
  POST  /pay             创建 Latipay 交易，返回支付跳转 URL
  POST  /callback        Latipay 异步回调（更新订单状态）
  GET   /return          Latipay 同步跳转（支付完成后跳回）
  GET   /query/{order_no} 主动查询订单支付状态
  POST  /refund          发起退款
"""

import hashlib
import hmac
import logging
from datetime import datetime
from decimal import Decimal
from typing import Optional

import httpx
from fastapi import APIRouter, Depends, HTTPException, Query, Request
from fastapi.responses import PlainTextResponse, RedirectResponse
from pydantic import BaseModel, Field
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

from app.api.deps import get_db, get_current_customer
from app.config import settings
from app.core.models.customer import Customer
from app.core.models.order import Order
from app.core.models.payment_gateway import PaymentGateway
from app.core.models.tenant import Tenant

logger = logging.getLogger("uvicorn.error")

router = APIRouter(prefix="/store/payment/latipay", tags=["Latipay支付"])

# ── Latipay API 地址 ────────────────────────────────────────────────────────
LATIPAY_API_BASE = "https://api.latipay.net"


def _latipay_urls() -> tuple[str, str]:
    base = settings.API_BASE_URL.rstrip("/")
    return (
        f"{base}/api/store/payment/latipay/callback",
        f"{base}/api/store/payment/latipay/return",
    )


# ── 签名工具 ─────────────────────────────────────────────────────────────────

async def _get_store_base(tenant_id: int | None, db: AsyncSession) -> str:
    """按租户 ID 动态返回前端基础 URL，避免多租户支付回调跳错店铺。"""
    if tenant_id:
        row = (await db.execute(
            select(Tenant.domain).where(Tenant.id == tenant_id)
        )).scalar_one_or_none()
        if row:
            domain = row.strip()
            if domain and not domain.startswith("http"):
                domain = f"https://{domain}"
            return domain.rstrip("/")
    return settings.FRONTEND_URL.rstrip("/")


def _sign_request(params: dict, api_key: str) -> str:
    """
    请求签名：sorted_params + api_key 拼接后，以 api_key 为 secret 做 HMAC-SHA256。
    """
    filtered = {k: str(v) for k, v in params.items() if v is not None and v != ""}
    message = "&".join(f"{k}={filtered[k]}" for k in sorted(filtered)) + api_key
    return hmac.new(api_key.encode(), message.encode(), hashlib.sha256).hexdigest()


def _verify_callback(params: dict, api_key: str, received_sig: str) -> bool:
    """
    回调签名验证：与 _sign_request 完全相同的算法。
    sorted_params + api_key 作为 message，api_key 为 HMAC secret。
    """
    filtered = {k: str(v) for k, v in params.items() if v is not None and v != ""}
    message  = "&".join(f"{k}={filtered[k]}" for k in sorted(filtered)) + api_key
    expected = hmac.new(api_key.encode(), message.encode(), hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, received_sig)


# ── 从数据库读取 Latipay 配置 ─────────────────────────────────────────────────

async def _get_latipay_config(db: AsyncSession, tenant_id: int | None = None) -> dict:
    q = select(PaymentGateway).where(PaymentGateway.code == "latipay")
    if tenant_id is not None:
        q = q.where(PaymentGateway.tenant_id == tenant_id)
    gw = (await db.execute(q)).scalar_one_or_none()

    if not gw or not gw.enabled:
        raise HTTPException(status_code=503, detail="Latipay 支付未启用，请联系商家")

    cfg = gw.config or {}
    required = ("user_id", "wallet_id", "api_key")
    missing = [f for f in required if not cfg.get(f)]
    if missing:
        raise HTTPException(
            status_code=503,
            detail=f"Latipay 配置不完整，缺少：{', '.join(missing)}"
        )
    return cfg


# ── 独立子网关：code → payment_method 映射 ────────────────────────────────────
LATIPAY_SUB_MAP: dict[str, str] = {
    "latipay_wechat":  "wechat",
    "latipay_alipay":  "alipay",
    "latipay_polipay": "polipay",
    "latipay_payid":   "payid",
    "latipay_upi":     "upi_upop",
}

# ── Schemas ───────────────────────────────────────────────────────────────────

class LatipayPayIn(BaseModel):
    order_no: str = Field(..., description="本系统订单号")
    payment_method: str = Field(
        ...,
        description="支付方式：wechat / alipay / polipay / payid / upi_upop"
    )
    customer_ip: Optional[str] = Field("1.1.1.1", description="客户 IP")

class LatipaySubPayIn(BaseModel):
    order_no: str = Field(..., description="本系统订单号")
    customer_ip: Optional[str] = Field("1.1.1.1", description="客户 IP")


class LatipayRefundIn(BaseModel):
    order_no: str
    refund_amount: str = Field(..., description="退款金额，如 '120.00'")
    reference: Optional[str] = Field("退款申请", description="退款备注")


# ── 1. 创建支付交易 ───────────────────────────────────────────────────────────

@router.post("/pay", summary="发起 Latipay 支付")
async def latipay_pay(
    body: LatipayPayIn,
    db: AsyncSession = Depends(get_db),
    customer: Customer = Depends(get_current_customer),
):
    cfg = await _get_latipay_config(db, tenant_id=customer.tenant_id)

    # 查订单
    order = (
        await db.execute(
            select(Order).where(
                Order.order_no == body.order_no,
                Order.customer_id == customer.id,
            )
        )
    ).scalar_one_or_none()
    if not order:
        raise HTTPException(status_code=404, detail="订单不存在")
    if order.status != "pending":
        raise HTTPException(status_code=400, detail="订单状态不允许支付")

    # 构造请求参数（version 2.0）
    # 所有要发送给 Latipay 的字段都必须参与签名计算
    callback_url, return_url = _latipay_urls()
    wallet_used   = Decimal(str(order.get_attribute("wallet_amount") or 0))
    charge_amount = max(Decimal("0.01"), Decimal(str(order.grand_total)) - wallet_used)
    amount_str    = f"{float(charge_amount):.2f}"

    params = {
        "user_id":            cfg["user_id"],
        "wallet_id":          cfg["wallet_id"],
        "payment_method":     body.payment_method,
        "amount":             amount_str,
        "return_url":         return_url,
        "callback_url":       callback_url,
        "merchant_reference": order.order_no,
        "ip":                 body.customer_ip or "1.1.1.1",
        "version":            "2.0",
        "product_name":       f"Order {order.order_no}",
    }
    # 微信 PC 场景：展示二维码（必须在签名前加入）
    if body.payment_method == "wechat":
        params["present_qr"] = "1"

    params["signature"] = _sign_request(params, cfg["api_key"])

    # 调 Latipay 接口
    try:
        async with httpx.AsyncClient(timeout=15) as client:
            resp = await client.post(
                f"{LATIPAY_API_BASE}/v2/transaction",
                json=params,
                headers={"Accept": "application/json"},
            )
        data = resp.json()
        logger.info(f"[Latipay pay] order={order.order_no} method={body.payment_method} response={data}")
    except Exception as e:
        logger.error(f"Latipay API error: {e}")
        raise HTTPException(status_code=502, detail="Latipay 服务暂时不可用，请稍后重试")

    if data.get("code") != 0:
        err_msg = data.get("message") or data.get("msg") or str(data)
        logger.error(f"[Latipay pay] rejected: {err_msg} | params={params}")
        raise HTTPException(
            status_code=400,
            detail=f"Latipay 拒绝请求：{err_msg}"
        )

    host_url = data.get("host_url", "")
    nonce    = data.get("nonce", "")
    if not host_url or not nonce:
        raise HTTPException(status_code=502, detail="Latipay 返回数据异常")

    payment_url = f"{host_url}/{nonce}"

    # 将 latipay 订单信息写入 extra_attributes，便于后续核对
    order.set_attribute("latipay_nonce", nonce)
    order.set_attribute("latipay_payment_method", body.payment_method)
    order.set_attribute("pay_method", f"latipay_{body.payment_method}")
    await db.commit()

    return {
        "order_no":    order.order_no,
        "payment_url": payment_url,
        "nonce":       nonce,
    }


# ── 2. 用 Latipay 查询 API 验证并落库 ────────────────────────────────────────

async def _verify_with_latipay_and_mark_paid(order_no: str, cfg: dict, db: AsyncSession) -> bool:
    """
    用 Latipay 查询 API 主动确认订单是否已支付，已确认则更新本地订单。
    返回 True 表示订单当前已是 paid 状态（本次更新或之前就是）。
    回调签名算法 Latipay 文档不清晰，这里改用主动查询验证，更可靠。
    """
    order = (
        await db.execute(select(Order).where(Order.order_no == order_no))
    ).scalar_one_or_none()
    if not order:
        return False
    if order.status == "paid":
        return True

    query_params = {
        "merchant_reference": order_no,
        "user_id":            cfg["user_id"],
    }
    query_params["signature"] = _sign_request(query_params, cfg["api_key"])

    try:
        async with httpx.AsyncClient(timeout=10) as client:
            resp = await client.get(
                f"{LATIPAY_API_BASE}/v2/transaction/{order_no}",
                params=query_params,
                headers={"Accept": "application/json"},
            )
        data = resp.json()
    except Exception as e:
        logger.error(f"[Latipay verify] query error for {order_no}: {e}")
        return False

    remote_status = data.get("status") or data.get("data", {}).get("status")
    logger.info(f"[Latipay verify] {order_no} remote_status={remote_status} resp={data}")

    if remote_status == "paid":
        order.status  = "paid"
        order.paid_at = datetime.now()
        order.set_attribute("latipay_order_id",    data.get("order_id") or data.get("data", {}).get("order_id"))
        order.set_attribute("latipay_pay_time",    data.get("pay_time") or data.get("data", {}).get("pay_time"))
        order.set_attribute("latipay_paid_amount", str(data.get("amount") or data.get("data", {}).get("amount") or ""))
        await db.commit()
        logger.info(f"[Latipay verify] Order {order_no} marked paid")
        return True
    return False


# ── 3. 异步回调（Latipay → 后端） ────────────────────────────────────────────

@router.post("/callback", summary="Latipay 异步通知（Webhook）", include_in_schema=False)
async def latipay_callback(request: Request, db: AsyncSession = Depends(get_db)):
    """
    Latipay 以 application/x-www-form-urlencoded POST 通知支付结果。
    通过 Latipay 查询 API 主动验证状态，不依赖回调签名。
    必须返回 HTTP 200，body 含 "sent"。
    """
    form = await request.form()
    data = dict(form)
    merchant_reference = data.get("merchant_reference", "")
    status = data.get("status", "")

    logger.info(f"[Latipay callback] ref={merchant_reference} status={status} data={dict(data)}")

    order = (await db.execute(select(Order).where(Order.order_no == merchant_reference))).scalar_one_or_none() if merchant_reference else None

    try:
        cfg = await _get_latipay_config(db, tenant_id=order.tenant_id if order else None)
    except HTTPException:
        logger.warning("[Latipay callback] Gateway config missing, ignoring")
        return PlainTextResponse("sent")

    if status == "paid" and merchant_reference:
        await _verify_with_latipay_and_mark_paid(merchant_reference, cfg, db)

    return PlainTextResponse("sent")


# ── 4. 同步跳转（Latipay → 前端） ────────────────────────────────────────────

@router.get("/return", summary="Latipay 同步跳转（支付完成后浏览器跳回）", include_in_schema=False)
async def latipay_return(
    merchant_reference: str = Query(...),
    status:             str = Query(None),
    db: AsyncSession = Depends(get_db),
):
    """
    Latipay 跳回后，主动用查询 API 验证状态再决定跳哪个页面。
    避免因为回调延迟/失败而把已支付订单跳到失败页。
    """
    order = (await db.execute(
        select(Order).where(Order.order_no == merchant_reference)
    )).scalar_one_or_none()
    frontend = await _get_store_base(order.tenant_id if order else None, db)
    paid = False

    try:
        cfg = await _get_latipay_config(db, tenant_id=order.tenant_id if order else None)
        paid = await _verify_with_latipay_and_mark_paid(merchant_reference, cfg, db)
    except HTTPException:
        pass

    if paid:
        return RedirectResponse(
            url=f"{frontend}/checkout/success?order_no={merchant_reference}&from=latipay",
            status_code=302,
        )
    else:
        return RedirectResponse(
            url=f"{frontend}/checkout/failed?order_no={merchant_reference}&reason={status or 'unknown'}",
            status_code=302,
        )


# ── 4. 主动查询支付状态 ───────────────────────────────────────────────────────

@router.get("/query/{order_no}", summary="查询 Latipay 支付状态")
async def latipay_query(
    order_no: str,
    db: AsyncSession = Depends(get_db),
    customer: Customer = Depends(get_current_customer),
):
    cfg = await _get_latipay_config(db, tenant_id=customer.tenant_id)

    # 先查本地订单状态
    order = (
        await db.execute(
            select(Order).where(
                Order.order_no == order_no,
                Order.customer_id == customer.id,
            )
        )
    ).scalar_one_or_none()
    if not order:
        raise HTTPException(status_code=404, detail="订单不存在")

    # 已标记 paid 则直接返回
    if order.status == "paid":
        return {"order_no": order_no, "status": "paid", "source": "local"}

    # 向 Latipay 查询
    query_params = {
        "merchant_reference": order_no,
        "user_id":            cfg["user_id"],
    }
    query_params["signature"] = _sign_request(query_params, cfg["api_key"])

    try:
        async with httpx.AsyncClient(timeout=15) as client:
            resp = await client.get(
                f"{LATIPAY_API_BASE}/v2/transaction/{order_no}",
                params=query_params,
                headers={"Accept": "application/json"},
            )
        data = resp.json()
    except Exception as e:
        logger.error(f"Latipay query error: {e}")
        raise HTTPException(status_code=502, detail="查询失败，请稍后重试")

    remote_status = data.get("status", "unknown")

    # 回调可能还没到，这里顺手更新
    if remote_status == "paid" and order.status == "pending":
        order.status  = "paid"
        order.paid_at = datetime.now()
        order.set_attribute("latipay_order_id",    data.get("order_id"))
        order.set_attribute("latipay_pay_time",    data.get("pay_time"))
        order.set_attribute("latipay_paid_amount", str(data.get("amount", "")))
        await db.commit()

    return {
        "order_no":       order_no,
        "status":         remote_status,
        "payment_method": data.get("payment_method"),
        "amount":         data.get("amount"),
        "currency":       data.get("currency"),
        "pay_time":       data.get("pay_time"),
        "source":         "latipay",
    }


# ── 5. 退款 ──────────────────────────────────────────────────────────────────

@router.post("/refund", summary="发起 Latipay 退款")
async def latipay_refund(
    body: LatipayRefundIn,
    db: AsyncSession = Depends(get_db),
    customer: Customer = Depends(get_current_customer),
):
    cfg = await _get_latipay_config(db, tenant_id=customer.tenant_id)

    order = (
        await db.execute(
            select(Order).where(
                Order.order_no == body.order_no,
                Order.customer_id == customer.id,
            )
        )
    ).scalar_one_or_none()
    if not order:
        raise HTTPException(status_code=404, detail="订单不存在")
    if order.status not in ("paid", "completed"):
        raise HTTPException(status_code=400, detail="订单状态不支持退款")

    latipay_order_id = order.get_attribute("latipay_order_id")
    if not latipay_order_id:
        raise HTTPException(
            status_code=400,
            detail="该订单未通过 Latipay 支付，无法通过此接口退款"
        )

    params = {
        "user_id":       cfg["user_id"],
        "order_id":      latipay_order_id,
        "refund_amount": body.refund_amount,
        "reference":     body.reference or "退款申请",
    }
    params["signature"] = _sign_request(params, cfg["api_key"])

    try:
        async with httpx.AsyncClient(timeout=15) as client:
            resp = await client.post(
                f"{LATIPAY_API_BASE}/refund",
                json=params,
                headers={"Accept": "application/json"},
            )
        data = resp.json()
    except Exception as e:
        logger.error(f"Latipay refund error: {e}")
        raise HTTPException(status_code=502, detail="退款请求失败，请稍后重试")

    if str(data.get("code")) != "0":
        raise HTTPException(
            status_code=400,
            detail=f"Latipay 退款失败：{data.get('message', '未知错误')}"
        )

    # 记录退款信息
    order.set_attribute("latipay_refund_amount", body.refund_amount)
    order.set_attribute("latipay_refund_time",   datetime.now().isoformat())
    await db.commit()

    return {"order_no": body.order_no, "refund_amount": body.refund_amount, "message": "退款申请已提交"}


# ════════════════════════════════════════════════════════════════════════════
# 独立子网关（latipay_wechat / latipay_alipay / latipay_polipay / latipay_payid / latipay_upi）
# 完全镜像聚合版，路由统一前缀 /sub/{gateway_code}
# ════════════════════════════════════════════════════════════════════════════

async def _get_sub_gateway_config(db: AsyncSession, gateway_code: str, tenant_id: int | None = None) -> dict:
    """读取独立子网关配置，与 _get_latipay_config 逻辑完全一致。"""
    if gateway_code not in LATIPAY_SUB_MAP:
        raise HTTPException(status_code=400, detail=f"不支持的 Latipay 子网关：{gateway_code}")

    q = select(PaymentGateway).where(PaymentGateway.code == gateway_code)
    if tenant_id is not None:
        q = q.where(PaymentGateway.tenant_id == tenant_id)
    gw = (await db.execute(q)).scalar_one_or_none()

    if not gw or not gw.enabled:
        raise HTTPException(status_code=503, detail="该支付方式未启用，请联系商家")

    cfg = gw.config or {}
    required = ("user_id", "wallet_id", "api_key")
    missing = [f for f in required if not cfg.get(f)]
    if missing:
        raise HTTPException(
            status_code=503,
            detail=f"Latipay 配置不完整，缺少：{', '.join(missing)}"
        )
    return cfg


# ── Sub 1. 创建支付交易（镜像 /pay） ─────────────────────────────────────────

@router.post("/sub/{gateway_code}/pay", summary="发起独立 Latipay 子网关支付")
async def latipay_sub_pay(
    gateway_code: str,
    body: LatipaySubPayIn,
    db: AsyncSession = Depends(get_db),
    customer: Customer = Depends(get_current_customer),
):
    cfg            = await _get_sub_gateway_config(db, gateway_code, tenant_id=customer.tenant_id)
    payment_method = LATIPAY_SUB_MAP[gateway_code]

    order = (
        await db.execute(
            select(Order).where(
                Order.order_no == body.order_no,
                Order.customer_id == customer.id,
            )
        )
    ).scalar_one_or_none()
    if not order:
        raise HTTPException(status_code=404, detail="订单不存在")
    if order.status != "pending":
        raise HTTPException(status_code=400, detail="订单状态不允许支付")

    callback_url, return_url = _latipay_urls()
    wallet_used   = Decimal(str(order.get_attribute("wallet_amount") or 0))
    charge_amount = max(Decimal("0.01"), Decimal(str(order.grand_total)) - wallet_used)
    amount_str    = f"{float(charge_amount):.2f}"

    params = {
        "user_id":            cfg["user_id"],
        "wallet_id":          cfg["wallet_id"],
        "payment_method":     payment_method,
        "amount":             amount_str,
        "return_url":         return_url,
        "callback_url":       callback_url,
        "merchant_reference": order.order_no,
        "ip":                 body.customer_ip or "1.1.1.1",
        "version":            "2.0",
        "product_name":       f"Order {order.order_no}",
    }
    if payment_method == "wechat":
        params["present_qr"] = "1"

    params["signature"] = _sign_request(params, cfg["api_key"])

    try:
        async with httpx.AsyncClient(timeout=15) as client:
            resp = await client.post(
                f"{LATIPAY_API_BASE}/v2/transaction",
                json=params,
                headers={"Accept": "application/json"},
            )
        data = resp.json()
        logger.info(f"[Latipay sub pay] order={order.order_no} gw={gateway_code} response={data}")
    except Exception as e:
        logger.error(f"Latipay sub pay API error: {e}")
        raise HTTPException(status_code=502, detail="Latipay 服务暂时不可用，请稍后重试")

    if data.get("code") != 0:
        err_msg = data.get("message") or data.get("msg") or str(data)
        logger.error(f"[Latipay sub pay] rejected: {err_msg} | params={params}")
        raise HTTPException(status_code=400, detail=f"Latipay 拒绝请求：{err_msg}")

    host_url = data.get("host_url", "")
    nonce    = data.get("nonce", "")
    if not host_url or not nonce:
        raise HTTPException(status_code=502, detail="Latipay 返回数据异常")

    payment_url = f"{host_url}/{nonce}"

    order.set_attribute("latipay_nonce",          nonce)
    order.set_attribute("latipay_payment_method",  payment_method)
    order.set_attribute("latipay_gateway_code",    gateway_code)
    order.set_attribute("pay_method",              f"latipay_{payment_method}")
    await db.commit()

    return {
        "order_no":    order.order_no,
        "payment_url": payment_url,
        "nonce":       nonce,
    }


# ── Sub 2. 异步回调（镜像 /callback） ────────────────────────────────────────

@router.post("/sub/{gateway_code}/callback", summary="独立子网关 Latipay 异步通知", include_in_schema=False)
async def latipay_sub_callback(
    gateway_code: str,
    request: Request,
    db: AsyncSession = Depends(get_db),
):
    form = await request.form()
    data = dict(form)
    merchant_reference = data.get("merchant_reference", "")
    status = data.get("status", "")

    logger.info(f"[Latipay sub callback] gw={gateway_code} ref={merchant_reference} status={status}")

    order = (await db.execute(select(Order).where(Order.order_no == merchant_reference))).scalar_one_or_none() if merchant_reference else None

    try:
        cfg = await _get_sub_gateway_config(db, gateway_code, tenant_id=order.tenant_id if order else None)
    except HTTPException:
        logger.warning(f"[Latipay sub callback] Gateway {gateway_code} config missing, ignoring")
        return PlainTextResponse("sent")

    if status == "paid" and merchant_reference:
        await _verify_with_latipay_and_mark_paid(merchant_reference, cfg, db)

    return PlainTextResponse("sent")


# ── Sub 3. 同步跳转（镜像 /return） ──────────────────────────────────────────

@router.get("/sub/{gateway_code}/return", summary="独立子网关 Latipay 同步跳转", include_in_schema=False)
async def latipay_sub_return(
    gateway_code: str,
    merchant_reference: str = Query(...),
    status:             str = Query(None),
    db: AsyncSession = Depends(get_db),
):
    order = (await db.execute(
        select(Order).where(Order.order_no == merchant_reference)
    )).scalar_one_or_none()
    frontend = await _get_store_base(order.tenant_id if order else None, db)
    paid = False

    try:
        cfg = await _get_sub_gateway_config(db, gateway_code, tenant_id=order.tenant_id if order else None)
        paid = await _verify_with_latipay_and_mark_paid(merchant_reference, cfg, db)
    except HTTPException:
        pass

    if paid:
        return RedirectResponse(
            url=f"{frontend}/checkout/success?order_no={merchant_reference}&from=latipay",
            status_code=302,
        )
    else:
        return RedirectResponse(
            url=f"{frontend}/checkout/failed?order_no={merchant_reference}&reason={status or 'unknown'}",
            status_code=302,
        )


# ── Sub 4. 主动查询支付状态（镜像 /query/{order_no}） ────────────────────────

@router.get("/sub/{gateway_code}/query/{order_no}", summary="查询独立子网关 Latipay 支付状态")
async def latipay_sub_query(
    gateway_code: str,
    order_no: str,
    db: AsyncSession = Depends(get_db),
    customer: Customer = Depends(get_current_customer),
):
    cfg = await _get_sub_gateway_config(db, gateway_code, tenant_id=customer.tenant_id)

    order = (
        await db.execute(
            select(Order).where(
                Order.order_no == order_no,
                Order.customer_id == customer.id,
            )
        )
    ).scalar_one_or_none()
    if not order:
        raise HTTPException(status_code=404, detail="订单不存在")

    if order.status == "paid":
        return {"order_no": order_no, "status": "paid", "source": "local"}

    query_params = {
        "merchant_reference": order_no,
        "user_id":            cfg["user_id"],
    }
    query_params["signature"] = _sign_request(query_params, cfg["api_key"])

    try:
        async with httpx.AsyncClient(timeout=15) as client:
            resp = await client.get(
                f"{LATIPAY_API_BASE}/v2/transaction/{order_no}",
                params=query_params,
                headers={"Accept": "application/json"},
            )
        data = resp.json()
    except Exception as e:
        logger.error(f"Latipay sub query error: {e}")
        raise HTTPException(status_code=502, detail="查询失败，请稍后重试")

    remote_status = data.get("status", "unknown")

    if remote_status == "paid" and order.status == "pending":
        order.status  = "paid"
        order.paid_at = datetime.now()
        order.set_attribute("latipay_order_id",    data.get("order_id"))
        order.set_attribute("latipay_pay_time",    data.get("pay_time"))
        order.set_attribute("latipay_paid_amount", str(data.get("amount", "")))
        await db.commit()

    return {
        "order_no":       order_no,
        "status":         remote_status,
        "payment_method": data.get("payment_method"),
        "amount":         data.get("amount"),
        "currency":       data.get("currency"),
        "pay_time":       data.get("pay_time"),
        "source":         "latipay",
    }


# ── Sub 5. 退款（镜像 /refund） ───────────────────────────────────────────────

@router.post("/sub/{gateway_code}/refund", summary="发起独立子网关 Latipay 退款")
async def latipay_sub_refund(
    gateway_code: str,
    body: LatipayRefundIn,
    db: AsyncSession = Depends(get_db),
    customer: Customer = Depends(get_current_customer),
):
    cfg = await _get_sub_gateway_config(db, gateway_code, tenant_id=customer.tenant_id)

    order = (
        await db.execute(
            select(Order).where(
                Order.order_no == body.order_no,
                Order.customer_id == customer.id,
            )
        )
    ).scalar_one_or_none()
    if not order:
        raise HTTPException(status_code=404, detail="订单不存在")
    if order.status not in ("paid", "completed"):
        raise HTTPException(status_code=400, detail="订单状态不支持退款")

    latipay_order_id = order.get_attribute("latipay_order_id")
    if not latipay_order_id:
        raise HTTPException(
            status_code=400,
            detail="该订单未通过 Latipay 支付，无法通过此接口退款"
        )

    params = {
        "user_id":       cfg["user_id"],
        "order_id":      latipay_order_id,
        "refund_amount": body.refund_amount,
        "reference":     body.reference or "退款申请",
    }
    params["signature"] = _sign_request(params, cfg["api_key"])

    try:
        async with httpx.AsyncClient(timeout=15) as client:
            resp = await client.post(
                f"{LATIPAY_API_BASE}/refund",
                json=params,
                headers={"Accept": "application/json"},
            )
        data = resp.json()
    except Exception as e:
        logger.error(f"Latipay sub refund error: {e}")
        raise HTTPException(status_code=502, detail="退款请求失败，请稍后重试")

    if str(data.get("code")) != "0":
        raise HTTPException(
            status_code=400,
            detail=f"Latipay 退款失败：{data.get('message', '未知错误')}"
        )

    order.set_attribute("latipay_refund_amount", body.refund_amount)
    order.set_attribute("latipay_refund_time",   datetime.now().isoformat())
    await db.commit()

    return {"order_no": body.order_no, "refund_amount": body.refund_amount, "message": "退款申请已提交"}
