"""
Tests for benchmarks/cli (benchmark_commands.py)

Tests cover:
- setup_benchmark_parser - argument parsing for benchmark commands
- run_simpleqa_cli - SimpleQA benchmark execution
- run_browsecomp_cli - BrowseComp benchmark execution
- list_benchmarks_cli - listing benchmarks
- main function behavior
"""

import argparse
import sys
from unittest.mock import patch, MagicMock
import pytest


@pytest.fixture
def mock_data_directory(tmp_path):
    """Mock the data directory to use a temporary path."""
    with patch(
        "local_deep_research.benchmarks.cli.benchmark_commands.get_data_directory"
    ) as mock:
        mock.return_value = tmp_path
        yield tmp_path


class TestSetupBenchmarkParser:
    """Tests for setup_benchmark_parser function."""

    def test_simpleqa_command_exists(self, mock_data_directory):
        """Test that simpleqa command is added to parser."""
        from local_deep_research.benchmarks.cli.benchmark_commands import (
            setup_benchmark_parser,
        )

        parser = argparse.ArgumentParser()
        subparsers = parser.add_subparsers(dest="command")

        setup_benchmark_parser(subparsers)

        args = parser.parse_args(["simpleqa"])
        assert args.command == "simpleqa"

    def test_browsecomp_command_exists(self, mock_data_directory):
        """Test that browsecomp command is added to parser."""
        from local_deep_research.benchmarks.cli.benchmark_commands import (
            setup_benchmark_parser,
        )

        parser = argparse.ArgumentParser()
        subparsers = parser.add_subparsers(dest="command")

        setup_benchmark_parser(subparsers)

        args = parser.parse_args(["browsecomp"])
        assert args.command == "browsecomp"

    def test_list_command_exists(self, mock_data_directory):
        """Test that list command is added to parser."""
        from local_deep_research.benchmarks.cli.benchmark_commands import (
            setup_benchmark_parser,
        )

        parser = argparse.ArgumentParser()
        subparsers = parser.add_subparsers(dest="command")

        setup_benchmark_parser(subparsers)

        args = parser.parse_args(["list"])
        assert args.command == "list"

    def test_compare_command_exists(self, mock_data_directory):
        """Test that compare command is added to parser."""
        from local_deep_research.benchmarks.cli.benchmark_commands import (
            setup_benchmark_parser,
        )

        parser = argparse.ArgumentParser()
        subparsers = parser.add_subparsers(dest="command")

        setup_benchmark_parser(subparsers)

        args = parser.parse_args(["compare"])
        assert args.command == "compare"

    def test_simpleqa_default_examples(self, mock_data_directory):
        """Test that simpleqa has default examples of 100."""
        from local_deep_research.benchmarks.cli.benchmark_commands import (
            setup_benchmark_parser,
        )

        parser = argparse.ArgumentParser()
        subparsers = parser.add_subparsers(dest="command")

        setup_benchmark_parser(subparsers)

        args = parser.parse_args(["simpleqa"])
        assert args.examples == 100

    def test_simpleqa_custom_examples(self, mock_data_directory):
        """Test that simpleqa accepts custom examples."""
        from local_deep_research.benchmarks.cli.benchmark_commands import (
            setup_benchmark_parser,
        )

        parser = argparse.ArgumentParser()
        subparsers = parser.add_subparsers(dest="command")

        setup_benchmark_parser(subparsers)

        args = parser.parse_args(["simpleqa", "--examples", "50"])
        assert args.examples == 50

    def test_simpleqa_default_iterations(self, mock_data_directory):
        """Test that simpleqa has default iterations of 3."""
        from local_deep_research.benchmarks.cli.benchmark_commands import (
            setup_benchmark_parser,
        )

        parser = argparse.ArgumentParser()
        subparsers = parser.add_subparsers(dest="command")

        setup_benchmark_parser(subparsers)

        args = parser.parse_args(["simpleqa"])
        assert args.iterations == 3

    def test_simpleqa_custom_iterations(self, mock_data_directory):
        """Test that simpleqa accepts custom iterations."""
        from local_deep_research.benchmarks.cli.benchmark_commands import (
            setup_benchmark_parser,
        )

        parser = argparse.ArgumentParser()
        subparsers = parser.add_subparsers(dest="command")

        setup_benchmark_parser(subparsers)

        args = parser.parse_args(["simpleqa", "--iterations", "5"])
        assert args.iterations == 5

    def test_simpleqa_default_questions(self, mock_data_directory):
        """Test that simpleqa has default questions of 3."""
        from local_deep_research.benchmarks.cli.benchmark_commands import (
            setup_benchmark_parser,
        )

        parser = argparse.ArgumentParser()
        subparsers = parser.add_subparsers(dest="command")

        setup_benchmark_parser(subparsers)

        args = parser.parse_args(["simpleqa"])
        assert args.questions == 3

    def test_simpleqa_default_search_tool(self, mock_data_directory):
        """Test that simpleqa has default search_tool of searxng."""
        from local_deep_research.benchmarks.cli.benchmark_commands import (
            setup_benchmark_parser,
        )

        parser = argparse.ArgumentParser()
        subparsers = parser.add_subparsers(dest="command")

        setup_benchmark_parser(subparsers)

        args = parser.parse_args(["simpleqa"])
        assert args.search_tool == "searxng"

    def test_simpleqa_custom_search_tool(self, mock_data_directory):
        """Test that simpleqa accepts custom search_tool."""
        from local_deep_research.benchmarks.cli.benchmark_commands import (
            setup_benchmark_parser,
        )

        parser = argparse.ArgumentParser()
        subparsers = parser.add_subparsers(dest="command")

        setup_benchmark_parser(subparsers)

        args = parser.parse_args(["simpleqa", "--search-tool", "duckduckgo"])
        assert args.search_tool == "duckduckgo"

    def test_simpleqa_human_eval_flag(self, mock_data_directory):
        """Test that simpleqa accepts human-eval flag."""
        from local_deep_research.benchmarks.cli.benchmark_commands import (
            setup_benchmark_parser,
        )

        parser = argparse.ArgumentParser()
        subparsers = parser.add_subparsers(dest="command")

        setup_benchmark_parser(subparsers)

        args = parser.parse_args(["simpleqa", "--human-eval"])
        assert args.human_eval is True

    def test_simpleqa_no_eval_flag(self, mock_data_directory):
        """Test that simpleqa accepts no-eval flag."""
        from local_deep_research.benchmarks.cli.benchmark_commands import (
            setup_benchmark_parser,
        )

        parser = argparse.ArgumentParser()
        subparsers = parser.add_subparsers(dest="command")

        setup_benchmark_parser(subparsers)

        args = parser.parse_args(["simpleqa", "--no-eval"])
        assert args.no_eval is True

    def test_simpleqa_custom_output_dir(self, mock_data_directory):
        """Test that simpleqa accepts custom output-dir."""
        from local_deep_research.benchmarks.cli.benchmark_commands import (
            setup_benchmark_parser,
        )

        parser = argparse.ArgumentParser()
        subparsers = parser.add_subparsers(dest="command")

        setup_benchmark_parser(subparsers)

        args = parser.parse_args(["simpleqa", "--output-dir", "/custom/path"])
        assert args.output_dir == "/custom/path"

    def test_simpleqa_search_model_option(self, mock_data_directory):
        """Test that simpleqa accepts search-model option."""
        from local_deep_research.benchmarks.cli.benchmark_commands import (
            setup_benchmark_parser,
        )

        parser = argparse.ArgumentParser()
        subparsers = parser.add_subparsers(dest="command")

        setup_benchmark_parser(subparsers)

        args = parser.parse_args(["simpleqa", "--search-model", "gpt-4"])
        assert args.search_model == "gpt-4"

    def test_simpleqa_search_provider_option(self, mock_data_directory):
        """Test that simpleqa accepts search-provider option."""
        from local_deep_research.benchmarks.cli.benchmark_commands import (
            setup_benchmark_parser,
        )

        parser = argparse.ArgumentParser()
        subparsers = parser.add_subparsers(dest="command")

        setup_benchmark_parser(subparsers)

        args = parser.parse_args(["simpleqa", "--search-provider", "openai"])
        assert args.search_provider == "openai"

    def test_simpleqa_search_strategy_option(self, mock_data_directory):
        """Test that simpleqa accepts search-strategy option."""
        from local_deep_research.benchmarks.cli.benchmark_commands import (
            setup_benchmark_parser,
        )

        parser = argparse.ArgumentParser()
        subparsers = parser.add_subparsers(dest="command")

        setup_benchmark_parser(subparsers)

        args = parser.parse_args(["simpleqa", "--search-strategy", "parallel"])
        assert args.search_strategy == "parallel"

    def test_simpleqa_default_search_strategy(self, mock_data_directory):
        """Test that simpleqa has default search-strategy of source_based."""
        from local_deep_research.benchmarks.cli.benchmark_commands import (
            setup_benchmark_parser,
        )

        parser = argparse.ArgumentParser()
        subparsers = parser.add_subparsers(dest="command")

        setup_benchmark_parser(subparsers)

        args = parser.parse_args(["simpleqa"])
        assert args.search_strategy == "source_based"

    def test_compare_default_dataset(self, mock_data_directory):
        """Test that compare has default dataset of simpleqa."""
        from local_deep_research.benchmarks.cli.benchmark_commands import (
            setup_benchmark_parser,
        )

        parser = argparse.ArgumentParser()
        subparsers = parser.add_subparsers(dest="command")

        setup_benchmark_parser(subparsers)

        args = parser.parse_args(["compare"])
        assert args.dataset == "simpleqa"

    def test_compare_custom_dataset(self, mock_data_directory):
        """Test that compare accepts custom dataset."""
        from local_deep_research.benchmarks.cli.benchmark_commands import (
            setup_benchmark_parser,
        )

        parser = argparse.ArgumentParser()
        subparsers = parser.add_subparsers(dest="command")

        setup_benchmark_parser(subparsers)

        args = parser.parse_args(["compare", "--dataset", "browsecomp"])
        assert args.dataset == "browsecomp"

    def test_compare_default_examples(self, mock_data_directory):
        """Test that compare has default examples of 20."""
        from local_deep_research.benchmarks.cli.benchmark_commands import (
            setup_benchmark_parser,
        )

        parser = argparse.ArgumentParser()
        subparsers = parser.add_subparsers(dest="command")

        setup_benchmark_parser(subparsers)

        args = parser.parse_args(["compare"])
        assert args.examples == 20


class TestRunSimpleqaCli:
    """Tests for run_simpleqa_cli function."""

    def test_run_simpleqa_calls_benchmark(self, mock_data_directory):
        """Test that run_simpleqa_cli calls run_simpleqa_benchmark."""
        from local_deep_research.benchmarks.cli.benchmark_commands import (
            run_simpleqa_cli,
        )

        args = MagicMock()
        args.examples = 10
        args.iterations = 2
        args.questions = 2
        args.search_tool = "searxng"
        args.output_dir = "/tmp/output"
        args.human_eval = False
        args.no_eval = False
        args.custom_dataset = None
        args.eval_model = None
        args.eval_provider = None
        args.search_model = None
        args.search_provider = None
        args.endpoint_url = None
        args.search_strategy = "source_based"

        with patch(
            "local_deep_research.benchmarks.cli.benchmark_commands.run_simpleqa_benchmark"
        ) as mock_benchmark:
            mock_benchmark.return_value = {
                "metrics": {
                    "accuracy": 0.8,
                    "correct": 8,
                    "average_processing_time": 5.0,
                },
                "total_examples": 10,
                "report_path": "/tmp/report.html",
            }

            run_simpleqa_cli(args)

            mock_benchmark.assert_called_once()

    def test_run_simpleqa_passes_search_config(self, mock_data_directory):
        """Test that run_simpleqa_cli passes search config correctly."""
        from local_deep_research.benchmarks.cli.benchmark_commands import (
            run_simpleqa_cli,
        )

        args = MagicMock()
        args.examples = 10
        args.iterations = 5
        args.questions = 4
        args.search_tool = "duckduckgo"
        args.output_dir = "/tmp/output"
        args.human_eval = False
        args.no_eval = False
        args.custom_dataset = None
        args.eval_model = None
        args.eval_provider = None
        args.search_model = "gpt-4"
        args.search_provider = "openai"
        args.endpoint_url = None
        args.search_strategy = "parallel"

        with patch(
            "local_deep_research.benchmarks.cli.benchmark_commands.run_simpleqa_benchmark"
        ) as mock_benchmark:
            mock_benchmark.return_value = {"metrics": {}, "total_examples": 10}

            run_simpleqa_cli(args)

            call_kwargs = mock_benchmark.call_args[1]
            assert call_kwargs["search_config"]["iterations"] == 5
            assert call_kwargs["search_config"]["questions_per_iteration"] == 4
            assert call_kwargs["search_config"]["search_tool"] == "duckduckgo"
            assert call_kwargs["search_config"]["model_name"] == "gpt-4"
            assert call_kwargs["search_config"]["provider"] == "openai"


class TestRunBrowsecompCli:
    """Tests for run_browsecomp_cli function."""

    def test_run_browsecomp_calls_benchmark(self, mock_data_directory):
        """Test that run_browsecomp_cli calls run_browsecomp_benchmark."""
        from local_deep_research.benchmarks.cli.benchmark_commands import (
            run_browsecomp_cli,
        )

        args = MagicMock()
        args.examples = 10
        args.iterations = 2
        args.questions = 2
        args.search_tool = "searxng"
        args.output_dir = "/tmp/output"
        args.human_eval = False
        args.no_eval = False
        args.custom_dataset = None
        args.eval_model = None
        args.eval_provider = None
        args.search_model = None
        args.search_provider = None
        args.endpoint_url = None
        args.search_strategy = "source_based"

        with patch(
            "local_deep_research.benchmarks.cli.benchmark_commands.run_browsecomp_benchmark"
        ) as mock_benchmark:
            mock_benchmark.return_value = {
                "metrics": {
                    "accuracy": 0.7,
                    "correct": 7,
                    "average_processing_time": 6.0,
                },
                "total_examples": 10,
                "report_path": "/tmp/report.html",
            }

            run_browsecomp_cli(args)

            mock_benchmark.assert_called_once()


class TestListBenchmarksCli:
    """Tests for list_benchmarks_cli function."""

    def test_list_benchmarks_calls_get_available_datasets(
        self, mock_data_directory, capsys
    ):
        """Test that list_benchmarks_cli calls get_available_datasets."""
        from local_deep_research.benchmarks.cli.benchmark_commands import (
            list_benchmarks_cli,
        )

        args = MagicMock()

        with patch(
            "local_deep_research.benchmarks.cli.benchmark_commands.get_available_datasets"
        ) as mock_datasets:
            mock_datasets.return_value = [
                {
                    "id": "simpleqa",
                    "name": "SimpleQA",
                    "description": "Simple QA benchmark",
                    "url": "http://example.com",
                }
            ]

            list_benchmarks_cli(args)

            mock_datasets.assert_called_once()

    def test_list_benchmarks_prints_datasets(self, mock_data_directory, capsys):
        """Test that list_benchmarks_cli prints dataset information."""
        from local_deep_research.benchmarks.cli.benchmark_commands import (
            list_benchmarks_cli,
        )

        args = MagicMock()

        with patch(
            "local_deep_research.benchmarks.cli.benchmark_commands.get_available_datasets"
        ) as mock_datasets:
            mock_datasets.return_value = [
                {
                    "id": "simpleqa",
                    "name": "SimpleQA",
                    "description": "Simple QA benchmark",
                    "url": "http://example.com",
                }
            ]

            list_benchmarks_cli(args)

            captured = capsys.readouterr()
            assert "simpleqa" in captured.out
            assert "SimpleQA" in captured.out


class TestMain:
    """Tests for main function."""

    def test_main_requires_command(self, mock_data_directory):
        """Test that main requires a command."""
        from local_deep_research.benchmarks.cli.benchmark_commands import main

        with patch.object(sys, "argv", ["ldr-benchmark"]):
            with pytest.raises(SystemExit):
                main()

    def test_main_with_list_command(self, mock_data_directory, capsys):
        """Test that main handles list command."""
        from local_deep_research.benchmarks.cli.benchmark_commands import main

        with patch.object(sys, "argv", ["ldr-benchmark", "list"]):
            with patch(
                "local_deep_research.benchmarks.cli.benchmark_commands.get_available_datasets"
            ) as mock_datasets:
                mock_datasets.return_value = [
                    {
                        "id": "test",
                        "name": "Test",
                        "description": "Test",
                        "url": "http://test.com",
                    }
                ]
                main()

                captured = capsys.readouterr()
                assert "Available Benchmarks" in captured.out

    def test_main_pins_diagnose_false_on_logger_add(self, mock_data_directory):
        """main() must pass diagnose=False to every logger.add (issue #4185).

        loguru defaults diagnose=True, which renders repr() of every
        traceback frame's locals on exception. Benchmarks invoke LLMs and
        search engines whose handlers hold api_key/Authorization headers as
        frame locals; leaving the default on would dump those to stderr on
        any failure. The benchmark CLI bypasses config_logger, so the fix
        lives at this entry point.
        """
        import local_deep_research.benchmarks.cli.benchmark_commands as module

        for verbose_flag in (["--verbose"], []):
            argv = ["ldr-benchmark"] + verbose_flag + ["list"]
            with patch.object(sys, "argv", argv):
                with patch(
                    "local_deep_research.benchmarks.cli.benchmark_commands.get_available_datasets",
                    return_value=[],
                ):
                    with patch.object(module, "logger") as mock_logger:
                        module.main()

                    assert mock_logger.add.call_args_list, (
                        f"no logger.add calls observed for argv={argv}"
                    )
                    for add_call in mock_logger.add.call_args_list:
                        assert add_call.kwargs.get("diagnose") is False, (
                            f"benchmark CLI logger.add must pass "
                            f"diagnose=False; got "
                            f"{add_call.kwargs.get('diagnose')!r} "
                            f"for argv={argv}"
                        )


class TestSearchConfigBuilding:
    """Tests for search config building logic."""

    def test_search_config_includes_basic_params(self, mock_data_directory):
        """Test that search config includes basic parameters."""
        from local_deep_research.benchmarks.cli.benchmark_commands import (
            run_simpleqa_cli,
        )

        args = MagicMock()
        args.examples = 10
        args.iterations = 3
        args.questions = 2
        args.search_tool = "searxng"
        args.output_dir = "/tmp/output"
        args.human_eval = False
        args.no_eval = False
        args.custom_dataset = None
        args.eval_model = None
        args.eval_provider = None
        args.search_model = None
        args.search_provider = None
        args.endpoint_url = None
        args.search_strategy = "standard"

        with patch(
            "local_deep_research.benchmarks.cli.benchmark_commands.run_simpleqa_benchmark"
        ) as mock_benchmark:
            mock_benchmark.return_value = {"metrics": {}, "total_examples": 10}

            run_simpleqa_cli(args)

            call_kwargs = mock_benchmark.call_args[1]
            assert "search_config" in call_kwargs
            assert call_kwargs["search_config"]["iterations"] == 3
            assert call_kwargs["search_config"]["questions_per_iteration"] == 2
            assert call_kwargs["search_config"]["search_tool"] == "searxng"

    def test_evaluation_config_set_when_eval_model_provided(
        self, mock_data_directory
    ):
        """Test that evaluation config is set when eval_model is provided."""
        from local_deep_research.benchmarks.cli.benchmark_commands import (
            run_simpleqa_cli,
        )

        args = MagicMock()
        args.examples = 10
        args.iterations = 3
        args.questions = 2
        args.search_tool = "searxng"
        args.output_dir = "/tmp/output"
        args.human_eval = False
        args.no_eval = False
        args.custom_dataset = None
        args.eval_model = "gpt-4"
        args.eval_provider = "openai"
        args.search_model = None
        args.search_provider = None
        args.endpoint_url = None
        args.search_strategy = "standard"

        with patch(
            "local_deep_research.benchmarks.cli.benchmark_commands.run_simpleqa_benchmark"
        ) as mock_benchmark:
            mock_benchmark.return_value = {"metrics": {}, "total_examples": 10}

            run_simpleqa_cli(args)

            call_kwargs = mock_benchmark.call_args[1]
            assert call_kwargs["evaluation_config"] is not None
            assert call_kwargs["evaluation_config"]["model_name"] == "gpt-4"
            assert call_kwargs["evaluation_config"]["provider"] == "openai"

    def test_evaluation_config_none_when_no_eval_args(
        self, mock_data_directory
    ):
        """Test that evaluation config is None when no eval args provided."""
        from local_deep_research.benchmarks.cli.benchmark_commands import (
            run_simpleqa_cli,
        )

        args = MagicMock()
        args.examples = 10
        args.iterations = 3
        args.questions = 2
        args.search_tool = "searxng"
        args.output_dir = "/tmp/output"
        args.human_eval = False
        args.no_eval = False
        args.custom_dataset = None
        args.eval_model = None
        args.eval_provider = None
        args.search_model = None
        args.search_provider = None
        args.endpoint_url = None
        args.search_strategy = "standard"

        with patch(
            "local_deep_research.benchmarks.cli.benchmark_commands.run_simpleqa_benchmark"
        ) as mock_benchmark:
            mock_benchmark.return_value = {"metrics": {}, "total_examples": 10}

            run_simpleqa_cli(args)

            call_kwargs = mock_benchmark.call_args[1]
            assert call_kwargs["evaluation_config"] is None
