#!/usr/bin/env python3
"""
DeepSeek 浏览器代理 — 持久化 Playwright session，自动处理 WAF。
通过 SOCKS5 隧道 → ARM32 家庭网络 → DeepSeek。
"""
import asyncio, json, sys
from playwright.async_api import async_playwright

LISTEN = ("127.0.0.1", 5555)
SOCKS5 = "socks5://127.0.0.1:2080"
DEEPSEEK_BASE = "https://chat.deepseek.com"


async def handle_client(reader, writer, page):
    try:
        data = await asyncio.wait_for(reader.read(65536), timeout=30)
        if not data:
            return
        request_text = data.decode("utf-8", errors="replace")
        lines = request_text.split("\r\n")
        if not lines:
            return

        parts = lines[0].split(" ")
        if len(parts) < 2:
            return
        method, path = parts[0], parts[1]

        headers = {}
        body_start = request_text.find("\r\n\r\n")
        body = ""
        if body_start >= 0:
            body = request_text[body_start + 4:]
            for line in lines[1:]:
                if ":" in line:
                    k, v = line.split(":", 1)
                    headers[k.strip().lower()] = v.strip()

        url = f"{DEEPSEEK_BASE}{path}"
        # 只保留安全的 header（过滤掉 curl 的特殊 header 和 cookie）
        safe_headers = {}
        for k, v in headers.items():
            if k in ("host", "content-length", "connection", "expect", "transfer-encoding", "cookie"):
                continue
            if any(c in k for c in '<>"{}[]\\^`|'):
                continue
            safe_headers[k] = v
        fetch_headers = json.dumps(safe_headers)

        result = await page.evaluate(f"""
            async () => {{
                try {{
                    const resp = await fetch({json.dumps(url)}, {{
                        method: {json.dumps(method)},
                        headers: {fetch_headers},
                        body: {json.dumps(body) if method != 'GET' and body else 'null'},
                        credentials: 'include',
                    }});
                    const text = await resp.text();
                    return {{ status: resp.status, headers: Object.fromEntries(resp.headers.entries()), body: text.substring(0, 50000) }};
                }} catch(e) {{
                    return {{ error: String(e) }};
                }}
            }}
        """)

        body_text = result.get("body", "")
        resp_headers = result.get("headers", {})
        status = result.get("status", 500)

        if "error" in result:
            print(f"  [ERR] fetch error: {result['error']}")
            body_text = result["error"]
            status = 502

        response = f"HTTP/1.1 {status} OK\r\n"
        response += f"Content-Length: {len(body_text.encode())}\r\n"
        response += f"Content-Type: {resp_headers.get('content-type', 'application/json')}\r\n"
        response += "Connection: close\r\n\r\n"
        response += body_text

        writer.write(response.encode())
        await writer.drain()

    except Exception as e:
        print(f"  [ERR] {e}")
    finally:
        try:
            writer.close()
        except Exception:
            pass


async def main():
    async with async_playwright() as p:
        browser = await p.chromium.launch(
            headless=True,
            args=["--no-sandbox", "--disable-gpu", "--disable-dev-shm-usage",
                  "--disable-setuid-sandbox", "--no-first-run", "--no-zygote",
                  "--single-process", "--disable-blink-features=AutomationControlled"],
        )
        context = await browser.new_context(
            proxy={"server": SOCKS5},
            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",
            viewport={"width": 1920, "height": 1080},
        )
        page = await context.new_page()
        await page.add_init_script(
            'Object.defineProperty(navigator,"webdriver",{get:()=>false});'
        )

        # 建立初始 session
        for attempt in range(10):
            print(f"[Proxy] 建立 DeepSeek session (尝试 {attempt+1}/10)...")
            try:
                await page.goto(f"{DEEPSEEK_BASE}/", wait_until="domcontentloaded", timeout=30000)
                await page.wait_for_load_state("networkidle", timeout=30000)
                await asyncio.sleep(3)
            except Exception as e:
                print(f"[Proxy] 页面加载失败: {e}")
                await asyncio.sleep(5)
                continue
            title = await page.title()
            print(f"[Proxy] 页面: {title}")
            if "ERROR" in title or "Verification" in title:
                print(f"[Proxy] 被拦截，等待重试...")
                await asyncio.sleep(5)
                continue
            break
        else:
            print("[Proxy] FATAL: 10 次尝试均失败")
            await browser.close()
            sys.exit(1)

        # 启动 HTTP 服务
        server = await asyncio.start_server(
            lambda r, w: handle_client(r, w, page), LISTEN[0], LISTEN[1]
        )
        print(f"[Proxy] 监听 {LISTEN[0]}:{LISTEN[1]}")

        # 定期刷新 session
        async def refresh():
            while True:
                await asyncio.sleep(600)
                print("[Proxy] 刷新 session...")
                try:
                    await page.goto(f"{DEEPSEEK_BASE}/", wait_until="domcontentloaded", timeout=30000)
                    await page.wait_for_load_state("networkidle", timeout=30000)
                    await asyncio.sleep(3)
                    print(f"[Proxy] 页面: {await page.title()}")
                except Exception as e:
                    print(f"[Proxy] 刷新失败: {e}")

        asyncio.create_task(refresh())
        await server.serve_forever()


if __name__ == "__main__":
    asyncio.run(main())