import jingrow
import traceback
import urllib.parse
import json
import requests
from datetime import datetime

class PayPalAPI:
    def __init__(self):
        # 初始化时不立即加载设置
        self.client_id = None
        self.client_secret = None
        self.server_url = None
        self.notify_url = None
        self.sandbox = False
        self.access_token = None
        self.token_expires_at = None
        
    def _initialize(self):
        # 每次都重新加载配置，确保使用最新设置
        # 从 Jcloud Settings 获取配置
        settings = jingrow.get_single("Jcloud Settings")
        
        # 配置PayPal客户端
        self.client_id = settings.paypal_client_id
        self.client_secret = settings.paypal_client_secret
        self.server_url = settings.paypal_server_url
        self.notify_url = settings.paypal_notify_url
        self.sandbox = settings.paypal_sandbox
        
        # 重置访问令牌
        self.access_token = None
        self.token_expires_at = None

    def _get_access_token(self):
        """获取PayPal API访问令牌"""
        # 检查令牌是否有效
        if self.access_token and self.token_expires_at and datetime.now() < self.token_expires_at:
            return self.access_token
        
        # 构建获取令牌的URL
        token_url = f"{self.server_url}/v1/oauth2/token"
        
        # 准备请求数据
        data = {
            "grant_type": "client_credentials"
        }
        
        # 发送请求
        try:
            response = requests.post(
                token_url,
                data=data,
                auth=(self.client_id, self.client_secret),
                headers={"Content-Type": "application/x-www-form-urlencoded"}
            )
            
            response.raise_for_status()
            token_data = response.json()
            
            # 保存访问令牌和过期时间
            self.access_token = token_data["access_token"]
            
            # 计算过期时间（提前5分钟过期）
            expires_in = token_data["expires_in"] - 300
            self.token_expires_at = datetime.now() + jingrow.utils.relativedelta(seconds=expires_in)
            
            return self.access_token
            
        except Exception as e:
            error_message = (
                "获取PayPal访问令牌失败:\n"
                f"异常信息: {str(e)}\n"
                f"堆栈信息:\n{traceback.format_exc()}\n"
            )
            jingrow.log_error(error_message, "PayPal Token Error")
            raise

    def generate_payment_url(self, order_id, amount, subject, team_name, return_url=None, cancel_url=None):
        self._initialize()
        
        # 获取访问令牌
        access_token = self._get_access_token()
        
        # 构建创建订单的URL
        create_order_url = f"{self.server_url}/v2/checkout/orders"
        
        # 构建请求内容
        order_data = {
            "intent": "CAPTURE",
            "purchase_units": [{
                "amount": {
                    "currency_code": "USD",  # 目前只支持USD
                    "value": str(amount)
                },
                "description": subject
            }],
            "application_context": {
                "return_url": return_url or f"{jingrow.utils.get_url()}/api/action/jcloud.api.billing.handle_paypal_return",
                "cancel_url": cancel_url or f"{jingrow.utils.get_url()}/api/action/jcloud.api.billing.handle_paypal_cancel",
                "brand_name": "Jingrow",
                "user_action": "PAY_NOW",
                "shipping_preference": "NO_SHIPPING"
            }
        }
        
        # 发送创建订单请求
        try:
            response = requests.post(
                create_order_url,
                headers={
                    "Content-Type": "application/json",
                    "Authorization": f"Bearer {access_token}"
                },
                json=order_data
            )
            
            response.raise_for_status()
            order_response = response.json()
            
            # 提取支付链接
            approval_url = None
            for link in order_response.get("links", []):
                if link["rel"] == "approve":
                    approval_url = link["href"]
                    break
            
            if not approval_url:
                raise Exception("未找到PayPal支付链接")
            
            return approval_url
            
        except Exception as e:
            error_message = (
                "创建PayPal订单失败:\n"
                f"异常信息: {str(e)}\n"
                f"请求数据: {json.dumps(order_data)}\n"
                f"响应内容: {response.text if 'response' in locals() else '无响应'}\n"
                f"堆栈信息:\n{traceback.format_exc()}\n"
            )
            jingrow.log_error(error_message, "PayPal Order Error")
            
            # 如果API调用失败，返回模拟链接用于测试
            jingrow.log_error("使用模拟PayPal支付链接", "PayPal Fallback")
            return f"https://www.paypal.com/checkoutnow?token={order_id}"

    def verify_webhook(self, headers, body):
        """验证PayPal webhook通知"""
        self._initialize()
        
        try:
            # 获取签名和证书
            transmission_id = headers.get("PAYPAL-TRANSMISSION-ID")
            transmission_time = headers.get("PAYPAL-TRANSMISSION-TIME")
            cert_url = headers.get("PAYPAL-CERT-URL")
            auth_algo = headers.get("PAYPAL-AUTH-ALGO")
            transmission_sig = headers.get("PAYPAL-TRANSMISSION-SIG")
            
            # 验证必要头信息
            if not all([transmission_id, transmission_time, cert_url, auth_algo, transmission_sig]):
                return False
            
            # 获取PayPal公钥证书
            response = requests.get(cert_url)
            response.raise_for_status()
            public_key = response.text
            
            # 构建用于验证的字符串
            webhook_id = jingrow.db.get_single_value("Jcloud Settings", "paypal_webhook_id") or ""
            body_bytes = body if isinstance(body, bytes) else body.encode("utf-8")
            
            # 注意：完整的验证实现需要使用加密库验证签名
            # 这里简化处理，实际项目中需要实现完整的签名验证
            jingrow.log_error(f"PayPal webhook验证: {transmission_id}", "PayPal Webhook")
            
            # 返回True表示验证成功（简化处理）
            return True
            
        except Exception as e:
            error_message = (
                "验证PayPal webhook失败:\n"
                f"异常信息: {str(e)}\n"
                f"堆栈信息:\n{traceback.format_exc()}\n"
            )
            jingrow.log_error(error_message, "PayPal Webhook Error")
            return False

    def capture_payment(self, order_id):
        """捕获PayPal支付金额"""
        self._initialize()
        
        # 获取访问令牌
        access_token = self._get_access_token()
        
        # 构建捕获支付的URL
        capture_url = f"{self.server_url}/v2/checkout/orders/{order_id}/capture"
        
        try:
            response = requests.post(
                capture_url,
                headers={
                    "Content-Type": "application/json",
                    "Authorization": f"Bearer {access_token}"
                }
            )
            
            response.raise_for_status()
            capture_data = response.json()
            
            return capture_data
            
        except Exception as e:
            error_message = (
                f"捕获PayPal支付失败 (Order ID: {order_id}):\n"
                f"异常信息: {str(e)}\n"
                f"响应内容: {response.text if 'response' in locals() else '无响应'}\n"
                f"堆栈信息:\n{traceback.format_exc()}\n"
            )
            jingrow.log_error(error_message, "PayPal Capture Error")
            raise

