"""
测试：表格提取加速方案
"""
import pytest
import asyncio
from pathlib import Path

from playwright_ez import EasyBrowser


# ============================================================
# 测试用HTML页面
# ============================================================

SIMPLE_TABLE_HTML = """
<!DOCTYPE html>
<html>
<head><title>Simple Table Test</title></head>
<body>
<table id="test-table">
    <tr>
        <th>姓名</th>
        <th>年龄</th>
        <th>城市</th>
    </tr>
    <tr>
        <td>张三</td>
        <td>25</td>
        <td>北京</td>
    </tr>
    <tr>
        <td>李四</td>
        <td>30</td>
        <td>上海</td>
    </tr>
    <tr>
        <td>王五</td>
        <td>28</td>
        <td>广州</td>
    </tr>
</table>
</body>
</html>
"""

COMPLEX_TABLE_HTML = """
<!DOCTYPE html>
<html>
<head><title>Complex Table Test</title></head>
<body>
<table class="data-table">
    <thead>
        <tr>
            <th>ID</th>
            <th>产品名称</th>
            <th>价格</th>
            <th>库存</th>
        </tr>
    </thead>
    <tbody>
        <tr><td>1</td><td>笔记本电脑</td><td>¥5999</td><td>50</td></tr>
        <tr><td>2</td><td>无线鼠标</td><td>¥99</td><td>200</td></tr>
        <tr><td>3</td><td>机械键盘</td><td>¥399</td><td>100</td></tr>
        <tr><td>4</td><td>显示器</td><td>¥1299</td><td>30</td></tr>
        <tr><td>5</td><td>耳机</td><td>¥299</td><td>150</td></tr>
    </tbody>
</table>

<table class="summary-table">
    <tr><th>统计项</th><th>数值</th></tr>
    <tr><td>总计</td><td>5件商品</td></tr>
</table>
</body>
</html>
"""

LARGE_TABLE_HTML = """
<!DOCTYPE html>
<html>
<head><title>Large Table Test</title></head>
<body>
<table id="large-table">
    <tr>
        <th>序号</th>
        <th>数据</th>
    </tr>
    %s
</table>
</body>
</html>
""" % "".join([f"<tr><td>{i}</td><td>数据{i}</td></tr>" for i in range(1, 101)])

# 模拟动态数据加载的页面
DYNAMIC_TABLE_HTML = """
<!DOCTYPE html>
<html>
<head>
    <title>Dynamic Table Test</title>
    <script>
        document.addEventListener('DOMContentLoaded', function() {
            setTimeout(function() {
                const table = document.getElementById('dynamic-table');
                const tbody = table.querySelector('tbody');
                for (let i = 1; i <= 5; i++) {
                    const tr = document.createElement('tr');
                    tr.innerHTML = `<td>项目${i}</td><td>值${i}</td>`;
                    tbody.appendChild(tr);
                }
            }, 100);
        });
    </script>
</head>
<body>
<table id="dynamic-table">
    <thead>
        <tr><th>项目</th><th>值</th></tr>
    </thead>
    <tbody></tbody>
</table>
</body>
</html>
"""


# ============================================================
# Fixtures
# ============================================================

@pytest.fixture
async def browser():
    """创建浏览器实例"""
    async with EasyBrowser() as browser:
        yield browser


@pytest.fixture
def test_html_dir(tmp_path):
    """创建临时HTML文件目录"""
    html_dir = tmp_path / "html"
    html_dir.mkdir()

    # 创建测试HTML文件
    (html_dir / "simple.html").write_text(SIMPLE_TABLE_HTML, encoding="utf-8")
    (html_dir / "complex.html").write_text(COMPLEX_TABLE_HTML, encoding="utf-8")
    (html_dir / "large.html").write_text(LARGE_TABLE_HTML, encoding="utf-8")
    (html_dir / "dynamic.html").write_text(DYNAMIC_TABLE_HTML, encoding="utf-8")

    return html_dir


# ============================================================
# 测试用例：基础表格提取
# ============================================================

@pytest.mark.asyncio
async def test_extract_table_basic(browser, test_html_dir):
    """测试基础表格提取（evaluate方案）"""
    html_file = test_html_dir / "simple.html"
    await browser.goto(f"file://{html_file}")

    data = await browser.extractor.extract_table("#test-table")

    assert len(data) == 3
    assert data[0]["姓名"] == "张三"
    assert data[0]["年龄"] == "25"
    assert data[1]["城市"] == "上海"


@pytest.mark.asyncio
async def test_extract_table_with_locator(browser, test_html_dir):
    """测试使用 Locator 提取表格"""
    html_file = test_html_dir / "complex.html"
    await browser.goto(f"file://{html_file}")

    locator = browser.page.locator(".data-table")
    data = await browser.extractor.extract_table(locator)

    assert len(data) == 5
    assert data[0]["产品名称"] == "笔记本电脑"
    assert data[2]["价格"] == "¥399"


# ============================================================
# 测试用例：HTML解析方案
# ============================================================

@pytest.mark.asyncio
async def test_extract_table_via_html_auto(browser, test_html_dir):
    """测试HTML解析方案（自动选择解析器）"""
    html_file = test_html_dir / "simple.html"
    await browser.goto(f"file://{html_file}")

    data = await browser.extractor.extract_table_via_html(
        "#test-table", parser="auto"
    )

    assert len(data) == 3
    assert data[0]["姓名"] == "张三"


@pytest.mark.asyncio
async def test_extract_table_via_html_lxml(browser, test_html_dir):
    """测试HTML解析方案（lxml解析器）"""
    html_file = test_html_dir / "complex.html"
    await browser.goto(f"file://{html_file}")

    data = await browser.extractor.extract_table_via_html(
        ".data-table", parser="lxml"
    )

    assert len(data) == 5
    assert "产品名称" in data[0]


@pytest.mark.asyncio
async def test_extract_table_via_html_builtin_parser(browser, test_html_dir):
    """测试HTML解析方案（内置解析器）"""
    html_file = test_html_dir / "simple.html"
    await browser.goto(f"file://{html_file}")

    data = await browser.extractor.extract_table_via_html(
        "#test-table", parser="html.parser"
    )

    assert len(data) == 3
    assert data[2]["姓名"] == "王五"


@pytest.mark.asyncio
async def test_extract_table_via_html_large(browser, test_html_dir):
    """测试HTML解析方案处理大表格"""
    html_file = test_html_dir / "large.html"
    await browser.goto(f"file://{html_file}")

    data = await browser.extractor.extract_table_via_html("#large-table")

    assert len(data) == 100
    assert data[0]["序号"] == "1"
    assert data[99]["数据"] == "数据100"


# ============================================================
# 测试用例：CDP协议方案
# ============================================================

@pytest.mark.asyncio
async def test_extract_table_via_cdp(browser, test_html_dir):
    """测试CDP协议方案"""
    html_file = test_html_dir / "simple.html"
    await browser.goto(f"file://{html_file}")

    data = await browser.extractor.extract_table_via_cdp("#test-table")

    # CDP可能在非Chromium浏览器上回退到evaluate
    assert len(data) == 3
    assert data[0]["姓名"] == "张三"


@pytest.mark.asyncio
async def test_extract_table_via_cdp_complex(browser, test_html_dir):
    """测试CDP协议方案处理复杂表格"""
    html_file = test_html_dir / "complex.html"
    await browser.goto(f"file://{html_file}")

    data = await browser.extractor.extract_table_via_cdp(".data-table")

    assert len(data) == 5


# ============================================================
# 测试用例：extract_table_fast 智能选择
# ============================================================

@pytest.mark.asyncio
async def test_extract_table_fast_auto(browser, test_html_dir):
    """测试智能快速提取（自动模式）"""
    html_file = test_html_dir / "simple.html"
    await browser.goto(f"file://{html_file}")

    data = await browser.extractor.extract_table_fast("#test-table", method="auto")

    assert len(data) == 3
    assert data[0]["姓名"] == "张三"


@pytest.mark.asyncio
async def test_extract_table_fast_html_method(browser, test_html_dir):
    """测试智能快速提取（强制HTML方法）"""
    html_file = test_html_dir / "complex.html"
    await browser.goto(f"file://{html_file}")

    data = await browser.extractor.extract_table_fast(
        ".data-table", method="html"
    )

    assert len(data) == 5


@pytest.mark.asyncio
async def test_extract_table_fast_evaluate_method(browser, test_html_dir):
    """测试智能快速提取（强制evaluate方法）"""
    html_file = test_html_dir / "simple.html"
    await browser.goto(f"file://{html_file}")

    data = await browser.extractor.extract_table_fast(
        "#test-table", method="evaluate"
    )

    assert len(data) == 3


@pytest.mark.asyncio
async def test_extract_table_fast_cdp_method(browser, test_html_dir):
    """测试智能快速提取（CDP方法）"""
    html_file = test_html_dir / "simple.html"
    await browser.goto(f"file://{html_file}")

    data = await browser.extractor.extract_table_fast(
        "#test-table", method="cdp"
    )

    assert len(data) == 3


# ============================================================
# 测试用例：动态内容处理
# ============================================================

@pytest.mark.asyncio
async def test_extract_table_dynamic_content(browser, test_html_dir):
    """测试动态加载的表格"""
    html_file = test_html_dir / "dynamic.html"
    await browser.goto(f"file://{html_file}")

    # 等待动态内容加载
    await browser.page.wait_for_timeout(200)

    # evaluate方案可以获取动态内容
    data = await browser.extractor.extract_table("#dynamic-table")
    assert len(data) == 5


@pytest.mark.asyncio
async def test_extract_table_via_html_dynamic_fallback(browser, test_html_dir):
    """测试HTML解析方案对动态内容的降级处理"""
    html_file = test_html_dir / "dynamic.html"
    await browser.goto(f"file://{html_file}")

    # 等待动态内容加载
    await browser.page.wait_for_timeout(200)

    # HTML解析会回退到evaluate获取动态内容
    data = await browser.extractor.extract_table_via_html("#dynamic-table")
    assert len(data) == 5


# ============================================================
# 测试用例：边界情况
# ============================================================

@pytest.mark.asyncio
async def test_extract_table_empty(browser, test_html_dir):
    """测试空表格"""
    empty_html = """
    <!DOCTYPE html>
    <html><body><table id="empty"><tr><th>列</th></tr></table></body></html>
    """
    html_file = test_html_dir / "empty.html"
    html_file.write_text(empty_html, encoding="utf-8")

    await browser.goto(f"file://{html_file}")
    data = await browser.extractor.extract_table("#empty")

    assert data == []


@pytest.mark.asyncio
async def test_extract_table_not_found(browser, test_html_dir):
    """测试表格不存在"""
    html_file = test_html_dir / "simple.html"
    await browser.goto(f"file://{html_file}")

    data = await browser.extractor.extract_table("#non-existent")
    assert data == []


@pytest.mark.asyncio
async def test_extract_table_multiple_tables(browser, test_html_dir):
    """测试多表格提取"""
    html_file = test_html_dir / "complex.html"
    await browser.goto(f"file://{html_file}")

    # 提取第一个表格
    data1 = await browser.extractor.extract_table(".data-table")
    assert len(data1) == 5

    # 提取第二个表格
    data2 = await browser.extractor.extract_table(".summary-table")
    assert len(data2) == 1


# ============================================================
# 性能对比测试
# ============================================================

@pytest.mark.asyncio
async def test_performance_comparison(browser, test_html_dir):
    """性能对比：evaluate vs HTML解析 vs CDP"""
    import time

    html_file = test_html_dir / "large.html"
    await browser.goto(f"file://{html_file}")

    # 预热
    await browser.extractor.extract_table("#large-table")

    # evaluate方案
    start = time.perf_counter()
    data_eval = await browser.extractor.extract_table("#large-table")
    time_eval = time.perf_counter() - start

    # HTML解析方案
    start = time.perf_counter()
    data_html = await browser.extractor.extract_table_via_html("#large-table")
    time_html = time.perf_counter() - start

    # CDP方案
    start = time.perf_counter()
    data_cdp = await browser.extractor.extract_table_via_cdp("#large-table")
    time_cdp = time.perf_counter() - start

    # 验证数据一致性
    assert len(data_eval) == len(data_html) == len(data_cdp) == 100

    # 输出性能对比
    print(f"\n性能对比 (100行表格):")
    print(f"  evaluate: {time_eval*1000:.2f}ms")
    print(f"  html解析: {time_html*1000:.2f}ms")
    print(f"  cdp:      {time_cdp*1000:.2f}ms")


if __name__ == "__main__":
    pytest.main([__file__, "-v", "-s"])
