"""Integration-test fixtures.

Loads connection settings from a ``.env`` file (or the real environment)
and skips the entire integration suite when the device is unreachable or
credentials are not configured.

Required environment variables
-------------------------------
ROUTEROS_HOST       IP / hostname of the RouterOS device  (default: 127.0.0.1)
ROUTEROS_PORT       Plain API port                         (default: 8728)
ROUTEROS_USER       Username                               (default: admin)
ROUTEROS_PASSWORD   Password                               (default: "")

Optional
--------
ROUTEROS_TLS_PORT   TLS API port                           (default: 8729)
ROUTEROS_TLS_VERIFY "true" | "false"  verify server cert  (default: false)
"""

from __future__ import annotations

import os
import socket
import ssl

import pytest

# Load .env from the project root (two levels up from this file).
try:
    from dotenv import load_dotenv

    _env_file = os.path.join(os.path.dirname(__file__), "..", "..", ".env")
    load_dotenv(_env_file)
except ImportError:
    pass  # python-dotenv not installed – rely on real env vars


# ---------------------------------------------------------------------------
# Settings helpers
# ---------------------------------------------------------------------------


def _get(key: str, default: str = "") -> str:
    return os.environ.get(key, default).strip()


def _address() -> str:
    host = _get("ROUTEROS_HOST", "127.0.0.1")
    port = _get("ROUTEROS_PORT", "8728")
    return f"{host}:{port}"


def _tls_address() -> str:
    host = _get("ROUTEROS_HOST", "127.0.0.1")
    port = _get("ROUTEROS_TLS_PORT", "8729")
    return f"{host}:{port}"


def _credentials() -> tuple[str, str]:
    return _get("ROUTEROS_USER", "admin"), _get("ROUTEROS_PASSWORD", "")


def _device_reachable(host: str, port: int, timeout: float = 3.0) -> bool:
    try:
        with socket.create_connection((host, port), timeout=timeout):
            return True
    except OSError:
        return False


# ---------------------------------------------------------------------------
# Session-scoped skip decision
# ---------------------------------------------------------------------------


def pytest_configure(config):
    config.addinivalue_line(
        "markers",
        "integration: tests that require a live RouterOS device or Docker container",
    )


@pytest.fixture(scope="session", autouse=True)
def require_device() -> None:
    """Skip the whole integration suite when the device is not reachable."""
    host = _get("ROUTEROS_HOST", "127.0.0.1")
    port = int(_get("ROUTEROS_PORT", "8728"))

    if not _device_reachable(host, port):
        pytest.skip(
            f"RouterOS device not reachable at {host}:{port}. "
            "Set ROUTEROS_HOST / ROUTEROS_PORT or start the Docker container.",
            allow_module_level=True,
        )


# ---------------------------------------------------------------------------
# Per-test fixtures
# ---------------------------------------------------------------------------


@pytest.fixture()
def ros_address() -> str:
    return _address()


@pytest.fixture()
def ros_tls_address() -> str:
    return _tls_address()


@pytest.fixture()
def ros_credentials() -> tuple[str, str]:
    return _credentials()


@pytest.fixture()
def client(ros_address, ros_credentials):
    """Yield an authenticated, synchronous :class:`~routeros.client.Client`."""
    import routeros

    username, password = ros_credentials
    with routeros.dial(ros_address, username, password, timeout=10.0) as c:
        yield c


@pytest.fixture()
def async_client(ros_address, ros_credentials):
    """Yield an authenticated :class:`~routeros.client.Client` in async mode."""
    import routeros

    username, password = ros_credentials
    with routeros.dial(ros_address, username, password, timeout=10.0) as c:
        c.async_start()
        yield c


@pytest.fixture()
def tls_ssl_context() -> ssl.SSLContext:
    """Return an SSLContext compatible with RouterOS self-signed certificates.

    RouterOS uses older TLS cipher suites and self-signed certificates.
    This context:
    * Disables certificate verification (unless ROUTEROS_TLS_VERIFY=true).
    * Allows legacy cipher suites used by RouterOS (TLSv1.2 + RSA ciphers).
    """
    verify = _get("ROUTEROS_TLS_VERIFY", "false").lower() in ("true", "1", "yes")

    # Use PROTOCOL_TLS_CLIENT so SNI and hostname are configured correctly,
    # then relax the security level so RouterOS's older ciphers are accepted.
    ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
    ctx.check_hostname = False
    ctx.verify_mode = ssl.CERT_NONE if not verify else ssl.CERT_REQUIRED

    # Allow TLSv1.2+ (RouterOS typically uses TLSv1.2 with RSA key exchange).
    try:
        ctx.minimum_version = ssl.TLSVersion.TLSv1_2
    except AttributeError:
        pass  # older Python – keep default

    # Enable broader cipher set so RSA-based suites used by RouterOS are accepted.
    try:
        ctx.set_ciphers("DEFAULT:@SECLEVEL=1")
    except ssl.SSLError:
        pass  # some builds don't support SECLEVEL – keep defaults

    return ctx
