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

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 sfi.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
    formats = ["txt", "json", "xml", "html", "csv", "md"]

    for i in range(10):  # Create 10 files per format
        for fmt in formats:
            if fmt == "txt":
                filename = test_dir / f"test_{i:04d}.txt"
                filename.write_text(test_content)
            elif fmt == "json":
                filename = test_dir / f"test_{i:04d}.json"
                data = {
                    "content": test_content,
                    "metadata": {"id": i, "format": "json"},
                }
                filename.write_text(json.dumps(data, indent=2))
            elif fmt == "xml":
                filename = test_dir / f"test_{i:04d}.xml"
                xml_content = f'<?xml version="1.0"?><document><content><![CDATA[{test_content}]]></content></document>'
                filename.write_text(xml_content)
            elif fmt == "html":
                filename = test_dir / f"test_{i:04d}.html"
                html_content = f"<!DOCTYPE html><html><body><pre>{test_content}</pre></body></html>"
                filename.write_text(html_content)
            elif fmt == "csv":
                filename = test_dir / f"test_{i:04d}.csv"
                lines = test_content.strip().split("\n")
                csv_content = "\n".join([f'"{line}"' for line in lines])
                filename.write_text(csv_content)
            elif fmt == "md":
                filename = test_dir / f"test_{i:04d}.md"
                md_content = f"# Test Document {i}\n\n```\n{test_content}\n```"
                filename.write_text(md_content)

    total_files = len(list(test_dir.glob("*")))
    print(f"\n✓ Created {total_files} test documents in {test_dir}")

    return test_dir


@pytest.mark.benchmark(group="file_types")
@pytest.mark.parametrize("file_type", ["txt", "json", "xml", "html", "csv", "md"])
def test_benchmark_scan_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=1, show_progress=False)

    results = benchmark(scan_files)

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


@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="process_pool")
@pytest.mark.parametrize("processes", [1, 2, 4])
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."""

    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


@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


@pytest.mark.benchmark(group="comparison")
@pytest.mark.parametrize("use_process_pool,workers", [(False, 4), (True, 2)])
def test_benchmark_thread_pool_vs_process_pool(
    use_process_pool: bool,
    workers: int,
    benchmark_test_docs: Path,
    benchmark_rules: list[Rule],
    benchmark: Any,
) -> None:
    """Compare thread pool vs process pool performance."""

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

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

    results = benchmark(scan_files)

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


@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 with different numbers of rules."""

    # Create rules
    rules = [
        Rule({"name": f"rule_{i}", "pattern": f"test_{i}", "regex": False, "context_lines": 1})
        for i in range(rule_count)
    ]

    scanner = DocumentScanner(
        benchmark_test_docs,
        rules,
        ["txt"],
        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


@pytest.mark.benchmark(group="file_collection")
def test_benchmark_file_collection(benchmark_test_docs: Path, benchmark_rules: list[Rule], benchmark: Any) -> None:
    """Benchmark file collection performance."""

    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 collect_files():
        return scanner._collect_files()

    files = benchmark(collect_files)

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


@pytest.mark.benchmark(group="text_extraction")
@pytest.mark.parametrize("file_type", ["txt", "json", "xml", "html"])
def test_benchmark_text_extraction(file_type: str, benchmark_test_docs: Path, benchmark: Any) -> None:
    """Benchmark text extraction for different file types."""

    # Get first file of the specified type
    files = list(benchmark_test_docs.glob(f"*.{file_type}"))
    if not files:
        pytest.skip(f"No test files for type: {file_type}")

    test_file = files[0]

    scanner = DocumentScanner(
        benchmark_test_docs,
        [Rule({"name": "test", "pattern": "test"})],
        [file_type],
        use_pdf_ocr=False,
        use_process_pool=False,
        batch_size=50,
    )

    def extract_text():
        return scanner._scan_file(test_file)

    result = benchmark(extract_text)

    assert result is not None


@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 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


def test_benchmark_summary(benchmark_test_docs: Path, benchmark_rules: list[Rule]) -> None:
    """Generate a summary of all benchmark results.

    This test doesn't actually run benchmarks but provides information
    about what was tested.
    """
    # Count files by type
    file_counts = {}
    for file_path in benchmark_test_docs.glob("*"):
        ext = file_path.suffix.lstrip(".")
        file_counts[ext] = file_counts.get(ext, 0) + 1

    total_files = len(list(benchmark_test_docs.glob("*")))

    print("\n" + "=" * 60)
    print("BENCHMARK SUMMARY")
    print("=" * 60)
    print(f"Total test files: {total_files}")
    print(f"File types: {len(file_counts)}")
    print("\nFiles by type:")
    for ext, count in sorted(file_counts.items()):
        print(f"  - {ext}: {count} files")
    print(f"\nRules configured: {len(benchmark_rules)}")
    print("=" * 60 + "\n")
