"""Layer 2 — Client construction, resource bindings, config, and lifecycle."""

from __future__ import annotations

import httpx
import pytest
import respx

from kanoniv.client.client import KanonivAsyncClient, KanonivClient
from kanoniv.client.resources.audit import AsyncAuditResource, AuditResource
from kanoniv.client.resources.entities import AsyncEntitiesResource, EntitiesResource
from kanoniv.client.resources.jobs import AsyncJobsResource, JobsResource
from kanoniv.client.resources.overrides import AsyncOverridesResource, OverridesResource
from kanoniv.client.resources.reviews import AsyncReviewsResource, ReviewsResource
from kanoniv.client.resources.rules import AsyncRulesResource, RulesResource
from kanoniv.client.resources.sources import AsyncSourcesResource, SourcesResource
from kanoniv.client.resources.specs import AsyncSpecsResource, SpecsResource

from .conftest import BASE_URL


class TestClientConstruction:
    """Client construction configures transport, auth, resources, and lifecycle."""

    def test_default_base_url(self):
        c = KanonivClient(api_key="kn_test")
        try:
            assert c._transport._client.base_url == httpx.URL("https://api.kanoniv.com")
        finally:
            c.close()

    def test_custom_base_url(self):
        c = KanonivClient(api_key="kn_test", base_url="http://localhost:8000")
        try:
            assert "localhost" in str(c._transport._client.base_url)
        finally:
            c.close()

    def test_sync_context_manager_closes(self, mock_api: respx.Router):
        mock_api.get("/v1/stats").mock(
            return_value=httpx.Response(200, json={"total": 0}),
        )
        with KanonivClient(api_key="kn_test", base_url=BASE_URL, max_retries=0) as c:
            c.stats()
        assert c._transport._client.is_closed

    @pytest.mark.asyncio
    async def test_async_context_manager_closes(self, mock_api: respx.Router):
        mock_api.get("/v1/stats").mock(
            return_value=httpx.Response(200, json={"total": 0}),
        )
        async with KanonivAsyncClient(api_key="kn_test", base_url=BASE_URL, max_retries=0) as c:
            await c.stats()
        assert c._transport._client.is_closed

    def test_all_resources_attached_sync(self):
        c = KanonivClient(api_key="kn_test")
        try:
            assert isinstance(c.entities, EntitiesResource)
            assert isinstance(c.sources, SourcesResource)
            assert isinstance(c.rules, RulesResource)
            assert isinstance(c.jobs, JobsResource)
            assert isinstance(c.reviews, ReviewsResource)
            assert isinstance(c.overrides, OverridesResource)
            assert isinstance(c.audit, AuditResource)
            assert isinstance(c.specs, SpecsResource)
        finally:
            c.close()

    def test_all_resources_attached_async(self):
        c = KanonivAsyncClient(api_key="kn_test")
        assert isinstance(c.entities, AsyncEntitiesResource)
        assert isinstance(c.sources, AsyncSourcesResource)
        assert isinstance(c.rules, AsyncRulesResource)
        assert isinstance(c.jobs, AsyncJobsResource)
        assert isinstance(c.reviews, AsyncReviewsResource)
        assert isinstance(c.overrides, AsyncOverridesResource)
        assert isinstance(c.audit, AsyncAuditResource)
        assert isinstance(c.specs, AsyncSpecsResource)

    def test_bearer_token_header(self, mock_api: respx.Router):
        route = mock_api.get("/v1/stats").mock(
            return_value=httpx.Response(200, json={"total": 0}),
        )
        c = KanonivClient(access_token="tok_bearer123", base_url=BASE_URL, max_retries=0)
        try:
            c.stats()
            assert route.calls.last.request.headers["Authorization"] == "Bearer tok_bearer123"
        finally:
            c.close()

    def test_custom_timeout_propagated(self):
        c = KanonivClient(api_key="kn_test", timeout=60.0)
        try:
            assert c._transport._client.timeout.connect == 60.0
        finally:
            c.close()
