"""Integration coverage for the /navigation/sidebar endpoint.

These tests validate role-based filtering, ordering, and disabled-link handling
through the full FastAPI stack so future changes keep navigation behaviour under
explicit test coverage.
"""

from __future__ import annotations

from collections.abc import Callable
from typing import Any, Mapping

import pytest
from fastapi.testclient import TestClient

from models.navigation import NavigationGroup, NavigationLink
from services.unit_of_work import UnitOfWork


@pytest.fixture()
def seed_navigation(unit_of_work_factory: Callable[[], UnitOfWork]) -> Callable[[], None]:
    def _seed() -> None:
        with unit_of_work_factory() as uow:
            repo = uow.navigation
            assert repo is not None

            workspace = repo.add_group(
                NavigationGroup(
                    slug="workspace",
                    label="Workspace",
                    sort_order=10,
                )
            )
            insights = repo.add_group(
                NavigationGroup(
                    slug="insights",
                    label="Insights",
                    sort_order=20,
                )
            )

            repo.add_link(
                NavigationLink(
                    group_id=workspace.id,
                    slug="projects",
                    label="Projects",
                    href_override="/projects",
                    sort_order=5,
                    required_roles=[],
                )
            )
            repo.add_link(
                NavigationLink(
                    group_id=workspace.id,
                    slug="admin-tools",
                    label="Admin Tools",
                    href_override="/admin/tools",
                    sort_order=10,
                    required_roles=["admin"],
                )
            )
            repo.add_link(
                NavigationLink(
                    group_id=workspace.id,
                    slug="disabled-link",
                    label="Hidden",
                    href_override="/hidden",
                    sort_order=15,
                    required_roles=[],
                    is_enabled=False,
                )
            )
            repo.add_link(
                NavigationLink(
                    group_id=insights.id,
                    slug="reports",
                    label="Reports",
                    href_override="/reports",
                    sort_order=1,
                    required_roles=[],
                )
            )

    return _seed


def _link_labels(group_json: Mapping[str, Any]) -> list[str]:
    return [link["label"] for link in group_json["links"]]


def test_admin_session_receives_all_enabled_links(
    client: TestClient,
    seed_navigation: Callable[[], None],
) -> None:
    seed_navigation()

    response = client.get("/navigation/sidebar")
    assert response.status_code == 200
    payload = response.json()

    assert [group["label"] for group in payload["groups"]] == [
        "Workspace",
        "Insights",
    ]
    workspace, insights = payload["groups"]
    assert _link_labels(workspace) == ["Projects", "Admin Tools"]
    assert _link_labels(insights) == ["Reports"]
    assert payload["roles"] == ["admin"]


def test_viewer_session_filters_admin_only_links(
    client: TestClient,
    seed_navigation: Callable[[], None],
    test_user_headers: Callable[[str | None], dict[str, str]],
) -> None:
    seed_navigation()

    response = client.get(
        "/navigation/sidebar",
        headers=test_user_headers("viewer"),
    )
    assert response.status_code == 200
    payload = response.json()

    assert [group["label"] for group in payload["groups"]] == [
        "Workspace",
        "Insights",
    ]
    workspace, insights = payload["groups"]
    assert _link_labels(workspace) == ["Projects"]
    assert _link_labels(insights) == ["Reports"]
    assert payload["roles"] == ["viewer"]


def test_anonymous_access_is_rejected(
    client: TestClient,
    seed_navigation: Callable[[], None],
    test_user_headers: Callable[[str | None], dict[str, str]],
) -> None:
    seed_navigation()

    response = client.get(
        "/navigation/sidebar",
        headers=test_user_headers("anonymous"),
    )
    assert response.status_code == 401
