import logging

from fastapi import APIRouter, Depends, HTTPException, Query, Request
from sqlalchemy import select, func
from sqlalchemy.ext.asyncio import AsyncSession

logger = logging.getLogger("payment")

from app.dependencies import get_db, get_current_user
from app.models.user import User
from app.models.payment_order import PaymentOrder
from app.models.recharge_package import RechargePackage
from app.schemas.payment import RechargeRequest, PaymentOrderOut
from app.services.payment import (
    create_recharge_order,
    verify_wechat_callback,
    verify_alipay_callback,
    process_payment_success_by_order_no,
    process_refund,
    _get_payment_configs,
    _close_alipay_order,
    _get_order_expire_seconds,
)

router = APIRouter(prefix="/payments", tags=["payments"])


@router.get("/methods")
async def get_payment_methods(
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db)
):
    """Return which payment methods are enabled (from admin config)."""
    from app.services.payment import _get_payment_configs
    configs = await _get_payment_configs(db)
    return {
        "alipay": configs.get("payment_alipay_enabled", "").lower() == "true",
        "wechat": configs.get("payment_wechat_enabled", "").lower() == "true",
    }


@router.post("/recharge", response_model=PaymentOrderOut)
async def recharge(
    req: RechargeRequest,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    if req.method not in ("wechat", "alipay"):
        raise HTTPException(status_code=400, detail="不支持的支付方式")

    # Check if the selected payment method is enabled in admin config
    from app.services.payment import _get_payment_configs, _is_mock_mode
    configs = await _get_payment_configs(db)
    if not _is_mock_mode(configs):
        enabled_key = f"payment_{req.method}_enabled"
        if configs.get(enabled_key, "").lower() != "true":
            raise HTTPException(status_code=400, detail="该支付方式未启用")

    result = await db.execute(
        select(RechargePackage).where(
            RechargePackage.id == req.plan,
            RechargePackage.is_active == True,
        )
        .limit(1)
    )
    pkg = result.scalar_one_or_none()
    if not pkg:
        raise HTTPException(status_code=400, detail="无效的套餐")
    try:
        order = await create_recharge_order(
            db,
            current_user.id,
            credits=pkg.credits,
            price=pkg.price,
            label=pkg.name,
            bonus_credits=pkg.bonus_credits,
            method=req.method,
        )
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    return order


@router.post("/wechat/callback")
async def wechat_callback(request: Request, db: AsyncSession = Depends(get_db)):
    # 读取微信支付回调数据
    body_bytes = await request.body()
    body_str = body_bytes.decode("utf-8")
    
    # 获取配置
    from app.services.payment import _get_payment_configs, _is_mock_mode, _get_wechat_client
    db_configs = await _get_payment_configs(db)
    
    # 检查 mock 模式
    if _is_mock_mode(db_configs):
        try:
            import json
            data = json.loads(body_str) if body_str else {}
            order_no = data.get("out_trade_no")
            if order_no:
                await process_payment_success_by_order_no(db, order_no)
            logger.info(f"Mock WeChat callback processed: order_no={order_no}")
            return {"code": "SUCCESS", "message": "OK"}
        except Exception as e:
            logger.exception(f"Mock WeChat callback error: {e}")
            return {"code": "SUCCESS", "message": "OK"}  # 微信要求即使处理失败也返回成功
    
    # 真实模式：使用 wechatpayv3 SDK 工具验证回调并解析数据
    try:
        from wechatpayv3.utils import (
            rsa_verify, load_public_key, sha256, b64decode,
            AESGCM, InvalidTag
        )
        
        mch_id = db_configs.get("payment_wechat_mch_id", "")
        api_v3_key = db_configs.get("payment_wechat_api_v3_key", "")
        public_key = db_configs.get("payment_wechat_public_key", "")
        
        if not all([mch_id, api_v3_key]):
            logger.error("WeChat payment config missing for callback")
            return {"code": "SUCCESS", "message": "OK"}
        
        # 从请求头获取必要信息（不区分大小写）
        headers = {k.lower(): v for k, v in dict(request.headers).items()}
        timestamp = headers.get("wechatpay-timestamp", "")
        nonce = headers.get("wechatpay-nonce", "")
        signature = headers.get("wechatpay-signature", "")
        serial_no = headers.get("wechatpay-serial", "")
        
        
        # 验证签名：使用平台公钥验证
        if public_key and serial_no:
            try:
                # 构造签名串：timestamp + "\n" + nonce + "\n" + body + "\n"
                # 符合微信支付官方文档规范：https://pay.weixin.qq.com/doc/v3/merchant/4013053249
                is_verified = rsa_verify(
                    timestamp=timestamp,
                    nonce=nonce,
                    body=body_str,
                    signature=signature,
                    public_key=load_public_key(public_key)
                )
                if not is_verified:
                    logger.warning(f"WeChat callback signature verification failed: serial={serial_no}")
                    raise HTTPException(status_code=400, detail="签名验证失败")
            except Exception as e:
                logger.warning(f"WeChat signature verification error: {e}, serial={serial_no}")
                raise HTTPException(status_code=400, detail="签名验证失败")
        else:
            if not public_key:
                logger.warning("WeChat platform public key not configured, skipping signature verification")
            if not serial_no:
                logger.warning("Wechatpay-Serial header missing, skipping signature verification")
        
        # 解密回调数据：使用 API v3 key
        # 官方文档：https://pay.weixin.qq.com/doc/v3/merchant/4012071382
        import json
        body_data = json.loads(body_str) if body_str else {}
        resource = body_data.get("resource", {})
        
        if not resource:
            logger.error("WeChat callback resource not found")
            raise HTTPException(status_code=400, detail="数据格式错误")
        
        # 验证加密算法（官方文档要求固定为 AEAD_AES_256_GCM）
        algorithm = resource.get("algorithm", "")
        if algorithm != "AEAD_AES_256_GCM":
            logger.error(f"WeChat callback unsupported algorithm: {algorithm}")
            raise HTTPException(status_code=400, detail="不支持的加密算法")
        
        ciphertext = resource.get("ciphertext", "")
        associated_data = resource.get("associated_data", "")
        nonce_str = resource.get("nonce", "")
        
        # 参数验证
        if not ciphertext:
            logger.error("WeChat callback ciphertext is empty")
            raise HTTPException(status_code=400, detail="密文为空")
        if not nonce_str:
            logger.error("WeChat callback nonce is empty")
            raise HTTPException(status_code=400, detail="随机数为空")
        
        # 使用 AES-GCM 解密（符合官方文档规范）
        # 官方文档：https://pay.weixin.qq.com/doc/v3/merchant/4012071382
        try:
            # API v3 key 需要转换为字节串
            api_v3_key_bytes = api_v3_key.encode('utf-8')
            
            # ciphertext 是 Base64 编码的，需要解码
            ciphertext_bytes = b64decode(ciphertext)
            
            # nonce 直接使用字符串编码（官方文档方式）
            nonce_bytes = nonce_str.encode('utf-8')
            
            # associated_data 是字符串，直接编码
            associated_data_bytes = associated_data.encode('utf-8') if associated_data else b''
            
            aesgcm = AESGCM(api_v3_key_bytes)
            decrypted_str = aesgcm.decrypt(nonce_bytes, ciphertext_bytes, associated_data_bytes)
        except InvalidTag:
            logger.error("WeChat callback decryption failed: Invalid tag (key or data mismatch)")
            raise HTTPException(status_code=400, detail="数据解密失败（密钥或数据不匹配）")
        except Exception as e:
            logger.error(f"WeChat callback decryption failed: {e}")
            raise HTTPException(status_code=400, detail="数据解密失败")
        
        if not decrypted_str:
            logger.error("WeChat callback decryption returned empty")
            raise HTTPException(status_code=400, detail="数据解密失败")
        
        decrypted_data = json.loads(decrypted_str)
        
        event_type = body_data.get("event_type", "")
        
        # 处理支付成功回调
        if event_type == "TRANSACTION.SUCCESS":
            order_no = decrypted_data.get("out_trade_no", "")
            transaction_id = decrypted_data.get("transaction_id", "")
            amount_info = decrypted_data.get("amount", {})
            total_amount = amount_info.get("total", 0) / 100  # 转换为元
            
            if order_no:
                await process_payment_success_by_order_no(db, order_no, transaction_id, total_amount)
                logger.info(
                    f"WeChat callback processed: order_no={order_no}, "
                    f"transaction_id={transaction_id}, amount={total_amount}"
                )
        
        # 处理退款回调
        elif event_type == "REFUND.SUCCESS":
            order_no = decrypted_data.get("out_trade_no", "")
            refund_id = decrypted_data.get("refund_id", "")
            refund_status = decrypted_data.get("status", "")
            
            if order_no and refund_status == "SUCCESS":
                # 更新订单状态为已退款
                from app.models import PaymentOrder
                from sqlalchemy import select
                
                result = await db.execute(select(PaymentOrder).where(PaymentOrder.order_no == order_no))
                order = result.scalar_one_or_none()
                
                if order and order.status == "refunding":
                    order.status = "refunded"
                    order.transaction_id = refund_id
                    await db.commit()
                    
                    logger.info(
                        f"WeChat refund callback processed: order_no={order_no}, "
                        f"refund_id={refund_id}, status={refund_status}"
                    )
        
        return {"code": "SUCCESS", "message": "OK"}
    except Exception as e:
        logger.exception(f"WeChat callback processing error: {e}")
        # 微信支付要求即使处理失败也返回成功，避免重复回调
        return {"code": "SUCCESS", "message": "OK"}


@router.post("/alipay/callback")
async def alipay_callback(request: Request, db: AsyncSession = Depends(get_db)):
    form_data = await request.form()
    data = dict(form_data)
    
    logger.info(
        f"ALIPAY_CALLBACK order_no={data.get('out_trade_no')} "
        f"data={data}"
    )

    # Verify signature first
    if not await verify_alipay_callback(data, db):
        raise HTTPException(status_code=400, detail="签名验证失败")

    # Check trade_status – only "TRADE_SUCCESS" and "TRADE_FINISHED" mean paid
    trade_status = data.get("trade_status", "")
    if trade_status not in ("TRADE_SUCCESS", "TRADE_FINISHED"):
        logger.info(f"Alipay callback trade_status={trade_status}, ignoring")
        return "success"

    order_no = data.get("out_trade_no")
    trade_no = data.get("trade_no", "")
    total_amount_str = data.get("total_amount", "")
    total_amount = float(total_amount_str) if total_amount_str else None
    
    if order_no:
        await process_payment_success_by_order_no(db, order_no, trade_no, total_amount)

    return "success"


@router.get("/orders")
async def list_orders(
    page: int = Query(1, ge=1),
    page_size: int = Query(20, ge=1, le=100),
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    from app.services.payment import _check_and_expire_order

    count_query = select(func.count(PaymentOrder.id)).where(PaymentOrder.user_id == current_user.id)
    total = (await db.execute(count_query)).scalar() or 0

    result = await db.execute(
        select(PaymentOrder)
        .where(PaymentOrder.user_id == current_user.id)
        .order_by(PaymentOrder.created_at.desc())
        .offset((page - 1) * page_size)
        .limit(page_size)
    )
    orders = result.scalars().all()
    for o in orders:
        await _check_and_expire_order(db, o)

    return {"items": [PaymentOrderOut.model_validate(o) for o in orders], "total": total}


@router.get("/orders/{order_no}", response_model=PaymentOrderOut)
async def get_order(
    order_no: str,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    from app.services.payment import _check_and_expire_order
    result = await db.execute(
        select(PaymentOrder)
        .where(
            PaymentOrder.order_no == order_no,
            PaymentOrder.user_id == current_user.id,
        )
        .limit(1)
    )
    order = result.scalar_one_or_none()
    if not order:
        raise HTTPException(status_code=404, detail="订单不存在")
    # Auto-expire if needed
    await _check_and_expire_order(db, order)
    return order


@router.post("/orders/{order_no}/cancel")
async def cancel_order(
    order_no: str,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    """Cancel a pending order. Only the order owner can cancel, only if still pending."""
    result = await db.execute(
        select(PaymentOrder).where(
            PaymentOrder.order_no == order_no,
            PaymentOrder.user_id == current_user.id,
        ).limit(1)
    )
    order = result.scalar_one_or_none()
    if not order:
        raise HTTPException(status_code=404, detail="订单不存在")
    if order.status != "pending":
        raise HTTPException(status_code=400, detail=f"订单状态为{order.status}，无法取消")
    
    # If it's an Alipay or WeChat order, call close API first
    db_configs = await _get_payment_configs(db)
    if order.payment_method == "alipay":
        try:
            await _close_alipay_order(db, order, db_configs)
        except Exception as e:
            logger.exception(f"Failed to close Alipay order {order_no}: {e}")
    elif order.payment_method == "wechat":
        try:
            from app.services.payment import _close_wechat_order
            await _close_wechat_order(db, order, db_configs)
        except Exception as e:
            logger.exception(f"Failed to close WeChat order {order_no}: {e}")
    
    order.status = "cancelled"
    await db.flush()
    logger.info(
        f"ORDER_CANCELLED order_no={order_no} user={current_user.id} amount={order.amount}"
    )
    return {"ok": True}
