from pathlib import Path

import pytest
from grizzly.common.utils import Exit

from autobisect.evaluators import BrowserEvaluator, EvaluatorResult
from autobisect.evaluators.browser.browser import BrowserEvaluatorException


def test_verify_build_status(mocker):
    """
    Test that BrowserEvaluator.verify_build() returns the correct status
    """
    mocker.patch(
        "autobisect.BrowserEvaluator.launch",
        side_effect=(
            EvaluatorResult.BUILD_CRASHED,
            EvaluatorResult.BUILD_PASSED,
            EvaluatorResult.BUILD_FAILED,
        ),
    )
    browser = BrowserEvaluator(Path("testcase.html"))
    assert browser.verify_build(Path("firefox")) is False
    assert browser.verify_build(Path("firefox")) is True
    assert browser.verify_build(Path("firefox")) is False


def test_evaluate_testcase_simple(mocker, tmp_path):
    """
    Simple test of BrowserEvaluator.evaluate_testcase()
    """
    mocker.patch(
        "autobisect.BrowserEvaluator.launch",
        autospec=True,
        return_value=EvaluatorResult.BUILD_PASSED,
    )
    browser = BrowserEvaluator(Path("testcase.html"))
    (tmp_path / "firefox").touch()
    assert browser.evaluate_testcase(tmp_path) == EvaluatorResult.BUILD_PASSED


def test_evaluate_testcase_non_existent_binary(tmp_path):
    """
    Test that BrowserEvaluator.evaluate_testcase fails when using a non-existent build path
    """
    browser = BrowserEvaluator(Path("testcase.html"))
    assert browser.evaluate_testcase(tmp_path) == EvaluatorResult.BUILD_FAILED


def test_launch_simple(mocker, tmp_path):
    """Simple test of BrowserEvaluator.launch()"""
    mocker.patch(
        "grizzly.replay.ReplayManager.main",
        side_effect=(Exit.SUCCESS, Exit.FAILURE),
    )

    binary = tmp_path / "firefox"
    binary.touch()
    testcase = tmp_path / "testcase.html"
    testcase.touch()

    browser = BrowserEvaluator(testcase)
    assert browser.launch(binary, testcase) == EvaluatorResult.BUILD_CRASHED
    assert browser.launch(binary, testcase) == EvaluatorResult.BUILD_PASSED


def test_launch_non_existent_binary(tmp_path):
    """Simple test of BrowserEvaluator.launch()"""
    binary = tmp_path / "firefox"
    testcase = tmp_path / "testcase.html"
    testcase.touch()

    browser = BrowserEvaluator(testcase)

    with pytest.raises(BrowserEvaluatorException):
        browser.launch(binary, testcase)


@pytest.mark.parametrize("ignore", ("log-limit", "memory", "timeout"))
@pytest.mark.parametrize("valgrind", (True, False))
@pytest.mark.parametrize("xvfb", (True, False))
@pytest.mark.parametrize("harness", (True, False))
def test_grizzly_arg_parsing(
    mocker,
    tmp_path: Path,
    ignore: str,
    valgrind: bool,
    xvfb: bool,
    harness: bool,
):
    """Ensure that args are accepted by grizzly"""
    binary = tmp_path / "firefox"
    binary.touch()
    testcase = tmp_path / "testcase.html"
    testcase.touch()
    prefs = tmp_path / "prefs.js"
    prefs.touch()

    # 'rr needs /proc/sys/kernel/perf_event_paranoid <= 1, but it is 2'
    mocker.patch.object(Path, "read_text", return_value=1)

    evaluator = BrowserEvaluator(
        testcase,
        ignore=[ignore],
        launch_timeout=300,
        prefs=prefs,
        relaunch=1,
        use_harness=harness,
        use_valgrind=valgrind,
        use_xvfb=xvfb,
        logs=tmp_path,
        pernosco=True,
        repeat=10,
    )
    evaluator.parse_args(binary, tmp_path, verify=False)


def test_grizzly_arg_parsing_no_pernosco_on_verify(tmp_path: Path):
    """Ensure that args are accepted by grizzly"""
    binary = tmp_path / "firefox"
    binary.touch()
    testcase = tmp_path / "testcase.html"
    testcase.touch()
    kwargs = {
        "pernosco": True,
        "logs": "/foo/bar",
        "repeat": 100,
    }
    evaluator = BrowserEvaluator(testcase, **kwargs)
    args = evaluator.parse_args(binary, tmp_path, verify=True)

    for k, v in kwargs.items():
        assert args.__dict__[k] != kwargs[k]
