# coverage run -m pytest -rA tests/test_subprocessor_error_detection.py --no-header --html=./reports/pytest/report.html --self-contained-html && coverage html #noqa E501

import os
import stat
import sys
import platform
import pytest

from pathlib import Path

import wox.python_discoverer as python_discoverer
import wox.subprocessor as subprocessor
import wox.venv_management as venv_manager

from wox.wox_exceptions import (
    DependencyConflictError,
    DiskFullError,
    PackageNotFoundError,
    PermissionDeniedError,
    PipTimeoutError,
    PythonInterpreterNotFoundError,
    PythonInterpreterUnstableError
)
from tests.conftest import maintainer_only
from tests.resources.constants import RAMDISK_PATH
from tests.resources.utils import run_with_timeout_process


@pytest.fixture
def package():
    return 'pandas'

@pytest.fixture
def python_interpreter():
    return python_discoverer.PythonInterpreter(
        python_discoverer.Version(platform.python_version()),
        Path(sys.executable)
    )

# python -B -m pytest -rA -k "test_pip_dependency_conflict_error"
def test_pip_dependency_conflict_error(tmp_path, python_interpreter):

    with pytest.raises(DependencyConflictError):
        subprocessor.run_command(
            f'{python_interpreter.path} -I -m pip install -qqq \
            --target {tmp_path} sphinx==8.2.3 furo==2021.10.9',
            python_interpreter = python_interpreter
        )

# python -B -m pytest -rA -k "test_uv_dependency_conflict_error"
def test_uv_dependency_conflict_error(tmp_path, python_interpreter):

    with pytest.raises(DependencyConflictError):
        subprocessor.run_command(
            f'uv pip install --python {python_interpreter.path} -qqq \
            --target {tmp_path} sphinx==8.2.3 furo==2021.10.9',
            python_interpreter = python_interpreter
        )

# python -B -m pytest -rA -k "test_uv_disk_full"
def test_uv_disk_full(tmpfs, python_interpreter):

    with pytest.raises(DiskFullError):
        subprocessor.run_command(
            f'uv pip install --python {python_interpreter.path} -qqq \
            --target {RAMDISK_PATH} pandas',
            python_interpreter = python_interpreter
        )

# python -B -m pytest -rA -k "test_pip_disk_full"
@pytest.mark.flaky(reruns = 1, reruns_delay = 1)
def test_pip_disk_full(tmpfs, python_interpreter):

    def pip_install(python_interpreter):
        subprocessor.run_command(
            f'{python_interpreter.path} -I -m pip install -qqq --target {RAMDISK_PATH} \
            pandas',
            python_interpreter = python_interpreter
        )

    with pytest.raises(DiskFullError):
        run_with_timeout_process(pip_install,
            timeout = 10,
            python_interpreter = python_interpreter
        )

# python -B -m pytest -rA -k "test_pip_package_not_found_error"
def test_pip_package_not_found_error(tmp_path, python_interpreter):

    with pytest.raises(PackageNotFoundError):
        subprocessor.run_command(
            f'{python_interpreter.path} -I -m pip install -qqq --target {tmp_path} pytes \
            cowsaa',
            python_interpreter = python_interpreter
        )

# python -B -m pytest -rA -k "test_uv_package_not_found_error"
def test_uv_package_not_found_error(tmp_path, python_interpreter):

    with pytest.raises(PackageNotFoundError):
        subprocessor.run_command(
            f'uv pip install --python {python_interpreter.path} -qqq \
            --target {tmp_path} pytes cowsaa',
            python_interpreter = python_interpreter
        )

# python -B -m pytest -rA -k "test_pip_permission_denied_error"
@maintainer_only
def test_pip_permission_denied_error(tmp_path, package, python_interpreter):
    print(os.environ.get('RUN_MAINTAINER_TESTS'))
    os.chmod(tmp_path, stat.S_IREAD)

    with pytest.raises(PermissionDeniedError):
        subprocessor.run_command(
            f'{python_interpreter.path} -I -m pip install -qqq --target {tmp_path} \
            {package}',
            python_interpreter = python_interpreter
        )

# python -B -m pytest -rA -k "test_uv_permission_denied_error"
@maintainer_only
def test_uv_permission_denied_error(tmp_path, package, python_interpreter):

    os.chmod(tmp_path, stat.S_IREAD)

    with pytest.raises(PermissionDeniedError):
        subprocessor.run_command(
            f'uv pip install --python {python_interpreter.path} -qqq --target {tmp_path} \
            {package}',
            python_interpreter = python_interpreter
        )

# python -B -m pytest -rA -k "test_pip_timeout_error"
@pytest.mark.parametrize(
    'url', [
        'http://127.0.0.1:9999/simple',
        'https://192.0.2.1/simple'
    ],
    ids = [
        'localhost',
        'reserved_ip'
    ]
)
def test_pip_timeout_error(tmp_path, package, python_interpreter, url):
    """
        Simulates a network failure when pip cannot reach its index server.
        Uses an IP address in the 192.0.2.0/24 range, reserved for
        documentation and testing purposes.
    """

    with pytest.raises(PipTimeoutError):
        subprocessor.run_command(
            f"{python_interpreter.path} -I -m pip install -qqq \
            --target {tmp_path} --cache-dir {tmp_path / 'pip_cache'} --index-url {url} \
            {package}",
            python_interpreter = python_interpreter
        )

# python -B -m pytest -rA -k "test_uv_timeout_error"
@pytest.mark.parametrize(
    'url', [
        'http://127.0.0.1:9999/simple',
        'https://192.0.2.1/simple'
    ],
    ids = [
        'localhost',
        'reserved_ip'
    ]
)
def test_uv_timeout_error(tmp_path, package, python_interpreter, url):
    """
        Simulates a network failure when pip cannot reach its index server.
        Uses an IP address in the 192.0.2.0/24 range, reserved for
        documentation and testing purposes.
    """

    with pytest.raises(PipTimeoutError):
        subprocessor.run_command(
            f"uv pip install --python {python_interpreter.path} -qqq \
            --target {tmp_path} --cache-dir {tmp_path / 'uv_cache'} --index {url} \
            {package}",
            python_interpreter = python_interpreter
        )

# python -B -m pytest -rA -k "test_pip_python_interpreter_unstable_error"
@maintainer_only
def test_pip_python_interpreter_unstable_error(tmp_path):

    if platform.system() != 'Linux':
        pytest.skip(
            'Requires Python broken interpreter built from source' \
            'following this guide : <url to doc>.'
        )

    env = 'py311'

    python_interpreter = python_discoverer.PythonInterpreter(
        python_discoverer.Version('3.11.3'),
        Path.home() / 'python311-broken' / 'bin' / 'python3.11'
    )

    env_path = tmp_path / env

    with pytest.raises(PythonInterpreterUnstableError):
        venv_manager.create_venv(env_path, python_interpreter)

# python -B -m pytest -rA -k "test_uv_python_interpreter_unstable_error"
@maintainer_only
def test_uv_python_interpreter_unstable_error(tmp_path):

    if platform.system() != 'Linux':
        pytest.skip('only works on Linux')

    if platform.system() != 'Linux':
        pytest.skip(
            'Requires Python broken interpreter built from source' \
            'following this guide : <url to doc>.'
        )

    env = 'py311'

    python_interpreter = python_discoverer.PythonInterpreter(
        python_discoverer.Version('3.11.3'),
        Path.home() / 'python311-broken' / 'bin' / 'python3.11'
    )

    env_path = tmp_path / env

    with pytest.raises(PythonInterpreterUnstableError):
        venv_manager.create_venv(env_path, python_interpreter, with_uv = True)

# python -B -m pytest -rA -k "test_python_interpretor_not_found_error"
def test_python_interpretor_not_found_error():

    with pytest.raises(PythonInterpreterNotFoundError):
        python_discoverer.python_discovery('py30')
