# #region DashboardsApiTests [TYPE Module] [C:3] [SEMANTICS test, dashboard, api, listing, migration]
# @BRIEF Unit tests for dashboards API endpoints.
# @LAYER API
# @RELATION DEPENDS_ON -> [DashboardsApi]
from datetime import UTC, datetime
import pytest
from unittest.mock import AsyncMock, MagicMock, patch

from fastapi.testclient import TestClient

from src.api.routes.dashboards import DashboardsResponse
from src.app import app
from src.core.database import get_db
from src.dependencies import (
    get_config_manager,
    get_current_user,
    get_mapping_service,
    get_resource_service,
    get_task_manager,
    has_permission,
)
from src.services.profile_service import ProfileService as DomainProfileService

# Global mock user for get_current_user dependency overrides
mock_user = MagicMock()
mock_user.id = "u-1"
mock_user.username = "testuser"
mock_user.roles = []
admin_role = MagicMock()
admin_role.name = "Admin"
mock_user.roles.append(admin_role)
@pytest.fixture(autouse=True)
def mock_deps():
    config_manager = MagicMock()
    task_manager = MagicMock()
    resource_service = MagicMock()
    mapping_service = MagicMock()
    db = MagicMock()
    app.dependency_overrides[get_config_manager] = lambda: config_manager
    app.dependency_overrides[get_task_manager] = lambda: task_manager
    app.dependency_overrides[get_resource_service] = lambda: resource_service
    app.dependency_overrides[get_mapping_service] = lambda: mapping_service
    app.dependency_overrides[get_current_user] = lambda: mock_user
    app.dependency_overrides[get_db] = lambda: db
    app.dependency_overrides[has_permission("plugin:migration", "READ")] = (
        lambda: mock_user
    )
    app.dependency_overrides[has_permission("plugin:migration", "EXECUTE")] = (
        lambda: mock_user
    )
    app.dependency_overrides[has_permission("plugin:backup", "EXECUTE")] = (
        lambda: mock_user
    )
    app.dependency_overrides[has_permission("tasks", "READ")] = lambda: mock_user
    yield {
        "config": config_manager,
        "task": task_manager,
        "resource": resource_service,
        "mapping": mapping_service,
        "db": db,
    }
    app.dependency_overrides.clear()
client = TestClient(app)
# #region test_get_dashboards_success [TYPE Function]
# @RELATION BINDS_TO -> DashboardsApiTests
# @BRIEF Validate dashboards listing returns a populated response that satisfies the schema contract.
# @TEST: GET /api/dashboards returns 200 and valid schema
# @PRE  env_id exists
# @POST  Response matches DashboardsResponse schema
def test_get_dashboards_success(mock_deps):
    """Uses @TEST_FIXTURE: dashboard_list_happy data."""
    mock_env = MagicMock()
    mock_env.id = "prod"
    mock_deps["config"].get_environments.return_value = [mock_env]
    mock_deps["task"].get_all_tasks.return_value = []
    # @TEST_FIXTURE  dashboard_list_happy -> {"id": 1, "title": "Main Revenue"}
    mock_deps["resource"].get_dashboards_with_status = AsyncMock(
        return_value=[
            {
                "id": 1,
                "title": "Main Revenue",
                "slug": "main-revenue",
                "git_status": {"branch": "main", "sync_status": "OK"},
                "last_task": {"task_id": "task-1", "status": "SUCCESS"},
            }
        ]
    )
    response = client.get("/api/dashboards?env_id=prod")
    assert response.status_code == 200
    data = response.json()
    # exhaustive @POST assertions
    assert "dashboards" in data
    assert len(data["dashboards"]) == 1
    assert data["dashboards"][0]["title"] == "Main Revenue"
    assert data["total"] == 1
    assert "page" in data
    DashboardsResponse(**data)
# #endregion test_get_dashboards_success
# #region test_get_dashboards_with_search [TYPE Function]
# @RELATION BINDS_TO -> DashboardsApiTests
# @BRIEF Validate dashboards listing applies the search filter and returns only matching rows.
# @TEST: GET /api/dashboards filters by search term
# @PRE  search parameter provided
# @POST  Only matching dashboards returned
def test_get_dashboards_with_search(mock_deps):
    mock_env = MagicMock()
    mock_env.id = "prod"
    mock_deps["config"].get_environments.return_value = [mock_env]
    mock_deps["task"].get_all_tasks.return_value = []
    async def mock_get_dashboards(env, tasks, include_git_status=False):
        return [
            {
                "id": 1,
                "title": "Sales Report",
                "slug": "sales",
                "git_status": {"branch": "main", "sync_status": "OK"},
                "last_task": None,
            },
            {
                "id": 2,
                "title": "Marketing Dashboard",
                "slug": "marketing",
                "git_status": {"branch": "main", "sync_status": "OK"},
                "last_task": None,
            },
        ]
    mock_deps["resource"].get_dashboards_with_status = AsyncMock(
        side_effect=mock_get_dashboards
    )
    response = client.get("/api/dashboards?env_id=prod&search=sales")
    assert response.status_code == 200
    data = response.json()
    # @POST  Filtered result count must match search
    assert len(data["dashboards"]) == 1
    assert data["dashboards"][0]["title"] == "Sales Report"
# #endregion test_get_dashboards_with_search
# #region test_get_dashboards_empty [TYPE Function]
# @RELATION BINDS_TO -> DashboardsApiTests
# @BRIEF Validate dashboards listing returns an empty payload for an environment without dashboards.
# @TEST_EDGE  empty_dashboards -> {env_id: 'empty_env', expected_total: 0}
def test_get_dashboards_empty(mock_deps):
    """@TEST_EDGE: empty_dashboards -> {env_id: 'empty_env', expected_total: 0}"""
    mock_env = MagicMock()
    mock_env.id = "empty_env"
    mock_deps["config"].get_environments.return_value = [mock_env]
    mock_deps["task"].get_all_tasks.return_value = []
    mock_deps["resource"].get_dashboards_with_status = AsyncMock(return_value=[])
    response = client.get("/api/dashboards?env_id=empty_env")
    assert response.status_code == 200
    data = response.json()
    assert data["total"] == 0
    assert len(data["dashboards"]) == 0
    assert data["total_pages"] == 1
    DashboardsResponse(**data)
# #endregion test_get_dashboards_empty
# #region test_get_dashboards_superset_failure [TYPE Function]
# @RELATION BINDS_TO -> DashboardsApiTests
# @BRIEF Validate dashboards listing surfaces a 503 contract when Superset access fails.
# @TEST_EDGE  external_superset_failure -> {env_id: 'bad_conn', status: 503}
def test_get_dashboards_superset_failure(mock_deps):
    """@TEST_EDGE: external_superset_failure -> {env_id: 'bad_conn', status: 503}"""
    mock_env = MagicMock()
    mock_env.id = "bad_conn"
    mock_deps["config"].get_environments.return_value = [mock_env]
    mock_deps["task"].get_all_tasks.return_value = []
    mock_deps["resource"].get_dashboards_with_status = AsyncMock(
        side_effect=Exception("Connection refused")
    )
    response = client.get("/api/dashboards?env_id=bad_conn")
    assert response.status_code == 503
    assert "Failed to fetch dashboards" in response.json()["detail"]
# #endregion test_get_dashboards_superset_failure
# #region test_get_dashboards_env_not_found [TYPE Function]
# @RELATION BINDS_TO -> DashboardsApiTests
# @BRIEF Validate dashboards listing returns 404 when the requested environment does not exist.
# @TEST: GET /api/dashboards returns 404 if env_id missing
# @PRE  env_id does not exist
# @POST  Returns 404 error
def test_get_dashboards_env_not_found(mock_deps):
    mock_deps["config"].get_environments.return_value = []
    response = client.get("/api/dashboards?env_id=nonexistent")
    assert response.status_code == 404
    assert "Environment not found" in response.json()["detail"]
# #endregion test_get_dashboards_env_not_found
# #region test_get_dashboards_invalid_pagination [TYPE Function]
# @RELATION BINDS_TO -> DashboardsApiTests
# @BRIEF Validate dashboards listing rejects invalid pagination parameters with 400 responses.
# @TEST: GET /api/dashboards returns 400 for invalid page/page_size
# @PRE  page < 1 or page_size > 100
# @POST  Returns 400 error
def test_get_dashboards_invalid_pagination(mock_deps):
    mock_env = MagicMock()
    mock_env.id = "prod"
    mock_deps["config"].get_environments.return_value = [mock_env]
    # Invalid page
    response = client.get("/api/dashboards?env_id=prod&page=0")
    assert response.status_code == 400
    assert "Page must be >= 1" in response.json()["detail"]
    # Invalid page_size
    response = client.get("/api/dashboards?env_id=prod&page_size=101")
    assert response.status_code == 400
    assert "Page size must be between 1 and 100" in response.json()["detail"]
# #endregion test_get_dashboards_invalid_pagination
# #region test_get_dashboard_detail_success [TYPE Function]
# @RELATION BINDS_TO -> DashboardsApiTests
# @BRIEF Validate dashboard detail returns charts and datasets for an existing dashboard.
# @TEST: GET /api/dashboards/{id} returns dashboard detail with charts and datasets
def test_get_dashboard_detail_success(mock_deps):
    with patch("src.api.routes.dashboards._detail_routes.SupersetClient") as mock_client_cls:
        mock_env = MagicMock()
        mock_env.id = "prod"
        mock_deps["config"].get_environments.return_value = [mock_env]
        mock_client = MagicMock()
        mock_client.get_dashboard_detail.return_value = {
            "id": 42,
            "title": "Revenue Dashboard",
            "slug": "revenue-dashboard",
            "url": "/superset/dashboard/42/",
            "description": "Overview",
            "last_modified": "2026-02-20T10:00:00+00:00",
            "published": True,
            "charts": [
                {
                    "id": 100,
                    "title": "Revenue by Month",
                    "viz_type": "line",
                    "dataset_id": 7,
                    "last_modified": "2026-02-19T10:00:00+00:00",
                    "overview": "line",
                }
            ],
            "datasets": [
                {
                    "id": 7,
                    "table_name": "fact_revenue",
                    "schema": "mart",
                    "database": "Analytics",
                    "last_modified": "2026-02-18T10:00:00+00:00",
                    "overview": "mart.fact_revenue",
                }
            ],
            "chart_count": 1,
            "dataset_count": 1,
        }
        mock_client_cls.return_value = mock_client
        response = client.get("/api/dashboards/42?env_id=prod")
        assert response.status_code == 200
        payload = response.json()
        assert payload["id"] == 42
        assert payload["chart_count"] == 1
        assert payload["dataset_count"] == 1
# #endregion test_get_dashboard_detail_success
# #region test_get_dashboard_detail_env_not_found [TYPE Function]
# @RELATION BINDS_TO -> DashboardsApiTests
# @BRIEF Validate dashboard detail returns 404 when the requested environment is missing.
# @TEST: GET /api/dashboards/{id} returns 404 for missing environment
def test_get_dashboard_detail_env_not_found(mock_deps):
    mock_deps["config"].get_environments.return_value = []
    response = client.get("/api/dashboards/42?env_id=missing")
    assert response.status_code == 404
    assert "Environment not found" in response.json()["detail"]
# #endregion test_get_dashboard_detail_env_not_found
# #region test_migrate_dashboards_success [TYPE Function]
# @RELATION BINDS_TO -> DashboardsApiTests
# @TEST: POST /api/dashboards/migrate creates migration task
# @PRE  Valid source_env_id, target_env_id, dashboard_ids
# @BRIEF Validate dashboard migration request creates an async task and returns its identifier.
# @POST  Returns task_id and create_task was called
def test_migrate_dashboards_success(mock_deps):
    mock_source = MagicMock()
    mock_source.id = "source"
    mock_target = MagicMock()
    mock_target.id = "target"
    mock_deps["config"].get_environments.return_value = [mock_source, mock_target]
    mock_task = MagicMock()
    mock_task.id = "task-migrate-123"
    mock_deps["task"].create_task = AsyncMock(return_value=mock_task)
    response = client.post(
        "/api/dashboards/migrate",
        json={
            "source_env_id": "source",
            "target_env_id": "target",
            "dashboard_ids": [1, 2, 3],
            "db_mappings": {"old_db": "new_db"},
        },
    )
    assert response.status_code == 200
    data = response.json()
    assert "task_id" in data
    # @POST/@SIDE_EFFECT: create_task was called
    mock_deps["task"].create_task.assert_called_once()
# #endregion test_migrate_dashboards_success
# #region test_migrate_dashboards_no_ids [TYPE Function]
# @RELATION BINDS_TO -> DashboardsApiTests
# @TEST: POST /api/dashboards/migrate returns 400 for empty dashboard_ids
# @PRE  dashboard_ids is empty
# @BRIEF Validate dashboard migration rejects empty dashboard identifier lists.
# @POST  Returns 400 error
def test_migrate_dashboards_no_ids(mock_deps):
    response = client.post(
        "/api/dashboards/migrate",
        json={
            "source_env_id": "source",
            "target_env_id": "target",
            "dashboard_ids": [],
        },
    )
    assert response.status_code == 400
    assert "At least one dashboard ID must be provided" in response.json()["detail"]
# #endregion test_migrate_dashboards_no_ids
# #region test_migrate_dashboards_env_not_found [TYPE Function]
# @RELATION BINDS_TO -> DashboardsApiTests
# @BRIEF Validate migration creation returns 404 when the source environment cannot be resolved.
# @PRE  source_env_id and target_env_id are valid environment IDs
def test_migrate_dashboards_env_not_found(mock_deps):
    """@PRE: source_env_id and target_env_id are valid environment IDs."""
    mock_deps["config"].get_environments.return_value = []
    response = client.post(
        "/api/dashboards/migrate",
        json={"source_env_id": "ghost", "target_env_id": "t", "dashboard_ids": [1]},
    )
    assert response.status_code == 404
    assert "Source environment not found" in response.json()["detail"]
# #endregion test_migrate_dashboards_env_not_found
# #region test_backup_dashboards_success [TYPE Function]
# @RELATION BINDS_TO -> DashboardsApiTests
# @TEST: POST /api/dashboards/backup creates backup task
# @PRE  Valid env_id, dashboard_ids
# @BRIEF Validate dashboard backup request creates an async backup task and returns its identifier.
# @POST  Returns task_id and create_task was called
def test_backup_dashboards_success(mock_deps):
    mock_env = MagicMock()
    mock_env.id = "prod"
    mock_deps["config"].get_environments.return_value = [mock_env]
    mock_task = MagicMock()
    mock_task.id = "task-backup-456"
    mock_deps["task"].create_task = AsyncMock(return_value=mock_task)
    response = client.post(
        "/api/dashboards/backup",
        json={"env_id": "prod", "dashboard_ids": [1, 2, 3], "schedule": "0 0 * * *"},
    )
    assert response.status_code == 200
    data = response.json()
    assert "task_id" in data
    # @POST/@SIDE_EFFECT: create_task was called
    mock_deps["task"].create_task.assert_called_once()
# #endregion test_backup_dashboards_success
# #region test_backup_dashboards_env_not_found [TYPE Function]
# @RELATION BINDS_TO -> DashboardsApiTests
# @BRIEF Validate backup task creation returns 404 when the target environment is missing.
# @PRE  env_id is a valid environment ID
def test_backup_dashboards_env_not_found(mock_deps):
    """@PRE: env_id is a valid environment ID."""
    mock_deps["config"].get_environments.return_value = []
    response = client.post(
        "/api/dashboards/backup", json={"env_id": "ghost", "dashboard_ids": [1]}
    )
    assert response.status_code == 404
    assert "Environment not found" in response.json()["detail"]
# #endregion test_backup_dashboards_env_not_found
# #region test_get_database_mappings_success [TYPE Function]
# @RELATION BINDS_TO -> DashboardsApiTests
# @TEST: GET /api/dashboards/db-mappings returns mapping suggestions
# @PRE  Valid source_env_id, target_env_id
# @BRIEF Validate database mapping suggestions are returned for valid source and target environments.
# @POST  Returns list of database mappings
def test_get_database_mappings_success(mock_deps):
    mock_source = MagicMock()
    mock_source.id = "prod"
    mock_target = MagicMock()
    mock_target.id = "staging"
    mock_deps["config"].get_environments.return_value = [mock_source, mock_target]
    mock_deps["mapping"].get_suggestions = AsyncMock(
        return_value=[
            {
                "source_db": "old_sales",
                "target_db": "new_sales",
                "source_db_uuid": "uuid-1",
                "target_db_uuid": "uuid-2",
                "confidence": 0.95,
            }
        ]
    )
    response = client.get(
        "/api/dashboards/db-mappings?source_env_id=prod&target_env_id=staging"
    )
    assert response.status_code == 200
    data = response.json()
    assert "mappings" in data
    assert len(data["mappings"]) == 1
    assert data["mappings"][0]["confidence"] == 0.95
# #endregion test_get_database_mappings_success
# #region test_get_database_mappings_env_not_found [TYPE Function]
# @RELATION BINDS_TO -> DashboardsApiTests
# @BRIEF Validate database mapping suggestions return 404 when either environment is missing.
# @PRE  source_env_id and target_env_id are valid environment IDs
def test_get_database_mappings_env_not_found(mock_deps):
    """@PRE: source_env_id must be a valid environment."""
    mock_deps["config"].get_environments.return_value = []
    response = client.get(
        "/api/dashboards/db-mappings?source_env_id=ghost&target_env_id=t"
    )
    assert response.status_code == 404
# #endregion test_get_database_mappings_env_not_found
# #region test_get_dashboard_tasks_history_filters_success [TYPE Function]
# @RELATION BINDS_TO -> DashboardsApiTests
# @BRIEF Validate dashboard task history returns only related backup and LLM tasks.
# @TEST: GET /api/dashboards/{id}/tasks returns backup and llm tasks for dashboard
def test_get_dashboard_tasks_history_filters_success(mock_deps):
    now = datetime.now(UTC)
    llm_task = MagicMock()
    llm_task.id = "task-llm-1"
    llm_task.plugin_id = "llm_dashboard_validation"
    llm_task.status = "SUCCESS"
    llm_task.started_at = now
    llm_task.finished_at = now
    llm_task.params = {"dashboard_id": "42", "environment_id": "prod"}
    llm_task.result = {"summary": "LLM validation complete"}
    backup_task = MagicMock()
    backup_task.id = "task-backup-1"
    backup_task.plugin_id = "superset-backup"
    backup_task.status = "RUNNING"
    backup_task.started_at = now
    backup_task.finished_at = None
    backup_task.params = {"env": "prod", "dashboards": [42]}
    backup_task.result = {}
    other_task = MagicMock()
    other_task.id = "task-other"
    other_task.plugin_id = "superset-backup"
    other_task.status = "SUCCESS"
    other_task.started_at = now
    other_task.finished_at = now
    other_task.params = {"env": "prod", "dashboards": [777]}
    other_task.result = {}
    mock_deps["task"].get_all_tasks.return_value = [other_task, llm_task, backup_task]
    response = client.get("/api/dashboards/42/tasks?env_id=prod&limit=10")
    assert response.status_code == 200
    data = response.json()
    assert data["dashboard_id"] == 42
    assert len(data["items"]) == 2
    assert {item["plugin_id"] for item in data["items"]} == {
        "llm_dashboard_validation",
        "superset-backup",
    }
# #endregion test_get_dashboard_tasks_history_filters_success
# #region test_get_dashboard_thumbnail_success [TYPE Function]
# @RELATION BINDS_TO -> DashboardsApiTests
# @BRIEF Validate dashboard thumbnail endpoint proxies image bytes and content type from Superset.
# @TEST: GET /api/dashboards/{id}/thumbnail proxies image bytes from Superset
def test_get_dashboard_thumbnail_success(mock_deps):
    with patch("src.api.routes.dashboards._detail_routes.SupersetClient") as mock_client_cls:
        mock_env = MagicMock()
        mock_env.id = "prod"
        mock_deps["config"].get_environments.return_value = [mock_env]
        mock_client = MagicMock()
        mock_response = MagicMock()
        mock_response.status_code = 200
        mock_response.content = b"fake-image-bytes"
        mock_response.headers = {"Content-Type": "image/png"}
        def _network_request(method, endpoint, **kwargs):
            if method == "POST":
                return {"image_url": "/api/v1/dashboard/42/screenshot/abc123/"}
            return mock_response
        mock_client.network.request.side_effect = _network_request
        mock_client_cls.return_value = mock_client
        response = client.get("/api/dashboards/42/thumbnail?env_id=prod")
        assert response.status_code == 200
        assert response.content == b"fake-image-bytes"
        assert response.headers["content-type"].startswith("image/png")
# #endregion test_get_dashboard_thumbnail_success
# #region _build_profile_preference_stub [TYPE Function]
# @RELATION BINDS_TO -> DashboardsApiTests
# @BRIEF Creates profile preference payload stub for dashboards filter contract tests.
# @PRE  username can be empty; enabled indicates profile-default toggle state.
# @POST  Returns object compatible with ProfileService.get_my_preference contract.
def _build_profile_preference_stub(username: str, enabled: bool):
    preference = MagicMock()
    preference.superset_username = username
    preference.superset_username_normalized = (
        str(username or "").strip().lower() or None
    )
    preference.show_only_my_dashboards = bool(enabled)
    payload = MagicMock()
    payload.preference = preference
    return payload
# #endregion _build_profile_preference_stub
# #region _matches_actor_case_insensitive [TYPE Function]
# @RELATION BINDS_TO -> DashboardsApiTests
# @BRIEF Applies trim + case-insensitive owners OR modified_by matching used by route contract tests.
# @PRE  owners can be None or list-like values.
# @POST  Returns True when bound username matches any owner or modified_by.
def _matches_actor_case_insensitive(bound_username, owners, modified_by):
    normalized_bound = str(bound_username or "").strip().lower()
    if not normalized_bound:
        return False
    owner_tokens = []
    for owner in owners or []:
        token = str(owner or "").strip().lower()
        if token:
            owner_tokens.append(token)
    modified_token = str(modified_by or "").strip().lower()
    return normalized_bound in owner_tokens or bool(
        modified_token and modified_token == normalized_bound
    )
# #endregion _matches_actor_case_insensitive
# #region test_get_dashboards_profile_filter_contract_owners_or_modified_by [TYPE Function]
# @RELATION BINDS_TO -> DashboardsApiTests
# @TEST: GET /api/dashboards applies profile-default filter with owners OR modified_by trim+case-insensitive semantics.
# @BRIEF Validate profile-default filtering matches owner and modifier aliases using normalized Superset actor values.
# @PRE  Current user has enabled profile-default preference and bound username.
# @POST  Response includes only matching dashboards and effective_profile_filter metadata.
def test_get_dashboards_profile_filter_contract_owners_or_modified_by(mock_deps):
    mock_env = MagicMock()
    mock_env.id = "prod"
    mock_deps["config"].get_environments.return_value = [mock_env]
    mock_deps["task"].get_all_tasks.return_value = []
    mock_deps["resource"].get_dashboards_with_status = AsyncMock(
        return_value=[
            {
                "id": 1,
                "title": "Owner Match",
                "slug": "owner-match",
                "owners": ["  John_Doe  "],
                "modified_by": "someone_else",
            },
            {
                "id": 2,
                "title": "Modifier Match",
                "slug": "modifier-match",
                "owners": ["analytics-team"],
                "modified_by": "  JOHN_DOE ",
            },
            {
                "id": 3,
                "title": "No Match",
                "slug": "no-match",
                "owners": ["another-user"],
                "modified_by": "nobody",
            },
        ]
    )
    with patch("src.api.routes.dashboards._listing_routes.ProfileService") as profile_service_cls:
        profile_service = MagicMock()
        profile_service.get_my_preference.return_value = _build_profile_preference_stub(
            username="  JOHN_DOE  ",
            enabled=True,
        )
        profile_service.matches_dashboard_actor.side_effect = (
            _matches_actor_case_insensitive
        )
        profile_service_cls.return_value = profile_service
        response = client.get(
            "/api/dashboards?env_id=prod&page_context=dashboards_main&apply_profile_default=true"
        )
    assert response.status_code == 200
    payload = response.json()
    assert payload["total"] == 2
    assert {item["id"] for item in payload["dashboards"]} == {1, 2}
    assert payload["effective_profile_filter"]["applied"] is True
    assert payload["effective_profile_filter"]["source_page"] == "dashboards_main"
    assert payload["effective_profile_filter"]["override_show_all"] is False
    assert payload["effective_profile_filter"]["username"] == "john_doe"
    assert payload["effective_profile_filter"]["match_logic"] == "owners_or_modified_by"
# #endregion test_get_dashboards_profile_filter_contract_owners_or_modified_by
# #region test_get_dashboards_override_show_all_contract [TYPE Function]
# @RELATION BINDS_TO -> DashboardsApiTests
# @TEST: GET /api/dashboards honors override_show_all and disables profile-default filter for current page.
# @BRIEF Validate override_show_all bypasses profile-default filtering without changing dashboard list semantics.
# @PRE  Profile-default preference exists but override_show_all=true query is provided.
# @POST  Response remains unfiltered and effective_profile_filter.applied is false.
def test_get_dashboards_override_show_all_contract(mock_deps):
    mock_env = MagicMock()
    mock_env.id = "prod"
    mock_deps["config"].get_environments.return_value = [mock_env]
    mock_deps["task"].get_all_tasks.return_value = []
    mock_deps["resource"].get_dashboards_with_status = AsyncMock(
        return_value=[
            {
                "id": 1,
                "title": "Dash A",
                "slug": "dash-a",
                "owners": ["john_doe"],
                "modified_by": "john_doe",
            },
            {
                "id": 2,
                "title": "Dash B",
                "slug": "dash-b",
                "owners": ["other"],
                "modified_by": "other",
            },
        ]
    )
    with patch("src.api.routes.dashboards.ProfileService") as profile_service_cls:
        profile_service = MagicMock()
        profile_service.get_my_preference.return_value = _build_profile_preference_stub(
            username="john_doe",
            enabled=True,
        )
        profile_service.matches_dashboard_actor.side_effect = (
            _matches_actor_case_insensitive
        )
        profile_service_cls.return_value = profile_service
        response = client.get(
            "/api/dashboards?env_id=prod&page_context=dashboards_main&apply_profile_default=true&override_show_all=true"
        )
    assert response.status_code == 200
    payload = response.json()
    assert payload["total"] == 2
    assert {item["id"] for item in payload["dashboards"]} == {1, 2}
    assert payload["effective_profile_filter"]["applied"] is False
    assert payload["effective_profile_filter"]["source_page"] == "dashboards_main"
    assert payload["effective_profile_filter"]["override_show_all"] is True
    assert payload["effective_profile_filter"]["username"] is None
    assert payload["effective_profile_filter"]["match_logic"] is None
    profile_service.matches_dashboard_actor.assert_not_called()
# #endregion test_get_dashboards_override_show_all_contract
# #region test_get_dashboards_profile_filter_no_match_results_contract [TYPE Function]
# @RELATION BINDS_TO -> DashboardsApiTests
# @TEST: GET /api/dashboards returns empty result set when profile-default filter is active and no dashboard actors match.
# @BRIEF Validate profile-default filtering returns an empty dashboard page when no actor aliases match the bound user.
# @PRE  Profile-default preference is enabled with bound username and all dashboards are non-matching.
# @POST  Response total is 0 with deterministic pagination and active effective_profile_filter metadata.
def test_get_dashboards_profile_filter_no_match_results_contract(mock_deps):
    mock_env = MagicMock()
    mock_env.id = "prod"
    mock_deps["config"].get_environments.return_value = [mock_env]
    mock_deps["task"].get_all_tasks.return_value = []
    mock_deps["resource"].get_dashboards_with_status = AsyncMock(
        return_value=[
            {
                "id": 101,
                "title": "Team Dashboard",
                "slug": "team-dashboard",
                "owners": ["analytics-team"],
                "modified_by": "someone_else",
            },
            {
                "id": 102,
                "title": "Ops Dashboard",
                "slug": "ops-dashboard",
                "owners": ["ops-user"],
                "modified_by": "ops-user",
            },
        ]
    )
    with patch("src.api.routes.dashboards._listing_routes.ProfileService") as profile_service_cls:
        profile_service = MagicMock()
        profile_service.get_my_preference.return_value = _build_profile_preference_stub(
            username="john_doe",
            enabled=True,
        )
        profile_service.matches_dashboard_actor.side_effect = (
            _matches_actor_case_insensitive
        )
        profile_service_cls.return_value = profile_service
        response = client.get(
            "/api/dashboards?env_id=prod&page_context=dashboards_main&apply_profile_default=true"
        )
    assert response.status_code == 200
    payload = response.json()
    assert payload["total"] == 0
    assert payload["dashboards"] == []
    assert payload["page"] == 1
    assert payload["page_size"] == 10
    assert payload["total_pages"] == 1
    assert payload["effective_profile_filter"]["applied"] is True
    assert payload["effective_profile_filter"]["source_page"] == "dashboards_main"
    assert payload["effective_profile_filter"]["override_show_all"] is False
    assert payload["effective_profile_filter"]["username"] == "john_doe"
    assert payload["effective_profile_filter"]["match_logic"] == "owners_or_modified_by"
# #endregion test_get_dashboards_profile_filter_no_match_results_contract
# #region test_get_dashboards_page_context_other_disables_profile_default [TYPE Function]
# @RELATION BINDS_TO -> DashboardsApiTests
# @TEST: GET /api/dashboards does not auto-apply profile-default filter outside dashboards_main page context.
# @BRIEF Validate non-dashboard page contexts suppress profile-default filtering and preserve unfiltered results.
# @PRE  Profile-default preference exists but page_context=other query is provided.
# @POST  Response remains unfiltered and metadata reflects source_page=other.
def test_get_dashboards_page_context_other_disables_profile_default(mock_deps):
    mock_env = MagicMock()
    mock_env.id = "prod"
    mock_deps["config"].get_environments.return_value = [mock_env]
    mock_deps["task"].get_all_tasks.return_value = []
    mock_deps["resource"].get_dashboards_with_status = AsyncMock(
        return_value=[
            {
                "id": 1,
                "title": "Dash A",
                "slug": "dash-a",
                "owners": ["john_doe"],
                "modified_by": "john_doe",
            },
            {
                "id": 2,
                "title": "Dash B",
                "slug": "dash-b",
                "owners": ["other"],
                "modified_by": "other",
            },
        ]
    )
    with patch("src.api.routes.dashboards.ProfileService") as profile_service_cls:
        profile_service = MagicMock()
        profile_service.get_my_preference.return_value = _build_profile_preference_stub(
            username="john_doe",
            enabled=True,
        )
        profile_service.matches_dashboard_actor.side_effect = (
            _matches_actor_case_insensitive
        )
        profile_service_cls.return_value = profile_service
        response = client.get(
            "/api/dashboards?env_id=prod&page_context=other&apply_profile_default=true"
        )
    assert response.status_code == 200
    payload = response.json()
    assert payload["total"] == 2
    assert {item["id"] for item in payload["dashboards"]} == {1, 2}
    assert payload["effective_profile_filter"]["applied"] is False
    assert payload["effective_profile_filter"]["source_page"] == "other"
    assert payload["effective_profile_filter"]["override_show_all"] is False
    assert payload["effective_profile_filter"]["username"] is None
    assert payload["effective_profile_filter"]["match_logic"] is None
    profile_service.matches_dashboard_actor.assert_not_called()
# #endregion test_get_dashboards_page_context_other_disables_profile_default
# #region test_get_dashboards_profile_filter_matches_display_alias_without_detail_fanout [TYPE Function]
# @RELATION BINDS_TO -> DashboardsApiTests
# @TEST: GET /api/dashboards resolves Superset display-name alias once and filters without per-dashboard detail calls.
# @BRIEF Validate profile-default filtering reuses resolved Superset display aliases without triggering per-dashboard detail fanout.
# @PRE  Profile-default filter is active, bound username is `admin`, dashboard actors contain display labels.
# @POST  Route matches by alias (`Superset Admin`) and does not call `SupersetClient.get_dashboard` in list filter path.
def test_get_dashboards_profile_filter_matches_display_alias_without_detail_fanout(
    mock_deps,
):
    mock_env = MagicMock()
    mock_env.id = "prod"
    mock_deps["config"].get_environments.return_value = [mock_env]
    mock_deps["task"].get_all_tasks.return_value = []
    mock_deps["resource"].get_dashboards_with_status = AsyncMock(
        return_value=[
            {
                "id": 5,
                "title": "Alias Match",
                "slug": "alias-match",
                "owners": [],
                "created_by": None,
                "modified_by": "Superset Admin",
            },
            {
                "id": 6,
                "title": "Alias No Match",
                "slug": "alias-no-match",
                "owners": [],
                "created_by": None,
                "modified_by": "Other User",
            },
        ]
    )
    with (
        patch("src.api.routes.dashboards._listing_routes.ProfileService") as profile_service_cls,
        patch("src.api.routes.dashboards._projection.SupersetClient") as superset_client_cls,
        patch(
            "src.api.routes.dashboards._projection.SupersetAccountLookupAdapter"
        ) as lookup_adapter_cls,
    ):
        profile_service = MagicMock()
        profile_service.get_my_preference.return_value = _build_profile_preference_stub(
            username="admin",
            enabled=True,
        )
        profile_service.matches_dashboard_actor.side_effect = (
            _matches_actor_case_insensitive
        )
        profile_service_cls.return_value = profile_service
        superset_client = MagicMock()
        superset_client_cls.return_value = superset_client
        lookup_adapter = MagicMock()
        lookup_adapter.get_users_page.return_value = {
            "items": [
                {
                    "environment_id": "prod",
                    "username": "admin",
                    "display_name": "Superset Admin",
                    "email": "admin@example.com",
                    "is_active": True,
                }
            ],
            "total": 1,
        }
        lookup_adapter_cls.return_value = lookup_adapter
        response = client.get(
            "/api/dashboards?env_id=prod&page_context=dashboards_main&apply_profile_default=true"
        )
    assert response.status_code == 200
    payload = response.json()
    assert payload["total"] == 1
    assert {item["id"] for item in payload["dashboards"]} == {5}
    assert payload["effective_profile_filter"]["applied"] is True
    lookup_adapter.get_users_page.assert_called_once()
    superset_client.get_dashboard.assert_not_called()
# #endregion test_get_dashboards_profile_filter_matches_display_alias_without_detail_fanout
# #region test_get_dashboards_profile_filter_matches_owner_object_payload_contract [TYPE Function]
# @RELATION BINDS_TO -> DashboardsApiTests
# @TEST: GET /api/dashboards profile-default filter matches Superset owner object payloads.
# @BRIEF Validate profile-default filtering accepts owner object payloads once aliases resolve to the bound Superset username.
# @PRE  Profile-default preference is enabled and owners list contains dict payloads.
# @POST  Response keeps dashboards where owner object resolves to bound username alias.
def test_get_dashboards_profile_filter_matches_owner_object_payload_contract(mock_deps):
    mock_env = MagicMock()
    mock_env.id = "prod"
    mock_deps["config"].get_environments.return_value = [mock_env]
    mock_deps["task"].get_all_tasks.return_value = []
    mock_deps["resource"].get_dashboards_with_status = AsyncMock(
        return_value=[
            {
                "id": 701,
                "title": "Featured Charts",
                "slug": "featured-charts",
                "owners": [
                    {
                        "id": 11,
                        "first_name": "user",
                        "last_name": "1",
                        "username": None,
                        "email": "user_1@example.local",
                    }
                ],
                "modified_by": "another_user",
            },
            {
                "id": 702,
                "title": "Other Dashboard",
                "slug": "other-dashboard",
                "owners": [
                    {
                        "id": 12,
                        "first_name": "other",
                        "last_name": "user",
                        "username": None,
                        "email": "other@example.local",
                    }
                ],
                "modified_by": "other_user",
            },
        ]
    )
    with (
        patch("src.api.routes.dashboards._listing_routes.ProfileService") as profile_service_cls,
        patch(
            "src.api.routes.dashboards._projection._resolve_profile_actor_aliases",
            return_value=["user_1"],
        ),
    ):
        profile_service = MagicMock(spec=DomainProfileService)
        profile_service.get_my_preference.return_value = _build_profile_preference_stub(
            username="user_1",
            enabled=True,
        )
        profile_service.matches_dashboard_actor.side_effect = (
            lambda bound_username, owners, modified_by: any(
                str(owner.get("email", "")).split("@", 1)[0].strip().lower()
                == str(bound_username).strip().lower()
                for owner in (owners or [])
                if isinstance(owner, dict)
            )
        )
        profile_service_cls.return_value = profile_service
        response = client.get(
            "/api/dashboards?env_id=prod&page_context=dashboards_main&apply_profile_default=true"
        )
    assert response.status_code == 200
    payload = response.json()
    assert payload["total"] == 1
    assert {item["id"] for item in payload["dashboards"]} == {701}
    assert payload["dashboards"][0]["title"] == "Featured Charts"
# #endregion test_get_dashboards_profile_filter_matches_owner_object_payload_contract
# #endregion DashboardsApiTests
