"""支付网关配置 + 会员余额管理 API

路由：
  GET  /admin/payment-gateways              列出所有支付网关
  PUT  /admin/payment-gateways/{code}       更新网关配置（启用/禁用 + API 密钥）
  GET  /admin/wallets                       会员余额列表（分页）
  GET  /admin/wallets/{customer_id}         单个客户余额 + 近期流水
  POST /admin/wallets/{customer_id}/adjust  管理员充值 / 扣款
"""
from decimal import Decimal
from typing import Optional, List

from fastapi import APIRouter, Depends, HTTPException, Query
from pydantic import BaseModel, Field
from sqlalchemy import select, func
from sqlalchemy.ext.asyncio import AsyncSession

from app.api.deps import get_db, get_admin_user, require_permission, get_tenant_by_domain
from app.core.models.tenant import Tenant
from app.core.models.user import User
from app.core.models.customer import Customer
from app.core.models.wallet import CustomerWallet, WalletTransaction
from app.core.models.payment_gateway import PaymentGateway

router = APIRouter(prefix="/admin", tags=["支付配置"])


# ── Schemas ────────────────────────────────────────────────────────────────

class GatewayOut(BaseModel):
    id: int
    code: str
    name: str
    description: Optional[str] = None
    icon: Optional[str] = None
    enabled: bool
    sort_order: int
    config: Optional[dict] = None
    model_config = {"from_attributes": True}

    @classmethod
    def from_orm(cls, gw: PaymentGateway):
        cfg = dict(gw.config or {})
        # 脱敏：隐藏密钥实际值，仅返回是否已填写
        masked = {}
        for k, v in cfg.items():
            if any(s in k.lower() for s in ("key", "secret", "token", "password")):
                masked[k] = "••••••••" if v else ""
            else:
                masked[k] = v
        return cls(
            id=gw.id, code=gw.code, name=gw.name,
            description=gw.description, icon=gw.icon,
            enabled=bool(gw.enabled), sort_order=gw.sort_order,
            config=masked,
        )


class GatewayUpdate(BaseModel):
    enabled: Optional[bool] = None
    sort_order: Optional[int] = None
    config: Optional[dict] = None     # 完整 config dict，前端原样传回（含脱敏占位）


class WalletOut(BaseModel):
    customer_id: int
    customer_name: str
    customer_email: str
    balance: float
    currency: str

    model_config = {"from_attributes": True}


class WalletTxnOut(BaseModel):
    id: int
    amount: float
    balance_after: float
    type: str
    source_type: Optional[str] = None
    source_id: Optional[int] = None
    note: Optional[str] = None
    created_at: str

    model_config = {"from_attributes": True}


class WalletAdjustIn(BaseModel):
    amount: Decimal = Field(..., description="正=充值 负=扣款")
    note: Optional[str] = Field(None, max_length=200)


class WalletTxnUpdateIn(BaseModel):
    note: Optional[str] = Field(None, max_length=200)


# ── 支付网关路由 ────────────────────────────────────────────────────────────

@router.get("/payment-gateways", response_model=List[GatewayOut], summary="列出所有支付网关")
async def list_gateways(
    db: AsyncSession = Depends(get_db),
    admin: User = Depends(require_permission("settings.payment.view")),
):
    result = await db.execute(
        select(PaymentGateway)
        .where(PaymentGateway.tenant_id == admin.tenant_id)
        .order_by(PaymentGateway.sort_order)
    )
    gateways = result.scalars().all()
    return [GatewayOut.from_orm(gw) for gw in gateways]


@router.put("/payment-gateways/{code}", response_model=GatewayOut, summary="更新支付网关配置")
async def update_gateway(
    code: str,
    body: GatewayUpdate,
    db: AsyncSession = Depends(get_db),
    admin: User = Depends(require_permission("settings.payment.update")),
):
    result = await db.execute(
        select(PaymentGateway).where(
            PaymentGateway.code == code,
            PaymentGateway.tenant_id == admin.tenant_id,
        )
    )
    gw = result.scalar_one_or_none()
    if not gw:
        raise HTTPException(status_code=404, detail="支付网关不存在")

    if body.enabled is not None:
        gw.enabled = 1 if body.enabled else 0
    if body.sort_order is not None:
        gw.sort_order = body.sort_order
    if body.config is not None:
        existing_cfg = dict(gw.config or {})
        for k, v in body.config.items():
            # 跳过前端返回的脱敏占位符，不覆盖已存储的真实值
            if v == "••••••••":
                continue
            existing_cfg[k] = v
        gw.config = existing_cfg

    await db.commit()
    await db.refresh(gw)
    return GatewayOut.from_orm(gw)


# ── 公开端点（前台结账用）────────────────────────────────────────────────────

@router.get("/payment-gateways/public", include_in_schema=False)
async def public_gateways(
    db: AsyncSession = Depends(get_db),
    tenant: Tenant = Depends(get_tenant_by_domain),
):
    """前台结账使用：只返回已启用网关的 code/name/icon，无配置信息"""
    result = await db.execute(
        select(PaymentGateway)
        .where(PaymentGateway.enabled == 1, PaymentGateway.tenant_id == tenant.id)
        .order_by(PaymentGateway.sort_order)
    )
    return [
        {"code": gw.code, "name": gw.name, "icon": gw.icon}
        for gw in result.scalars().all()
    ]


# ── 会员余额路由 ────────────────────────────────────────────────────────────

@router.get("/wallets", summary="会员余额列表")
async def list_wallets(
    page: int = Query(1, ge=1),
    page_size: int = Query(20, ge=1, le=100),
    keyword: Optional[str] = Query(None),
    db: AsyncSession = Depends(get_db),
    admin: User = Depends(get_admin_user),
):
    q = (
        select(CustomerWallet, Customer)
        .join(Customer, Customer.id == CustomerWallet.customer_id)
        .where(Customer.tenant_id == admin.tenant_id)
    )
    if keyword:
        like = f"%{keyword}%"
        q = q.where(
            Customer.name.ilike(like) | Customer.email.ilike(like)
        )
    total_q = select(func.count()).select_from(q.subquery())
    total = (await db.execute(total_q)).scalar_one()

    rows = (
        await db.execute(
            q.order_by(CustomerWallet.balance.desc())
            .offset((page - 1) * page_size)
            .limit(page_size)
        )
    ).all()

    items = [
        {
            "customer_id": w.customer_id,
            "customer_name": c.name,
            "customer_email": c.email,
            "balance": float(w.balance),
            "currency": w.currency,
        }
        for w, c in rows
    ]
    return {"total": total, "page": page, "page_size": page_size, "items": items}


@router.get("/wallets/{customer_id}", summary="单个客户余额详情 + 流水")
async def get_wallet(
    customer_id: int,
    db: AsyncSession = Depends(get_db),
    admin: User = Depends(get_admin_user),
):
    # 客户信息（限本租户）
    customer = (
        await db.execute(select(Customer).where(
            Customer.id == customer_id,
            Customer.tenant_id == admin.tenant_id,
        ))
    ).scalar_one_or_none()
    if not customer:
        raise HTTPException(status_code=404, detail="客户不存在")

    # 钱包（不存在则虚构一个余额为 0 的结果）
    wallet = (
        await db.execute(
            select(CustomerWallet).where(CustomerWallet.customer_id == customer_id)
        )
    ).scalar_one_or_none()

    balance = float(wallet.balance) if wallet else 0.0
    currency = wallet.currency if wallet else "NZD"

    # 近 50 条流水
    txns = (
        await db.execute(
            select(WalletTransaction)
            .where(WalletTransaction.customer_id == customer_id)
            .order_by(WalletTransaction.id.desc())
            .limit(50)
        )
    ).scalars().all()

    return {
        "customer_id": customer_id,
        "customer_name": customer.name,
        "customer_email": customer.email,
        "balance": balance,
        "currency": currency,
        "transactions": [
            {
                "id": t.id,
                "amount": float(t.amount),
                "balance_after": float(t.balance_after),
                "type": t.type,
                "source_type": t.source_type,
                "source_id": t.source_id,
                "note": t.note,
                "created_at": t.created_at.isoformat() if t.created_at else None,
            }
            for t in txns
        ],
    }


@router.post("/wallets/{customer_id}/adjust", summary="管理员充值 / 扣款")
async def adjust_wallet(
    customer_id: int,
    body: WalletAdjustIn,
    db: AsyncSession = Depends(get_db),
    admin: User = Depends(get_admin_user),
):
    if body.amount == Decimal("0"):
        raise HTTPException(status_code=400, detail="金额不能为 0")

    customer = (
        await db.execute(select(Customer).where(
            Customer.id == customer_id,
            Customer.tenant_id == admin.tenant_id,
        ))
    ).scalar_one_or_none()
    if not customer:
        raise HTTPException(status_code=404, detail="客户不存在")

    # 获取或创建钱包（upsert-style）
    wallet = (
        await db.execute(
            select(CustomerWallet).where(CustomerWallet.customer_id == customer_id)
        )
    ).scalar_one_or_none()

    if not wallet:
        wallet = CustomerWallet(customer_id=customer_id, balance=Decimal("0.00"), tenant_id=admin.tenant_id)
        db.add(wallet)
        await db.flush()

    new_balance = wallet.balance + body.amount
    if new_balance < Decimal("0"):
        raise HTTPException(status_code=400, detail="扣款后余额不能为负数")

    wallet.balance = new_balance

    txn = WalletTransaction(
        tenant_id=admin.tenant_id,
        customer_id=customer_id,
        amount=body.amount,
        balance_after=new_balance,
        type="admin_adjust",
        source_type="admin",
        note=body.note or f"管理员调整（{admin.name or admin.email}）",
    )
    db.add(txn)
    await db.commit()

    return {
        "customer_id": customer_id,
        "balance": float(new_balance),
        "transaction_id": txn.id,
    }


@router.put("/wallets/{customer_id}/transactions/{txn_id}", summary="编辑流水备注")
async def update_wallet_txn(
    customer_id: int,
    txn_id: int,
    body: WalletTxnUpdateIn,
    db: AsyncSession = Depends(get_db),
    admin: User = Depends(get_admin_user),
):
    # 先验证 customer_id 属于当前租户
    owner = (await db.execute(select(Customer).where(
        Customer.id == customer_id, Customer.tenant_id == admin.tenant_id,
    ))).scalar_one_or_none()
    if not owner:
        raise HTTPException(status_code=404, detail="客户不存在")
    txn = (
        await db.execute(
            select(WalletTransaction).where(
                WalletTransaction.id == txn_id,
                WalletTransaction.customer_id == customer_id,
            )
        )
    ).scalar_one_or_none()
    if not txn:
        raise HTTPException(status_code=404, detail="流水记录不存在")
    txn.note = body.note
    await db.commit()
    return {"id": txn.id, "note": txn.note}


@router.delete("/wallets/{customer_id}/transactions/{txn_id}", summary="删除流水并反向调整余额")
async def delete_wallet_txn(
    customer_id: int,
    txn_id: int,
    db: AsyncSession = Depends(get_db),
    admin: User = Depends(get_admin_user),
):
    # 先验证 customer_id 属于当前租户
    owner = (await db.execute(select(Customer).where(
        Customer.id == customer_id, Customer.tenant_id == admin.tenant_id,
    ))).scalar_one_or_none()
    if not owner:
        raise HTTPException(status_code=404, detail="客户不存在")
    txn = (
        await db.execute(
            select(WalletTransaction).where(
                WalletTransaction.id == txn_id,
                WalletTransaction.customer_id == customer_id,
            )
        )
    ).scalar_one_or_none()
    if not txn:
        raise HTTPException(status_code=404, detail="流水记录不存在")

    wallet = (
        await db.execute(
            select(CustomerWallet).where(CustomerWallet.customer_id == customer_id)
        )
    ).scalar_one_or_none()

    if wallet:
        new_balance = wallet.balance - Decimal(str(txn.amount))
        if new_balance < Decimal("0"):
            raise HTTPException(
                status_code=400,
                detail=f"删除该记录将导致余额为负（{float(new_balance):.2f}），请先手动调整余额",
            )
        wallet.balance = new_balance

    await db.delete(txn)
    await db.commit()
    return {"detail": "已删除", "balance": float(wallet.balance) if wallet else 0.0}
