"""
CFspider 内置本地代理服务器
将浏览器的 HTTP 请求转发到 Cloudflare Workers
"""

import threading
import socket
import ssl
import requests
from http.server import HTTPServer, BaseHTTPRequestHandler
from urllib.parse import urlparse, urlencode


class ProxyHandler(BaseHTTPRequestHandler):
    """HTTP 代理请求处理器"""
    
    cf_proxies = None
    timeout = 30
    
    def log_message(self, format, *args):
        """禁用日志输出"""
        pass
    
    def do_CONNECT(self):
        """处理 HTTPS CONNECT 请求"""
        # 解析目标地址
        host, port = self.path.split(':')
        port = int(port)
        
        # 建立到目标的连接（通过 Workers 代理）
        # 由于 Workers 不支持 CONNECT，我们需要用 Man-in-the-Middle 方式
        # 向客户端发送连接成功
        self.send_response(200, 'Connection Established')
        self.end_headers()
        
        # 创建 SSL 上下文用于与客户端通信
        # 这里我们使用一个简化的方式：直接转发数据
        # 实际的 HTTPS 请求会在 SSL 握手后通过 HTTP 方法处理
        
        # 获取客户端 socket
        client_socket = self.connection
        
        # 创建到目标服务器的连接
        try:
            target_socket = socket.create_connection((host, port), timeout=self.timeout)
            if port == 443:
                context = ssl.create_default_context()
                target_socket = context.wrap_socket(target_socket, server_hostname=host)
            
            # 双向转发数据
            client_socket.setblocking(False)
            target_socket.setblocking(False)
            
            while True:
                try:
                    data = client_socket.recv(8192)
                    if data:
                        target_socket.sendall(data)
                    else:
                        break
                except (BlockingIOError, ssl.SSLWantReadError):
                    pass
                
                try:
                    data = target_socket.recv(8192)
                    if data:
                        client_socket.sendall(data)
                    else:
                        break
                except (BlockingIOError, ssl.SSLWantReadError):
                    pass
                    
        except Exception as e:
            pass
        finally:
            try:
                target_socket.close()
            except:
                pass
    
    def do_GET(self):
        """处理 GET 请求"""
        self._proxy_request('GET')
    
    def do_POST(self):
        """处理 POST 请求"""
        self._proxy_request('POST')
    
    def do_PUT(self):
        """处理 PUT 请求"""
        self._proxy_request('PUT')
    
    def do_DELETE(self):
        """处理 DELETE 请求"""
        self._proxy_request('DELETE')
    
    def do_HEAD(self):
        """处理 HEAD 请求"""
        self._proxy_request('HEAD')
    
    def do_OPTIONS(self):
        """处理 OPTIONS 请求"""
        self._proxy_request('OPTIONS')
    
    def do_PATCH(self):
        """处理 PATCH 请求"""
        self._proxy_request('PATCH')
    
    def _proxy_request(self, method):
        """通过 Workers 代理请求"""
        try:
            # 获取目标 URL
            target_url = self.path
            if not target_url.startswith('http'):
                # 如果是相对路径，从 Host 头构建完整 URL
                host = self.headers.get('Host', '')
                target_url = f"http://{host}{self.path}"
            
            # 读取请求体
            content_length = int(self.headers.get('Content-Length', 0))
            body = self.rfile.read(content_length) if content_length > 0 else None
            
            # 构建请求头
            headers = {}
            for key, value in self.headers.items():
                if key.lower() not in ['host', 'proxy-connection', 'proxy-authorization']:
                    headers[f'x-cfspider-header-{key}'] = value
            
            # 构建 Workers 代理 URL
            proxy_url = f"{self.cf_proxies.rstrip('/')}/proxy"
            params = {
                'url': target_url,
                'method': method
            }
            
            # 发送请求到 Workers
            response = requests.post(
                proxy_url,
                params=params,
                headers=headers,
                data=body,
                timeout=self.timeout,
                stream=True
            )
            
            # 发送响应
            self.send_response(response.status_code)
            for key, value in response.headers.items():
                if key.lower() not in ['transfer-encoding', 'content-encoding', 'content-length']:
                    self.send_header(key, value)
            
            content = response.content
            self.send_header('Content-Length', len(content))
            self.end_headers()
            self.wfile.write(content)
            
        except Exception as e:
            self.send_error(502, f'Proxy Error: {str(e)}')


class LocalProxyServer:
    """本地代理服务器"""
    
    def __init__(self, cf_proxies, timeout=30):
        """
        初始化本地代理服务器
        
        Args:
            cf_proxies: Workers 地址，如 "https://ip.kami666.xyz"
            timeout: 请求超时时间（秒）
        """
        self.cf_proxies = cf_proxies
        self.timeout = timeout
        self.server = None
        self.thread = None
        self.port = None
    
    def start(self):
        """
        启动代理服务器
        
        Returns:
            int: 代理服务器端口号
        """
        # 找一个可用端口
        with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
            s.bind(('127.0.0.1', 0))
            self.port = s.getsockname()[1]
        
        # 配置处理器
        handler = ProxyHandler
        handler.cf_proxies = self.cf_proxies
        handler.timeout = self.timeout
        
        # 创建服务器
        self.server = HTTPServer(('127.0.0.1', self.port), handler)
        
        # 在后台线程运行
        self.thread = threading.Thread(target=self._run, daemon=True)
        self.thread.start()
        
        return self.port
    
    def _run(self):
        """运行服务器"""
        self.server.serve_forever()
    
    def stop(self):
        """停止代理服务器"""
        if self.server:
            self.server.shutdown()
            self.server = None
        self.thread = None
        self.port = None
    
    @property
    def proxy_url(self):
        """获取代理 URL"""
        if self.port:
            return f"http://127.0.0.1:{self.port}"
        return None

