"""Integration tests – connection and authentication."""

from __future__ import annotations

import pytest

pytestmark = pytest.mark.integration


class TestDial:
    def test_dial_connects_and_authenticates(self, ros_address, ros_credentials):
        """Basic dial() must succeed and return a usable client."""
        import routeros

        username, password = ros_credentials
        with routeros.dial(ros_address, username, password, timeout=10.0) as c:
            # Client is authenticated – run a no-op command.
            reply = c.run("/system/identity/print")
            assert reply.done is not None
            assert len(reply.re) == 1
            assert "name" in reply.re[0].map

    def test_invalid_password_raises(self, ros_address, ros_credentials):
        import routeros
        from routeros import RouterOSError

        username, _ = ros_credentials
        with pytest.raises(RouterOSError):
            routeros.dial(ros_address, username, "WRONG_PASSWORD_XYZ", timeout=5.0)

    def test_context_manager_closes_connection(self, ros_address, ros_credentials):
        import routeros

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

    def test_dial_with_timeout(self, ros_address, ros_credentials):
        import routeros

        username, password = ros_credentials
        # A generous timeout should always succeed.
        with routeros.dial(ros_address, username, password, timeout=30.0) as c:
            reply = c.run("/system/identity/print")
            assert reply.done is not None


class TestDialTLS:
    def test_dial_tls_connects(self, ros_tls_address, ros_credentials):
        """TLS connection must succeed when SSL is enabled on the device.

        RouterOS older versions (< 7.x) may only support TLSv1.0/1.1 which
        Python 3.10+ restricts and Python 3.14 removes entirely.  When the
        handshake fails we skip with a diagnostic rather than fail – the
        library code is correct, the constraint is on the Python/OpenSSL side.
        """
        import socket
        import ssl

        import routeros

        host, port_str = ros_tls_address.rsplit(":", 1)
        port = int(port_str)

        # If TLS port is not open, skip rather than fail.
        try:
            with socket.create_connection((host, port), timeout=3.0):
                pass
        except OSError:
            pytest.skip(
                f"TLS port {ros_tls_address} is not reachable – enable API-SSL on the device"
            )

        # Try progressively more permissive contexts to accommodate older
        # RouterOS firmware (TLSv1.0/1.1 + legacy RSA cipher suites).
        contexts = []

        # Context A: SECLEVEL=1 (allows RSA key exchange, TLSv1.2)
        try:
            ctx_a = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
            ctx_a.check_hostname = False
            ctx_a.verify_mode = ssl.CERT_NONE
            ctx_a.set_ciphers("DEFAULT:@SECLEVEL=1")
            contexts.append(("SECLEVEL=1", ctx_a))
        except ssl.SSLError:
            pass

        # Context B: SECLEVEL=0 (legacy, allows very old ciphers and TLSv1.0)
        try:
            ctx_b = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
            ctx_b.check_hostname = False
            ctx_b.verify_mode = ssl.CERT_NONE
            ctx_b.set_ciphers("ALL:@SECLEVEL=0")
            contexts.append(("SECLEVEL=0", ctx_b))
        except ssl.SSLError:
            pass

        username, password = ros_credentials
        last_err = None
        for label, ctx in contexts:
            try:
                with routeros.dial_tls(
                    ros_tls_address,
                    username,
                    password,
                    tls_context=ctx,
                    timeout=10.0,
                ) as c:
                    reply = c.run("/system/identity/print")
                    assert reply.done is not None
                    return  # success
            except ssl.SSLError as exc:
                last_err = exc

        # All contexts exhausted – RouterOS TLS version is incompatible with
        # this Python/OpenSSL build (e.g. device uses TLSv1.0 only).
        pytest.skip(
            f"TLS handshake failed with all tried cipher contexts "
            f"({last_err}). "
            "The RouterOS firmware likely requires TLSv1.0/1.1 which this "
            "Python/OpenSSL version no longer supports. "
            "Upgrade RouterOS or downgrade Python's SSL library to resolve."
        )
