import functools
import sys
from contextlib import contextmanager

import pytest

_orig_trace = None


def pytest_configure():
    global _orig_trace
    _orig_trace = sys.gettrace()


@pytest.fixture(scope="session", autouse=True)
def term():
    """Configure TERM for predictable output from Pygments."""
    from _pytest.monkeypatch import MonkeyPatch

    m = MonkeyPatch()
    m.setenv("TERM", "xterm-256color")
    yield m
    m.undo()


# if _orig_trace and not hasattr(sys, "pypy_version_info"):
# Fails with PyPy2 (https://travis-ci.org/antocuni/pdb/jobs/509624590)?!
@pytest.fixture(autouse=True)
def restore_settrace(monkeypatch):
    """(Re)store sys.gettrace after test run.

    This is required to re-enable coverage tracking.
    """
    assert sys.gettrace() is _orig_trace

    orig_settrace = sys.settrace

    # Wrap sys.settrace to restore original tracing function (coverage)
    # with `sys.settrace(None)`.
    def settrace(func):
        if func is None:
            orig_settrace(_orig_trace)
        else:
            orig_settrace(func)
    monkeypatch.setattr("sys.settrace", settrace)

    yield

    newtrace = sys.gettrace()
    if newtrace is not _orig_trace:
        sys.settrace(_orig_trace)
        assert newtrace is None


@pytest.fixture(scope="session")
def _tmphome_path(tmpdir_factory):
    return tmpdir_factory.mktemp("tmphome")


@pytest.fixture(autouse=sys.version_info < (3, 6))
def tmphome(request, monkeypatch):
    """Set up HOME in a temporary directory.

    This ignores any real ~/.pdbrc.py then, and seems to be
    required also with linecache on py27, where it would read contents from
    ~/.pdbrc?!.
    """
    # Use tmpdir from testdir, if it is used.
    if "testdir" in request.fixturenames:
        tmpdir = request.getfixturevalue("testdir").tmpdir
    else:
        tmpdir = request.getfixturevalue("_tmphome_path")

    monkeypatch.setenv("HOME", str(tmpdir))
    monkeypatch.setenv("USERPROFILE", str(tmpdir))

    with tmpdir.as_cwd():
        yield tmpdir


@pytest.fixture(params=("pyrepl", "readline"), scope="session")
def readline_param(request):
    from _pytest.monkeypatch import MonkeyPatch

    m = MonkeyPatch()

    if request.param == "pyrepl":
        try:
            import pyrepl.readline  # noqa: F401
        except ImportError as exc:
            pytest.skip(msg="pyrepl not available: {}".format(exc))
        m.setattr("fancycompleter.DefaultConfig.prefer_pyrepl", True)
    else:
        m.setattr("fancycompleter.DefaultConfig.prefer_pyrepl", False)
    return request.param


@pytest.fixture
def monkeypatch_readline(request, monkeypatch, readline_param):
    """Patch readline to return given results."""
    def inner(line, begidx, endidx):
        if readline_param == "pyrepl":
            readline = "pyrepl.readline"
        else:
            assert readline_param == "readline"
            readline = "readline"

        monkeypatch.setattr("%s.get_line_buffer" % readline, lambda: line)
        monkeypatch.setattr("%s.get_begidx" % readline, lambda: begidx)
        monkeypatch.setattr("%s.get_endidx" % readline, lambda: endidx)

    return inner


@pytest.fixture
def monkeypatch_pdb_methods(monkeypatch):
    def mock(method, *args, **kwargs):
        print("=== %s(%s, %s)" % (method, args, kwargs))

    for mock_method in ("set_trace", "set_continue"):
        monkeypatch.setattr(
            "pdb.pdb.Pdb.%s" % mock_method, functools.partial(mock, mock_method)
        )


@pytest.fixture
def monkeypatch_importerror(monkeypatch):
    @contextmanager
    def cm(mocked_imports):
        orig_import = __import__

        def import_mock(name, *args):
            if name in mocked_imports:
                raise ImportError
            return orig_import(name, *args)

        with monkeypatch.context() as m:
            if sys.version_info >= (3,):
                m.setattr('builtins.__import__', import_mock)
            else:
                m.setattr('__builtin__.__import__', import_mock)
            yield m
    return cm

[(15, 'pytest.fixture', 'pytest.fixture', ([], {'scope': '"""session"""', 'autouse': '(True)'}), False, 'import pytest\n'), (28, 'pytest.fixture', 'pytest.fixture', ([], {'autouse': '(True)'}), False, 'import pytest\n'), (55, 'pytest.fixture', 'pytest.fixture', ([], {'scope': '"""session"""'}), False, 'import pytest\n'), (60, 'pytest.fixture', 'pytest.fixture', ([], {'autouse': '(sys.version_info < (3, 6))'}), False, 'import pytest\n'), (81, 'pytest.fixture', 'pytest.fixture', ([], {'params': "('pyrepl', 'readline')", 'scope': '"""session"""'}), False, 'import pytest\n'), (12, 'sys.gettrace', 'sys.gettrace', ([], {}), False, 'import sys\n'), (20, '_pytest.monkeypatch.MonkeyPatch', 'MonkeyPatch', ([], {}), False, 'from _pytest.monkeypatch import MonkeyPatch\n'), (49, 'sys.gettrace', 'sys.gettrace', ([], {}), False, 'import sys\n'), (85, '_pytest.monkeypatch.MonkeyPatch', 'MonkeyPatch', ([], {}), False, 'from _pytest.monkeypatch import MonkeyPatch\n'), (34, 'sys.gettrace', 'sys.gettrace', ([], {}), False, 'import sys\n'), (51, 'sys.settrace', 'sys.settrace', (['_orig_trace'], {}), False, 'import sys\n'), (122, 'functools.partial', 'functools.partial', (['mock', 'mock_method'], {}), False, 'import functools\n')]