"""Performance benchmarks for docscan module using pytest-benchmark.

Note: Process pool benchmarks are skipped on Windows due to compatibility issues
with pytest-benchmark module-scoped fixtures. Use thread pool benchmarks instead.
"""

from __future__ import annotations

import json

# Import module being tested
import sys
from pathlib import Path
from typing import Any

import pytest

sys.path.insert(0, str(Path(__file__).parent.parent))
from pytola.office.docscan.docscan import DocumentScanner, Rule


@pytest.fixture(scope="module")
def benchmark_rules():
    """Load comprehensive rules for benchmarking."""
    rules_data = {
        "rules": [
            {
                "name": "email",
                "pattern": r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}",
                "regex": True,
                "context_lines": 1,
            },
            {
                "name": "phone",
                "pattern": r"\d{3}-\d{3}-\d{4}",
                "regex": True,
                "context_lines": 1,
            },
            {
                "name": "url",
                "pattern": r"https?://[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}",
                "regex": True,
                "context_lines": 1,
            },
        ]
    }
    return [Rule(rule) for rule in rules_data["rules"]]


@pytest.fixture(scope="module")
def benchmark_test_docs(tmp_path_factory):
    """Create test documents for benchmarking."""
    test_dir = tmp_path_factory.mktemp("benchmark_docs")

    test_content = """
    Performance Test Document

    Contact Information:
    Email: test.user@example.com
    Email: admin@company.org
    Email: support@service.net

    Phone Numbers:
    Office: 555-123-4567
    Mobile: +1-555-987-6543
    Fax: 555-555-5555

    URLs:
    Website: https://www.example.com
    API: https://api.example.com/v1/users
    Docs: http://docs.example.com/guide
    """

    # Create test files in various formats
    for i in range(20):
        # Text files
        with open(test_dir / f"test_{i}.txt", "w", encoding="utf-8") as f:
            f.write(test_content * (i % 5 + 1))

        # JSON files
        with open(test_dir / f"data_{i}.json", "w", encoding="utf-8") as f:
            json.dump(
                {"content": test_content * (i % 3 + 1), "index": i},
                f,
                ensure_ascii=False,
            )

        # XML files
        xml_content = f"""<?xml version="1.0" encoding="UTF-8"?>
        <root>
            <content><![CDATA[{test_content}]]></content>
            <index>{i}</index>
        </root>
        """
        with open(test_dir / f"document_{i}.xml", "w", encoding="utf-8") as f:
            f.write(xml_content)

        # HTML files
        html_content = f"""
        <!DOCTYPE html>
        <html>
        <head><title>Test Document {i}</title></head>
        <body>
            <p>{test_content}</p>
        </body>
        </html>
        """
        with open(test_dir / f"page_{i}.html", "w", encoding="utf-8") as f:
            f.write(html_content)

        # CSV files
        csv_content = """email,phone,url
        test.user@example.com,555-123-4567,https://www.example.com
        admin@company.org,555-987-6543,https://api.example.com/v1/users
        support@service.net,555-555-5555,http://docs.example.com/guide
        """ * (i % 3 + 1)
        with open(test_dir / f"records_{i}.csv", "w", encoding="utf-8") as f:
            f.write(csv_content)

        # Markdown files
        md_content = f"""
        # Test Document {i}

        {test_content}

        ---
        Generated for benchmark testing
        """
        with open(test_dir / f"doc_{i}.md", "w", encoding="utf-8") as f:
            f.write(md_content)

    return test_dir


# ==================== File Type Benchmarks ====================


@pytest.mark.benchmark(group="file_types")
@pytest.mark.parametrize("file_type", ["txt", "json", "xml", "html", "csv", "md"])
def test_benchmark_by_file_type(
    file_type: str,
    benchmark_test_docs: Path,
    benchmark_rules: list[Rule],
    benchmark: Any,
) -> None:
    """Benchmark scanning different file types."""
    scanner = DocumentScanner(
        benchmark_test_docs,
        benchmark_rules,
        [file_type],
        use_pdf_ocr=False,
        use_process_pool=False,
        batch_size=50,
    )

    def scan_files():
        return scanner.scan(threads=4, show_progress=False)

    results = benchmark(scan_files)

    # Verify results
    assert results is not None
    assert "scan_info" in results
    assert results["scan_info"]["total_files"] > 0


# ==================== Thread Pool Benchmarks ====================


@pytest.mark.benchmark(group="thread_pool")
@pytest.mark.parametrize("threads", [1, 2, 4, 8])
def test_benchmark_thread_pool(
    threads: int, benchmark_test_docs: Path, benchmark_rules: list[Rule], benchmark: Any
) -> None:
    """Benchmark thread pool with different thread counts."""
    scanner = DocumentScanner(
        benchmark_test_docs,
        benchmark_rules,
        ["txt", "json", "xml", "html", "csv", "md"],
        use_pdf_ocr=False,
        use_process_pool=False,
        batch_size=50,
    )

    def scan_files():
        return scanner.scan(threads=threads, show_progress=False)

    results = benchmark(scan_files)

    assert results is not None
    assert "scan_info" in results
    assert results["scan_info"]["total_files"] > 0


@pytest.mark.benchmark(group="thread_pool")
@pytest.mark.parametrize("threads", [1, 2, 4, 8])
def test_benchmark_thread_pool_complex(
    threads: int, benchmark_test_docs: Path, benchmark_rules: list[Rule], benchmark: Any
) -> None:
    """Benchmark thread pool with complex rules."""
    scanner = DocumentScanner(
        benchmark_test_docs,
        benchmark_rules,
        ["txt", "json", "xml"],
        use_pdf_ocr=False,
        use_process_pool=False,
        batch_size=50,
    )

    def scan_files():
        return scanner.scan(threads=threads, show_progress=False)

    results = benchmark(scan_files)

    assert results is not None
    assert "scan_info" in results


# ==================== Rule Complexity Benchmarks ====================


@pytest.mark.benchmark(group="rule_complexity")
@pytest.mark.parametrize("rule_count", [1, 3, 5, 10])
def test_benchmark_rule_complexity(rule_count: int, benchmark_test_docs: Path, benchmark: Any) -> None:
    """Benchmark scanning with different rule counts."""
    # Create rules dynamically
    rules = []
    for i in range(rule_count):
        rules.append(
            Rule(
                {
                    "name": f"pattern_{i}",
                    "pattern": rf"pattern_{i}",
                    "regex": False,
                    "context_lines": 1,
                }
            )
        )

    scanner = DocumentScanner(
        benchmark_test_docs,
        rules,
        ["txt", "json"],
        use_pdf_ocr=False,
        use_process_pool=False,
        batch_size=50,
    )

    def scan_files():
        return scanner.scan(threads=4, show_progress=False)

    results = benchmark(scan_files)

    assert results is not None
    assert "scan_info" in results


# ==================== File Collection Benchmarks ====================


@pytest.mark.benchmark(group="file_collection")
def test_benchmark_file_collection(benchmark_test_docs: Path, benchmark: Any) -> None:
    """Benchmark file discovery and collection."""
    scanner = DocumentScanner(
        benchmark_test_docs,
        [],
        ["txt", "json", "xml", "html", "csv", "md"],
        use_pdf_ocr=False,
        use_process_pool=False,
    )

    def collect_files():
        return scanner._collect_files()

    results = benchmark(collect_files)

    assert results is not None
    assert len(results) > 0


# ==================== Text Extraction Benchmarks ====================


@pytest.mark.benchmark(group="text_extraction")
@pytest.mark.parametrize("file_type", ["txt", "json", "xml", "html", "csv", "md"])
def test_benchmark_text_extraction(file_type: str, benchmark_test_docs: Path, benchmark: Any) -> None:
    """Benchmark text extraction by file type."""
    scanner = DocumentScanner(
        benchmark_test_docs,
        [],
        [file_type],
        use_pdf_ocr=False,
    )

    # Get test files
    files = list(benchmark_test_docs.glob(f"*.{file_type}"))

    def extract_text():
        total_text = ""
        for file in files:
            text, _ = scanner._extract_text(file)
            total_text += text
        return total_text

    results = benchmark(extract_text)

    assert results is not None


# ==================== Batch Size Benchmarks ====================


@pytest.mark.benchmark(group="batch_size")
@pytest.mark.parametrize("batch_size", [10, 50, 100, 200])
def test_benchmark_batch_size(
    batch_size: int,
    benchmark_test_docs: Path,
    benchmark_rules: list[Rule],
    benchmark: Any,
) -> None:
    """Benchmark scanning with different batch sizes."""
    scanner = DocumentScanner(
        benchmark_test_docs,
        benchmark_rules,
        ["txt", "json", "xml"],
        use_pdf_ocr=False,
        use_process_pool=False,
        batch_size=batch_size,
    )

    def scan_files():
        return scanner.scan(threads=4, show_progress=False)

    results = benchmark(scan_files)

    assert results is not None
    assert "scan_info" in results


# ==================== Process Pool Benchmarks (Skipped on Windows) ====================


@pytest.mark.benchmark(group="process_pool")
@pytest.mark.parametrize("processes", [1, 2, 4])
@pytest.mark.skip(
    reason=(
        "Process pool benchmarks skipped due to Windows compatibility issues "
        "with pytest-benchmark module-scoped fixtures. Use thread pool benchmarks instead."
    )
)
def test_benchmark_process_pool(
    processes: int,
    benchmark_test_docs: Path,
    benchmark_rules: list[Rule],
    benchmark: Any,
) -> None:
    """Benchmark process pool with different process counts.

    Note: This test is skipped by default on Windows due to compatibility issues.
    To run on Linux/macOS, use: pytest --benchmark-only -k test_benchmark_process_pool -k "not skip"
    """
    scanner = DocumentScanner(
        benchmark_test_docs,
        benchmark_rules,
        ["txt", "json", "xml", "html", "csv", "md"],
        use_pdf_ocr=False,
        use_process_pool=True,
        batch_size=50,
    )

    def scan_files():
        return scanner.scan(threads=processes, show_progress=False)

    results = benchmark(scan_files)

    assert results is not None
    assert "scan_info" in results
    assert results["scan_info"]["total_files"] > 0


# ==================== Comparison Benchmarks ====================


@pytest.mark.benchmark(group="comparison")
@pytest.mark.parametrize("threads", [1, 4])
def test_benchmark_single_thread_vs_4_threads(
    threads: int, benchmark_test_docs: Path, benchmark_rules: list[Rule], benchmark: Any
) -> None:
    """Compare single thread vs 4 threads performance."""
    scanner = DocumentScanner(
        benchmark_test_docs,
        benchmark_rules,
        ["txt", "json", "xml"],
        use_pdf_ocr=False,
        use_process_pool=False,
        batch_size=50,
    )

    def scan_files():
        return scanner.scan(threads=threads, show_progress=False)

    results = benchmark(scan_files)

    # Verify results
    assert results is not None
    assert "scan_info" in results
