# API 集成测试 - 基础API客户端
import pytest
import requests
import time
import os
from typing import Optional, Dict, Any, Union
from requests.adapters import HTTPAdapter, Retry
from dotenv import load_dotenv
import httpx

# 加载环境变量
load_dotenv()


class BaseAPIClient:
    """基础 API 客户端，提供通用的 HTTP 请求方法"""
    
    def __init__(self, base_url: Optional[str] = None, timeout: int = 30):
        self.base_url = base_url or os.getenv('BASE_URL', 'http://localhost:8084')
        self.timeout = timeout
        self.session = requests.Session()
        self.token: Optional[str] = None
        self.user_id: Optional[int] = None
        
        # 配置重试策略
        retries = Retry(
            total=3,
            backoff_factor=0.1,
            status_forcelist=[500, 502, 503, 504]
        )
        self.session.mount('http', HTTPAdapter(max_retries=retries))
        self.session.mount('https', HTTPAdapter(max_retries=retries))
    
    def login(self, username: str, password: str) -> bool:
        """登录并获取 Token"""
        response = self.post(
            '/api/auth/login',
            json={'username': username, 'password': password},
            include_auth=False
        )
        
        if response.status_code == 200:
            data = response.json()
            self.token = data.get('token')
            self.user_id = data.get('userId')
            print(f"✅ 登录成功: {username} (User ID: {self.user_id})")
            return True
        else:
            print(f"❌ 登录失败: {response.status_code}")
            return False
    
    def _build_url(self, path: str) -> str:
        """构建完整 URL"""
        if path.startswith('http'):
            return path
        return f"{self.base_url}{path}"
    
    def _get_headers(self, include_auth: bool = True) -> Dict[str, str]:
        """获取请求头"""
        headers = {
            'Content-Type': 'application/json',
            'Accept': 'application/json'
        }
        
        if include_auth and self.token:
            headers['Authorization'] = f"Bearer {self.token}"
        
        return headers
    
    def get(self, path: str, params: Optional[Dict] = None, include_auth: bool = True) -> requests.Response:
        """GET 请求"""
        url = self._build_url(path)
        headers = self._get_headers(include_auth)
        
        response = self.session.get(
            url,
            headers=headers,
            params=params,
            timeout=self.timeout
        )
        
        return response
    
    def post(self, path: str, data: Optional[Dict] = None, json: Optional[Dict] = None, 
             include_auth: bool = True) -> requests.Response:
        """POST 请求"""
        url = self._build_url(path)
        headers = self._get_headers(include_auth)
        
        response = self.session.post(
            url,
            headers=headers,
            data=data,
            json=json,
            timeout=self.timeout
        )
        
        return response
    
    def put(self, path: str, data: Optional[Dict] = None, json: Optional[Dict] = None,
            include_auth: bool = True) -> requests.Response:
        """PUT 请求"""
        url = self._build_url(path)
        headers = self._get_headers(include_auth)
        
        response = self.session.put(
            url,
            headers=headers,
            data=data,
            json=json,
            timeout=self.timeout
        )
        
        return response
    
    def delete(self, path: str, include_auth: bool = True) -> requests.Response:
        """DELETE 请求"""
        url = self._build_url(path)
        headers = self._get_headers(include_auth)
        
        response = self.session.delete(
            url,
            headers=headers,
            timeout=self.timeout
        )
        
        return response
    
    def cleanup_resource(self, resource_type: str, resource_id: int) -> bool:
        """清理测试资源"""
        try:
            response = self.delete(f'/api/{resource_type}/{resource_id}')
            return response.status_code == 200
        except Exception as e:
            print(f"清理资源失败: {e}")
            return False


class APIFixture:
    """API 测试固定装置，提供测试数据管理"""
    
    def __init__(self, api_client: BaseAPIClient):
        self.api_client = api_client
        self.created_users = []
        self.created_roles = []
        self.created_menus = []
        self.created_configs = []
        self.created_dicts = []
    
    def cleanup(self):
        """清理所有创建的测试数据"""
        print("\n🧹 清理测试数据...")
        
        # 清理用户
        for user_id in self.created_users:
            self.api_client.cleanup_resource('users', user_id)
        self.created_users.clear()
        
        # 清理角色
        for role_id in self.created_roles:
            self.api_client.cleanup_resource('roles', role_id)
        self.created_roles.clear()
        
        # 清理菜单
        for menu_id in self.created_menus:
            self.api_client.cleanup_resource('menus', menu_id)
        self.created_menus.clear()
        
        # 清理配置
        for config_id in self.created_configs:
            self.api_client.cleanup_resource('config', config_id)
        self.created_configs.clear()
        
        # 清理字典
        for dict_id in self.created_dicts:
            self.api_client.cleanup_resource('dict', dict_id)
        self.created_dicts.clear()
        
        print("✅ 测试数据清理完成")


class AsyncAPIClient:
    """异步 API 客户端，使用 httpx"""
    
    def __init__(self, client: httpx.AsyncClient):
        self.client = client
        self.token: Optional[str] = None
        self.user_id: Optional[int] = None
    
    def set_auth(self, token: str, user_id: int = None):
        """设置认证信息"""
        self.token = token
        self.user_id = user_id
        self.client.headers.update({'Authorization': f'Bearer {token}'})
    
    async def login(self, username: str, password: str) -> httpx.Response:
        """登录并获取 Token"""
        response = await self.client.post(
            '/api/auth/login',
            json={'username': username, 'password': password}
        )
        
        if response.status_code == 200:
            data = response.json()
            self.token = data.get('token')
            self.user_id = data.get('userId')
            print(f"✅ 登录成功: {username} (User ID: {self.user_id})")
        
        return response
    
    async def get(self, path: str, params: Optional[Dict] = None) -> httpx.Response:
        """GET 请求"""
        return await self.client.get(path, params=params)
    
    async def post(self, path: str, json: Optional[Dict] = None) -> httpx.Response:
        """POST 请求"""
        return await self.client.post(path, json=json)
    
    async def put(self, path: str, json: Optional[Dict] = None) -> httpx.Response:
        """PUT 请求"""
        return await self.client.put(path, json=json)
    
    async def delete(self, path: str) -> httpx.Response:
        """DELETE 请求"""
        return await self.client.delete(path)
