"""Performance benchmark tests using pytest-benchmark.

This module demonstrates performance testing best practices using pytest-benchmark.
Benchmarks help detect performance regressions and establish performance baselines
for critical functions and CLI operations.

Key concepts demonstrated:
- Function-level performance benchmarking
- CLI performance and overhead measurement
- Statistical significance and regression detection
- Integration with existing test fixtures
"""

from contextlib import redirect_stdout
from io import StringIO
from typing import TYPE_CHECKING

import pytest

if TYPE_CHECKING:
    from click.testing import CliRunner, Result

from augint_library import print_hi
from augint_library.cli import cli


@pytest.mark.unit
def test_print_hi_performance(benchmark) -> None:
    """Benchmark the core print_hi function performance.

    This test establishes a baseline for the main library function and will
    detect performance regressions in future changes.

    Args:
        benchmark: pytest-benchmark fixture for performance measurement
    """
    name = "Alice"

    def run_print_hi() -> str:
        """Wrapper function to capture print_hi output."""
        output = StringIO()
        with redirect_stdout(output):
            print_hi(name)
        return output.getvalue()

    # Benchmark the function - pytest-benchmark runs multiple iterations
    result = benchmark(run_print_hi)

    # Verify correctness alongside performance
    assert result.strip() == f"Hi {name}"


@pytest.mark.unit
def test_print_hi_with_various_name_lengths(benchmark) -> None:
    """Benchmark print_hi with different name lengths to test scalability.

    Args:
        benchmark: pytest-benchmark fixture for performance measurement
    """
    # Test with a moderately long name to check if string length affects performance
    long_name = "Alice" * 20  # 100 characters

    def run_print_hi_long() -> str:
        """Wrapper for long name test."""
        output = StringIO()
        with redirect_stdout(output):
            print_hi(long_name)
        return output.getvalue()

    result = benchmark(run_print_hi_long)
    assert result.strip() == f"Hi {long_name}"


@pytest.mark.unit
def test_cli_invocation_performance(benchmark, cli_runner: "CliRunner") -> None:
    """Benchmark CLI command invocation overhead.

    This test measures the complete CLI stack performance including:
    - Click command parsing
    - Logging setup
    - Function execution
    - Output generation

    Args:
        benchmark: pytest-benchmark fixture for performance measurement
        cli_runner: pytest-click fixture for CLI testing
    """
    args = ["greet", "Alice"]

    def run_cli() -> "Result":
        """Wrapper function to run CLI command."""
        return cli_runner.invoke(cli, args)

    # Benchmark the CLI invocation
    result = benchmark(run_cli)

    # Verify correctness alongside performance
    assert result.exit_code == 0
    assert "Hi Alice" in result.output
    assert "Starting greeting command" in result.output
    assert "Greeting completed successfully" in result.output


@pytest.mark.unit
def test_cli_with_logging_options_performance(benchmark, cli_runner: "CliRunner") -> None:
    """Benchmark CLI performance with different logging configurations.

    Tests the performance impact of various logging options to ensure
    logging doesn't introduce significant overhead.

    Args:
        benchmark: pytest-benchmark fixture for performance measurement
        cli_runner: pytest-click fixture for CLI testing
    """
    args = ["greet", "Alice", "--json-logs", "--log-level", "DEBUG"]

    def run_cli_with_logging() -> "Result":
        """Wrapper function to run CLI with logging options."""
        return cli_runner.invoke(cli, args)

    result = benchmark(run_cli_with_logging)

    # Verify correctness
    assert result.exit_code == 0
    assert "Hi Alice" in result.output


@pytest.mark.unit
def test_multiple_cli_invocations_performance(benchmark, cli_runner: "CliRunner") -> None:
    """Benchmark multiple CLI invocations to test for memory leaks or slowdowns.

    Args:
        benchmark: pytest-benchmark fixture for performance measurement
        cli_runner: pytest-click fixture for CLI testing
    """

    def run_multiple_cli_calls() -> list["Result"]:
        """Run CLI command multiple times to test consistency."""
        results = []
        for name in ["Alice", "Bob", "Charlie"]:
            result = cli_runner.invoke(cli, ["greet", name])
            results.append(result)
        return results

    results = benchmark(run_multiple_cli_calls)

    # Verify all invocations succeeded
    for i, result in enumerate(results):
        assert result.exit_code == 0
        expected_names = ["Alice", "Bob", "Charlie"]
        assert f"Hi {expected_names[i]}" in result.output


@pytest.mark.unit
@pytest.mark.parametrize("name_length", [1, 10, 50, 100])
def test_print_hi_scalability_by_length(benchmark, name_length: int) -> None:
    """Benchmark print_hi performance across different input sizes.

    This parameterized test helps identify if the function has any scalability
    issues with longer string inputs.

    Args:
        benchmark: pytest-benchmark fixture for performance measurement
        name_length: Length of the test name string
    """
    name = "A" * name_length

    def run_print_hi_sized() -> str:
        """Wrapper function for sized name test."""
        output = StringIO()
        with redirect_stdout(output):
            print_hi(name)
        return output.getvalue()

    result = benchmark(run_print_hi_sized)
    assert result.strip() == f"Hi {name}"
