import time
import requests
import loguru
from typing import List, Dict, Any
from concurrent.futures import ThreadPoolExecutor, as_completed
from util.proxy.ProxyManager import ProxyManager


# 代理连通性测试工具
class ProxyTester:
    def __init__(self, timeout: int = 10):
        self.timeout = timeout

    # 测试单个代理连通性
    def test_single_proxy(self, proxy: str) -> Dict[str, Any]:
        result = {
            "proxy": ProxyManager.mask_proxy_value(proxy) or proxy,
            "status": "failed",
            "response_time": None,
            "error": None,
            "ip_info": None,
        }

        try:
            session = requests.Session()
            proxy = ProxyManager.normalize_proxy_value(proxy)
            if proxy != "none" and not self._validate_proxy_format(proxy):
                result["error"] = "代理格式无效"
                return result
            ProxyManager(proxy).apply_to_session(session)

            # 测试连通性和响应时间
            start_time = time.time()
            response = session.get(
                "https://api.bilibili.com/x/web-interface/nav",
                timeout=self.timeout,
                headers={
                    "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36 Edg/126.0.0.0",
                },
            )
            end_time = time.time()
            response_time = round((end_time - start_time) * 1000, 2)  # 毫秒

            if response.status_code == 200:
                result["status"] = "success"
                result["response_time"] = response_time
                # 获取出口IP信息
                result["ip_info"] = self._get_ip_info(session)
            else:
                result["error"] = f"B站连接失败: HTTP {response.status_code}"
                result["status"] = "partial"
                result["response_time"] = response_time
                # 部分成功时也尝试获取IP
                result["ip_info"] = self._get_ip_info(session)
        except requests.exceptions.Timeout:
            result["error"] = f"连接超时 (>{self.timeout}s)"
        except requests.exceptions.ProxyError:
            result["error"] = "代理服务器错误或无法连接"
        except requests.exceptions.ConnectionError as e:
            if "proxy" in str(e).lower():
                result["error"] = "代理连接失败"
            else:
                result["error"] = "网络连接失败"
        except Exception as e:
            result["error"] = f"未知错误: {str(e)}"

        return result

    def _get_ip_info(self, session) -> str:
        """获取出口IP信息"""
        # 服务列表：优先详细信息，然后降级到基础服务
        ip_services = [
            {
                "name": "ip-api.com",
                "url": "http://ip-api.com/json/",
                "parser": lambda data: (
                    f"{data.get('query', '未知')} ({data.get('city', '未知')}, {data.get('isp', '未知')})"
                ),
            },
            {
                "name": "httpbin.org",
                "url": "http://httpbin.org/ip",
                "parser": lambda data: data.get("origin", "未知"),
            },
        ]

        for service in ip_services:
            try:
                ip_response = session.get(service["url"], timeout=3)
                if ip_response.status_code == 200:
                    ip_data = ip_response.json()
                    return service["parser"](ip_data)
            except Exception:
                continue

        return "IP获取失败"

    # 验证代理格式是否正确
    def _validate_proxy_format(self, proxy: str) -> bool:
        try:
            # 基本格式检查
            if not proxy or proxy.strip() == "":
                return False

            # 检查是否包含协议
            if not any(
                proxy.startswith(protocol)
                for protocol in ["http://", "https://", "socks5://", "socks4://"]
            ):
                return False

            # 检查是否包含端口
            if ":" not in proxy.split("://")[1]:
                return False

            return True
        except Exception:
            return False

    # 测试代理列表的连通性
    def test_proxy_list(
        self, proxy_string: str, max_workers: int = 5
    ) -> List[Dict[str, Any]]:
        proxy_list = ProxyManager.parse_proxy_list(
            proxy_string,
            include_direct_fallback=True,
        )
        if not proxy_list:
            proxy_list = ["none"]

        results = []
        # 使用线程池并发测试
        with ThreadPoolExecutor(max_workers=max_workers) as executor:
            future_to_proxy = {
                executor.submit(self.test_single_proxy, proxy): proxy
                for proxy in proxy_list
            }

            for future in as_completed(future_to_proxy):
                try:
                    result = future.result()
                    results.append(result)
                    loguru.logger.info(
                        f"代理测试完成: {result['proxy']} - {result['status']}"
                    )
                except Exception as e:
                    loguru.logger.error(f"代理测试异常: {e}")

        # 按照原始顺序排序结果（直连在前，然后是代理）
        def get_sort_key(result):
            proxy = result["proxy"]
            if proxy == "直连" or proxy.lower() in ["none", "direct"]:
                return (0, proxy)
            else:
                try:
                    raw_proxy = next(
                        (
                            item
                            for item in proxy_list
                            if ProxyManager.mask_proxy_value(item) == proxy
                        ),
                        proxy,
                    )
                    return (1, proxy_list.index(raw_proxy))
                except ValueError:
                    return (2, proxy)

        results.sort(key=get_sort_key)
        return results

    # 格式化测试结果为可读文本
    def format_test_results(self, results: List[Dict[str, Any]]) -> str:
        output = []
        output.append("代理连通性测试结果:")
        output.append("=" * 50)

        success_count = 0
        for i, result in enumerate(results, 1):
            proxy = result["proxy"]
            status = result["status"]
            response_time = result["response_time"]
            error = result["error"]
            ip_info = result["ip_info"]

            if status == "success":
                output.append(f"✅ [{i}] {proxy}")
                output.append(f"    响应时间: {response_time}ms")
                if ip_info and ip_info != "IP获取失败":
                    output.append(f"    出口IP: {ip_info}")
                success_count += 1
            elif status == "partial":
                output.append(f"⚠️  [{i}] {proxy}")
                output.append(f"    响应时间: {response_time}ms")
                if ip_info and ip_info != "IP获取失败":
                    output.append(f"    出口IP: {ip_info}")
                output.append(f"    警告: {error}")
            else:
                output.append(f"❌ [{i}] {proxy}")
                output.append(f"    错误: {error}")

            output.append("")

        output.append("=" * 50)
        output.append(f"测试统计: {success_count}/{len(results)} 个代理可用")
        return "\n".join(output)


def test_proxy_connectivity(proxy_string: str = "none", timeout: int = 10) -> str:
    tester = ProxyTester(timeout=timeout)
    results = tester.test_proxy_list(proxy_string)
    return tester.format_test_results(results)
