"""Tests for the MLDClient main class."""

from pathlib import Path

import httpx
import pytest

from mld_sdk.client._exceptions import MLDAPIError
from mld_sdk.client.client import MLDClient
from mld_sdk.client.resources.auth import AuthAPI
from mld_sdk.client.resources.experiments import ExperimentsAPI
from mld_sdk.client.resources.plugins import PluginsAPI
from mld_sdk.client.resources.projects import ProjectsAPI


@pytest.fixture(autouse=True)
def _isolated_config(tmp_path: Path, monkeypatch: pytest.MonkeyPatch):
    monkeypatch.setenv("XDG_CONFIG_HOME", str(tmp_path))
    monkeypatch.delenv("MLD_URL", raising=False)
    monkeypatch.delenv("MLD_TOKEN", raising=False)


class TestMLDClientInit:
    def test_explicit_base_url(self):
        client = MLDClient(base_url="http://localhost:8001")
        assert client._base_url == "http://localhost:8001"
        client.close()

    def test_base_url_from_env(self, monkeypatch: pytest.MonkeyPatch):
        monkeypatch.setenv("MLD_URL", "http://env-host:8001")
        client = MLDClient()
        assert client._base_url == "http://env-host:8001"
        client.close()

    def test_token_from_env(self, monkeypatch: pytest.MonkeyPatch):
        monkeypatch.setenv("MLD_TOKEN", "env-token")
        client = MLDClient(base_url="http://localhost:8001")
        assert client._http._token == "env-token"
        client.close()

    def test_no_host_raises(self):
        with pytest.raises(MLDAPIError, match="No MLD host configured"):
            MLDClient()

    def test_token_from_config(self):
        from mld_sdk.client._config import store_token

        store_token("http://localhost:8001", "stored-tok", "admin")
        client = MLDClient(base_url="http://localhost:8001")
        assert client._http._token == "stored-tok"
        client.close()

    def test_base_url_from_config(self):
        from mld_sdk.client._config import store_token

        store_token("http://saved-host:8001", "tok", "admin")
        client = MLDClient()
        assert client._base_url == "http://saved-host:8001"
        client.close()


class TestMLDClientResourceNamespaces:
    def test_auth_property_returns_auth_api(self):
        client = MLDClient(base_url="http://localhost:8001")
        assert isinstance(client.auth, AuthAPI)
        client.close()

    def test_experiments_property(self):
        client = MLDClient(base_url="http://localhost:8001")
        assert isinstance(client.experiments, ExperimentsAPI)
        client.close()

    def test_projects_property(self):
        client = MLDClient(base_url="http://localhost:8001")
        assert isinstance(client.projects, ProjectsAPI)
        client.close()

    def test_plugins_property(self):
        client = MLDClient(base_url="http://localhost:8001")
        assert isinstance(client.plugins, PluginsAPI)
        client.close()

    def test_cached_property_returns_same_instance(self):
        client = MLDClient(base_url="http://localhost:8001")
        assert client.experiments is client.experiments
        assert client.auth is client.auth
        client.close()


class TestMLDClientContextManager:
    def test_context_manager(self):
        with MLDClient(base_url="http://localhost:8001") as client:
            assert client._base_url == "http://localhost:8001"

    def test_repr(self):
        client = MLDClient(base_url="http://localhost:8001")
        assert "localhost:8001" in repr(client)
        client.close()


class TestMLDClientConvenienceMethods:
    def test_login_delegates_to_auth(self):
        def handler(request: httpx.Request) -> httpx.Response:
            return httpx.Response(
                200,
                json={
                    "access_token": "tok",
                    "expires_in": 3600,
                    "user": {"id": "1", "username": "admin", "role": "admin"},
                },
            )

        client = MLDClient(base_url="http://localhost:8001")
        client._http._client = httpx.Client(
            base_url="http://localhost:8001",
            transport=httpx.MockTransport(handler),
        )
        result = client.login("admin", "pass")
        assert result["access_token"] == "tok"
        client.close()


class TestMLDClientInitLogin:
    def test_login_at_init_with_username_password(self):
        """MLDClient(username=..., password=...) should auto-login."""
        requests_made: list[httpx.Request] = []

        def handler(request: httpx.Request) -> httpx.Response:
            requests_made.append(request)
            return httpx.Response(
                200,
                json={
                    "access_token": "init-tok",
                    "expires_in": 3600,
                    "user": {"id": "1", "username": "admin", "role": "admin"},
                },
            )

        # Patch the transport before __init__ calls login
        import mld_sdk.client._http as http_mod

        orig_init = http_mod.HTTPClient.__init__

        transport = httpx.MockTransport(handler)

        def patched_init(self, base_url, token=None, timeout=30.0):
            orig_init(self, base_url, token, timeout)
            self._client = httpx.Client(base_url=base_url, transport=transport)

        monkeypatch = pytest.MonkeyPatch()
        monkeypatch.setattr(http_mod.HTTPClient, "__init__", patched_init)
        try:
            client = MLDClient(
                base_url="http://localhost:8001",
                username="admin",
                password="secret",
            )
            assert client._http._token == "init-tok"
            assert len(requests_made) == 1
            assert "/login" in str(requests_made[0].url)
            client.close()
        finally:
            monkeypatch.undo()

    def test_no_login_without_credentials(self):
        """MLDClient() without username/password should not attempt login."""
        client = MLDClient(base_url="http://localhost:8001")
        # No login request made — token stays None
        assert client._http._token is None
        client.close()
