"""Windcave HPP 支付集成

路由列表（均挂在 /store/payment/windcave 前缀下）：
  POST  /pay        创建 Windcave HPP Session，返回支付跳转 URL
  GET   /return     Windcave 支付完成后同步跳回（查询结果、更新订单）
  POST  /notify     Windcave 异步 Webhook（备用，主逻辑在 /return）

Windcave HPP API 文档：
  POST https://sec.windcave.com/api/v1/sessions  — 创建 Session
  GET  https://sec.windcave.com/api/v1/sessions/{id} — 查询 Session / 交易结果
  认证：Basic Auth（api_username:api_key，Base64 编码）
"""

import base64
import logging
from datetime import datetime
from decimal import Decimal

import httpx
from fastapi import APIRouter, Depends, HTTPException, Query, Request
from fastapi.responses import 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 as _global_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/windcave", tags=["Windcave支付"])

WINDCAVE_API_BASE_PROD = "https://sec.windcave.com/api/v1"
WINDCAVE_API_BASE_UAT  = "https://uat.windcave.com/api/v1"

def _api_base(cfg: dict) -> str:
    return WINDCAVE_API_BASE_UAT if cfg.get("test_mode") else WINDCAVE_API_BASE_PROD


async def _get_store_base(tenant_id: int | None, db: AsyncSession) -> str:
    """按租户 ID 查询其 store 域名，构造前端基础 URL。SaaS 多租户安全跳转。"""
    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 _global_settings.FRONTEND_URL.rstrip("/")


# ── 工具函数 ─────────────────────────────────────────────────────────────────

def _basic_auth_header(username: str, api_key: str) -> str:
    token = base64.b64encode(f"{username}:{api_key}".encode()).decode()
    return f"Basic {token}"


async def _get_windcave_config(db: AsyncSession, tenant_id: int | None = None) -> dict:
    q = select(PaymentGateway).where(PaymentGateway.code == "windcave")
    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="Windcave 支付未启用，请联系商家")

    cfg = gw.config or {}
    required = ("api_username", "api_key")
    missing = [f for f in required if not cfg.get(f)]
    if missing:
        raise HTTPException(
            status_code=503,
            detail=f"Windcave 配置不完整，缺少：{', '.join(missing)}",
        )
    return cfg


async def _query_session(session_id: str, cfg: dict) -> dict:
    """查询 Windcave Session 详情（含交易结果）"""
    auth = _basic_auth_header(cfg["api_username"], cfg["api_key"])
    async with httpx.AsyncClient(timeout=15) as client:
        resp = await client.get(
            f"{_api_base(cfg)}/sessions/{session_id}",
            headers={"Authorization": auth, "Content-Type": "application/json"},
        )
    if resp.status_code != 200:
        logger.error("Windcave query session failed: %s %s", resp.status_code, resp.text)
        return {}
    return resp.json()


def _extract_link(links: list, rel: str) -> str:
    for lnk in links or []:
        if lnk.get("rel") == rel:
            return lnk.get("href", "")
    return ""


# ── Schema ────────────────────────────────────────────────────────────────────

class WindcavePayIn(BaseModel):
    order_no: str = Field(..., description="本系统订单号")


# ── 1. 创建支付 Session ────────────────────────────────────────────────────────

@router.post("/pay", summary="发起 Windcave HPP 支付")
async def windcave_pay(
    body: WindcavePayIn,
    db: AsyncSession = Depends(get_db),
    customer: Customer = Depends(get_current_customer),
):
    cfg = await _get_windcave_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 == "paid":
        raise HTTPException(status_code=400, detail="该订单已支付")

    # 计算实付金额（扣除已用余额）
    wallet_used = Decimal(str(order.get_attribute("wallet_amount") or 0))
    grand_total = Decimal(str(order.grand_total))
    charge_amount = max(Decimal("0.01"), grand_total - wallet_used)

    currency = cfg.get("currency", "NZD")

    # 构建回调/跳转 URL（return/notify 指向后端 API，由 windcave_return 再 302 到租户前端）
    api_base = _global_settings.API_BASE_URL.rstrip("/")

    # successUrl 必须是公网可访问的地址（Windcave 不接受 localhost）
    # 默认用后端 API 地址，后端处理完再 302 到前端成功页
    return_url  = cfg.get("return_url",  f"{api_base}/api/store/payment/windcave/return")
    notify_url  = cfg.get("notify_url",  f"{api_base}/api/store/payment/windcave/notify")

    session_payload = {
        "type":              "purchase",
        "amount":            f"{charge_amount:.2f}",
        "currency":          currency,
        "merchantReference": order.order_no,
        "language":          "en",
        "links": [
            {"href": f"{return_url}?order_no={order.order_no}", "rel": "successUrl",  "method": "GET"},
            {"href": f"{return_url}?order_no={order.order_no}&status=failed",    "rel": "failUrl",    "method": "GET"},
            {"href": f"{return_url}?order_no={order.order_no}&status=cancelled", "rel": "cancelUrl",  "method": "GET"},
            {"href": notify_url,                                                  "rel": "notifyUrl",  "method": "POST"},
        ],
    }

    auth = _basic_auth_header(cfg["api_username"], cfg["api_key"])
    async with httpx.AsyncClient(timeout=15) as client:
        resp = await client.post(
            f"{_api_base(cfg)}/sessions",
            json=session_payload,
            headers={"Authorization": auth, "Content-Type": "application/json"},
        )

    if resp.status_code not in (200, 201, 202):
        logger.error("Windcave create session failed: %s %s", resp.status_code, resp.text)
        raise HTTPException(status_code=502, detail="Windcave 支付接口异常，请稍后重试")

    data = resp.json()
    # Windcave 不同版本 rel 可能是 "payUrl" 或 "hpp"
    links = data.get("links", [])
    pay_url = _extract_link(links, "payUrl") or _extract_link(links, "hpp")
    if not pay_url:
        raise HTTPException(status_code=502, detail="未获取到 Windcave 支付链接")

    # 将 session_id 存入订单 extra_attributes 以便 return 时验证
    order.set_attribute("windcave_session_id", data.get("id", ""))
    await db.commit()

    return {"payment_url": pay_url}


# ── 2. 同步跳转回调（用户支付完成后 Windcave 跳回） ───────────────────────────

@router.get("/return", summary="Windcave 支付跳转回调")
async def windcave_return(
    order_no: str = Query(...),
    sessionId: str = Query(None),
    status: str = Query(None),
    db: AsyncSession = Depends(get_db),
):
    order = (
        await db.execute(select(Order).where(Order.order_no == order_no))
    ).scalar_one_or_none()

    store_base = await _get_store_base(order.tenant_id if order else None, db)

    if not order:
        return RedirectResponse(f"{store_base}/checkout/success?order_no={order_no}&wc_result=error")

    # 已支付直接跳成功
    if order.status == "paid":
        return RedirectResponse(f"{store_base}/checkout/success?order_no={order_no}")

    # 用户主动取消或失败
    if status in ("cancelled", "failed"):
        return RedirectResponse(
            f"{store_base}/checkout/success?order_no={order_no}&wc_result={status}"
        )

    # 查询 Windcave Session 确认支付结果
    if sessionId:
        cfg = {}
        try:
            cfg = await _get_windcave_config(db, tenant_id=order.tenant_id if order else None)
        except HTTPException:
            pass

        if cfg:
            session_data = await _query_session(sessionId, cfg)
            transactions = session_data.get("transactions", [])
            approved = any(
                t.get("authorised") and t.get("type") == "Purchase"
                for t in transactions
            )
            if approved:
                await _mark_paid(order, db, session_id=sessionId)
                return RedirectResponse(f"{store_base}/checkout/success?order_no={order_no}")
            else:
                return RedirectResponse(
                    f"{store_base}/checkout/success?order_no={order_no}&wc_result=failed"
                )

    return RedirectResponse(f"{store_base}/checkout/success?order_no={order_no}&wc_result=pending")


# ── 3. 异步 Webhook（备用） ────────────────────────────────────────────────────

@router.post("/notify", summary="Windcave 异步通知（Webhook）")
async def windcave_notify(request: Request, db: AsyncSession = Depends(get_db)):
    """
    Windcave 在后台异步推送交易结果。
    此端点主要作为备份：若用户关闭了跳转页，仍可通过 webhook 更新订单状态。
    Windcave 不对 Webhook 签名，因此通过查询 session 来验证真实性。
    """
    try:
        data = await request.json()
    except Exception:
        return {"result": "0"}

    session_id = data.get("id") or data.get("sessionId", "")
    if not session_id:
        return {"result": "0"}

    # 根据 merchantReference 找订单
    merchant_ref = data.get("merchantReference", "")
    if not merchant_ref:
        return {"result": "0"}

    order = (
        await db.execute(select(Order).where(Order.order_no == merchant_ref))
    ).scalar_one_or_none()
    if not order or order.status == "paid":
        return {"result": "1"}

    # 向 Windcave 主动查询确认
    try:
        cfg = await _get_windcave_config(db, tenant_id=order.tenant_id if order else None)
        session_data = await _query_session(session_id, cfg)
        transactions = session_data.get("transactions", [])
        approved = any(
            t.get("authorised") and t.get("type") == "Purchase"
            for t in transactions
        )
        if approved:
            await _mark_paid(order, db, session_id=session_id)
    except Exception as e:
        logger.exception("Windcave notify processing failed: %s", e)

    return {"result": "1"}


# ── 内部：标记订单已支付 ───────────────────────────────────────────────────────

async def _mark_paid(order: Order, db: AsyncSession, *, session_id: str = "") -> None:
    if order.status == "paid":
        return
    order.status   = "paid"
    order.paid_at  = datetime.now()
    if session_id:
        order.set_attribute("windcave_session_id", session_id)
    await db.commit()
    logger.info("Windcave: order %s marked as paid (session=%s)", order.order_no, session_id)
