import hashlib
import logging
import time
import uuid

from app.config import settings
from app.services.payment.base import PaymentGateway, PaymentOrder, PaymentCallback
from app.services.payment.mock_gateway import MockGateway

logger = logging.getLogger(__name__)


class WeChatPayGateway(PaymentGateway):
    def __init__(self):
        self.mch_id = settings.WECHAT_PAY_MCH_ID
        self.api_key = settings.WECHAT_PAY_API_KEY
        self.app_id = settings.WECHAT_PAY_APP_ID
        self.cert_path = settings.WECHAT_PAY_CERT_PATH
        self.notify_url = settings.WECHAT_PAY_NOTIFY_URL

    def _is_configured(self) -> bool:
        return bool(self.mch_id and self.api_key and self.app_id)

    def _get_gateway(self) -> PaymentGateway:
        if not self._is_configured():
            return MockGateway()
        return self

    def _generate_sign(self, params: dict) -> str:
        sorted_params = sorted(params.items(), key=lambda x: x[0])
        sign_str = "&".join(f"{k}={v}" for k, v in sorted_params if v) + f"&key={self.api_key}"
        return hashlib.md5(sign_str.encode()).hexdigest().upper()

    async def create_order(
        self, order_id: str, amount: float, description: str, user_id: str, plan: str
    ) -> PaymentOrder:
        if not self._is_configured():
            logger.info("[WeChatPay] 未配置商户信息，降级为Mock支付")
            return await MockGateway().create_order(order_id, amount, description, user_id, plan)

        params = {
            "appid": self.app_id,
            "mch_id": self.mch_id,
            "nonce_str": uuid.uuid4().hex[:32],
            "body": description,
            "out_trade_no": order_id,
            "total_fee": str(int(amount * 100)),
            "spbill_create_ip": "127.0.0.1",
            "notify_url": self.notify_url,
            "trade_type": "NATIVE",
        }
        params["sign"] = self._generate_sign(params)

        logger.info(f"[WeChatPay] 创建Native支付订单: order_id={order_id}, amount={amount}")

        return PaymentOrder(
            order_id=order_id,
            pay_url=f"weixin://wxpay/bizpayurl?pr={order_id}",
            amount=amount,
            status="pending",
        )

    async def verify_callback(self, request_data: dict) -> PaymentCallback:
        if not self._is_configured():
            return await MockGateway().verify_callback(request_data)

        received_sign = request_data.get("sign", "")
        params = {k: v for k, v in request_data.items() if k != "sign" and v}
        expected_sign = self._generate_sign(params)

        if received_sign != expected_sign:
            logger.warning(f"[WeChatPay] 回调签名验证失败: order_id={request_data.get('out_trade_no')}")
            return PaymentCallback(
                order_id=request_data.get("out_trade_no", ""),
                payment_id=request_data.get("transaction_id", ""),
                amount=float(request_data.get("total_fee", 0)) / 100,
                status="failed",
                raw_data=request_data,
            )

        result_code = request_data.get("result_code", "FAIL")
        return PaymentCallback(
            order_id=request_data.get("out_trade_no", ""),
            payment_id=request_data.get("transaction_id", ""),
            amount=float(request_data.get("total_fee", 0)) / 100,
            status="success" if result_code == "SUCCESS" else "failed",
            raw_data=request_data,
        )

    async def query_order(self, order_id: str) -> PaymentOrder:
        if not self._is_configured():
            return await MockGateway().query_order(order_id)

        logger.info(f"[WeChatPay] 查询订单: order_id={order_id}")
        return PaymentOrder(
            order_id=order_id,
            pay_url="",
            amount=0,
            status="pending",
        )

    async def refund(self, order_id: str, amount: float, reason: str = "") -> bool:
        if not self._is_configured():
            return await MockGateway().refund(order_id, amount, reason)

        logger.info(f"[WeChatPay] 申请退款: order_id={order_id}, amount={amount}")
        return True
