# #region DashboardListingRoutes [C:4] [TYPE Module] [SEMANTICS fastapi, dashboard, api, search]
# @BRIEF Dashboard listing route handler for Dashboard Hub.
# @LAYER API
# @RELATION DEPENDS_ON -> [EXT:frontend:DashboardRouter]]
# @RELATION DEPENDS_ON -> [DashboardSchemas]
# @RELATION DEPENDS_ON -> [DashboardHelpers]
# @RELATION DEPENDS_ON -> [DashboardProjection]

from typing import Any, Literal

from fastapi import Depends, HTTPException, Query
from sqlalchemy.orm import Session

from src.core.database import get_db
from src.core.logger import belief_scope, logger
from src.dependencies import (
    get_config_manager,
    get_current_user,
    get_resource_service,
    get_task_manager,
    has_permission,
)
from src.models.auth import User
from src.services.profile_service import ProfileService

from ._helpers import _dashboard_git_filter_value, _normalize_filter_values
from ._projection import (
    _get_profile_filter_binding,
    _matches_dashboard_actor_aliases,
    _project_dashboard_response_items,
    _resolve_profile_actor_aliases,
)
from ._router import router
from ._schemas import DashboardsResponse, EffectiveProfileFilter


# #region get_dashboards [C:3] [TYPE Function]
# @BRIEF Fetch list of dashboards from a specific environment with Git status and last task status
# @PRE  env_id must be a valid environment ID
# @PRE  page must be >= 1 if provided
# @PRE  page_size must be between 1 and 100 if provided
# @POST  Returns a list of dashboards with enhanced metadata and pagination info
# @POST  Response includes pagination metadata (page, page_size, total, total_pages)
# @POST  Response includes effective profile filter metadata for main dashboards page context
# @RELATION CALLS -> [EXT:method:get_dashboards_with_status]
@router.get("", response_model=DashboardsResponse)
async def get_dashboards(
    env_id: str,
    search: str | None = None,
    page: int = 1,
    page_size: int = 10,
    page_context: Literal["dashboards_main", "other"] = Query("dashboards_main"),
    apply_profile_default: bool = Query(default=True),
    override_show_all: bool = Query(default=False),
    filter_title: list[str] | None = Query(default=None),
    filter_git_status: list[str] | None = Query(default=None),
    filter_llm_status: list[str] | None = Query(default=None),
    filter_changed_on: list[str] | None = Query(default=None),
    filter_actor: list[str] | None = Query(default=None),
    config_manager=Depends(get_config_manager),
    task_manager=Depends(get_task_manager),
    resource_service=Depends(get_resource_service),
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db),
    _=Depends(has_permission("plugin:migration", "READ")),
):
    with belief_scope(
        "get_dashboards",
        f"env_id={env_id}, search={search}, page={page}, page_size={page_size}, "
        f"page_context={page_context}, applyp={apply_profile_default}, overhide={override_show_all}",
    ):
        if page < 1:
            logger.error(f"[get_dashboards][Coherence:Failed] Invalid page: {page}")
            raise HTTPException(status_code=400, detail="Page must be >= 1")
        if page_size < 1 or page_size > 100:
            logger.error(f"[get_dashboards][Coherence:Failed] Invalid page_size: {page_size}")
            raise HTTPException(status_code=400, detail="Page size must be between 1 and 100")

        environments = config_manager.get_environments()
        env = next((e for e in environments if e.id == env_id), None)
        if not env:
            logger.error(f"[get_dashboards][Coherence:Failed] Environment not found: {env_id}")
            raise HTTPException(status_code=404, detail="Environment not found")

        bound_username: str | None = None
        can_apply_profile_filter = False
        can_apply_slug_filter = False
        effective_profile_filter = EffectiveProfileFilter(
            applied=False,
            source_page=page_context,
            override_show_all=bool(override_show_all),
            username=None,
            match_logic=None,
        )
        profile_service: ProfileService | None = None

        try:
            profile_service_module = getattr(ProfileService, "__module__", "")
            is_mock_db = db.__class__.__module__.startswith("unittest.mock")
            use_profile_service = (not is_mock_db) or profile_service_module.startswith(
                "unittest.mock"
            )
            if use_profile_service:
                profile_service = ProfileService(db=db, config_manager=config_manager)
                profile_preference = _get_profile_filter_binding(
                    profile_service, current_user
                )
                normalized_username = (
                    str(profile_preference.get("superset_username_normalized") or "")
                    .strip()
                    .lower()
                )
                raw_username = (
                    str(profile_preference.get("superset_username") or "")
                    .strip()
                    .lower()
                )
                bound_username = normalized_username or raw_username or None

                can_apply_profile_filter = (
                    page_context == "dashboards_main"
                    and bool(apply_profile_default)
                    and not bool(override_show_all)
                    and bool(profile_preference.get("show_only_my_dashboards", False))
                    and bool(bound_username)
                )
                can_apply_slug_filter = (
                    page_context == "dashboards_main"
                    and bool(apply_profile_default)
                    and not bool(override_show_all)
                    and bool(profile_preference.get("show_only_slug_dashboards", True))
                )

                profile_match_logic = None
                if can_apply_profile_filter and can_apply_slug_filter:
                    profile_match_logic = "owners_or_modified_by+slug_only"
                elif can_apply_profile_filter:
                    profile_match_logic = "owners_or_modified_by"
                elif can_apply_slug_filter:
                    profile_match_logic = "slug_only"

                effective_profile_filter = EffectiveProfileFilter(
                    applied=bool(can_apply_profile_filter or can_apply_slug_filter),
                    source_page=page_context,
                    override_show_all=bool(override_show_all),
                    username=bound_username if can_apply_profile_filter else None,
                    match_logic=profile_match_logic,
                )
        except Exception as profile_error:
            logger.explore(
                f"Profile preference unavailable; continuing without profile-default filter: {profile_error}",
                extra={"src": "get_dashboards"},
            )

        try:
            all_tasks = task_manager.get_all_tasks()
            title_filters = _normalize_filter_values(filter_title)
            git_filters = _normalize_filter_values(filter_git_status)
            llm_filters = _normalize_filter_values(filter_llm_status)
            changed_on_filters = _normalize_filter_values(filter_changed_on)
            actor_filters = _normalize_filter_values(filter_actor)
            has_column_filters = any(
                (
                    title_filters,
                    git_filters,
                    llm_filters,
                    changed_on_filters,
                    actor_filters,
                )
            )
            needs_full_scan = (
                has_column_filters
                or bool(can_apply_profile_filter)
                or bool(can_apply_slug_filter)
            )

            if not needs_full_scan:
                try:
                    page_payload = (
                        await resource_service.get_dashboards_page_with_status(
                            env,
                            all_tasks,
                            page=page,
                            page_size=page_size,
                            search=search,
                            include_git_status=False,
                            require_slug=bool(can_apply_slug_filter),
                        )
                    )
                    paginated_dashboards = page_payload["dashboards"]
                    total = page_payload["total"]
                    total_pages = page_payload["total_pages"]
                except Exception as page_error:
                    logger.reason(
                        f"Page-based fetch failed; using compatibility fallback: {page_error}",
                        extra={"src": "get_dashboards"},
                    )
                    if can_apply_slug_filter:
                        dashboards = await resource_service.get_dashboards_with_status(
                            env,
                            all_tasks,
                            include_git_status=False,
                            require_slug=True,
                        )
                    else:
                        dashboards = await resource_service.get_dashboards_with_status(
                            env,
                            all_tasks,
                            include_git_status=False,
                        )

                    if search:
                        search_lower = search.lower()
                        dashboards = [
                            d
                            for d in dashboards
                            if search_lower in d.get("title", "").lower()
                            or search_lower in d.get("slug", "").lower()
                        ]

                    total = len(dashboards)
                    total_pages = (
                        (total + page_size - 1) // page_size if total > 0 else 1
                    )
                    start_idx = (page - 1) * page_size
                    end_idx = start_idx + page_size
                    paginated_dashboards = dashboards[start_idx:end_idx]
            else:
                if can_apply_slug_filter:
                    dashboards = await resource_service.get_dashboards_with_status(
                        env,
                        all_tasks,
                        include_git_status=bool(git_filters),
                        require_slug=True,
                    )
                else:
                    dashboards = await resource_service.get_dashboards_with_status(
                        env,
                        all_tasks,
                        include_git_status=bool(git_filters),
                    )

                if (
                    can_apply_profile_filter
                    and bound_username
                    and profile_service is not None
                ):
                    actor_aliases = _resolve_profile_actor_aliases(env, bound_username)
                    if not actor_aliases:
                        actor_aliases = [bound_username]
                    logger.reason(
                        "Applying profile actor filter",
                        extra={"src": "get_dashboards", "payload": {"env": env_id, "bound_username": bound_username, "actor_aliases": actor_aliases, "dashboards_before": len(dashboards)}},
                    )
                    filtered_dashboards: list[dict[str, Any]] = []
                    max_actor_samples = 15
                    for index, dashboard in enumerate(dashboards):
                        owners_value = dashboard.get("owners")
                        created_by_value = dashboard.get("created_by")
                        modified_by_value = dashboard.get("modified_by")
                        matches_actor = _matches_dashboard_actor_aliases(
                            profile_service=profile_service,
                            actor_aliases=actor_aliases,
                            owners=owners_value,
                            modified_by=modified_by_value,
                        )
                        if index < max_actor_samples:
                            logger.reflect(
                                "Profile actor filter sample",
                                extra={"src": "get_dashboards", "payload": {"env": env_id, "dashboard_id": dashboard.get('id'), "bound_username": bound_username, "actor_aliases": actor_aliases, "owners": owners_value, "created_by": created_by_value, "modified_by": modified_by_value, "matches": matches_actor}},
                            )
                        if matches_actor:
                            filtered_dashboards.append(dashboard)

                    logger.reflect(
                        "Profile actor filter summary",
                        extra={"src": "get_dashboards", "payload": {"env": env_id, "bound_username": bound_username, "dashboards_before": len(dashboards), "dashboards_after": len(filtered_dashboards)}},
                    )
                    dashboards = filtered_dashboards

                if can_apply_slug_filter:
                    dashboards = [
                        dashboard
                        for dashboard in dashboards
                        if str(dashboard.get("slug") or "").strip()
                    ]

                if search:
                    search_lower = search.lower()
                    dashboards = [
                        d
                        for d in dashboards
                        if search_lower in d.get("title", "").lower()
                        or search_lower in d.get("slug", "").lower()
                    ]

                def _matches_dashboard_filters(dashboard: dict[str, Any]) -> bool:
                    title_value = str(dashboard.get("title") or "").strip().lower()
                    if title_filters and title_value not in title_filters:
                        return False

                    if git_filters:
                        git_value = _dashboard_git_filter_value(dashboard)
                        if git_value not in git_filters:
                            return False

                    llm_value = (
                        str(
                            (
                                (dashboard.get("last_task") or {}).get(
                                    "validation_status"
                                )
                            )
                            or "UNKNOWN"
                        )
                        .strip()
                        .lower()
                    )
                    if llm_filters and llm_value not in llm_filters:
                        return False

                    changed_on_raw = (
                        str(dashboard.get("last_modified") or "").strip().lower()
                    )
                    changed_on_prefix = (
                        changed_on_raw[:10]
                        if len(changed_on_raw) >= 10
                        else changed_on_raw
                    )
                    if (
                        changed_on_filters
                        and changed_on_raw not in changed_on_filters
                        and changed_on_prefix not in changed_on_filters
                    ):
                        return False

                    owners = dashboard.get("owners") or []
                    if isinstance(owners, list):
                        actor_value = ", ".join(
                            str(item).strip() for item in owners if str(item).strip()
                        ).lower()
                    else:
                        actor_value = str(owners).strip().lower()
                    if not actor_value:
                        actor_value = "-"
                    if actor_filters and actor_value not in actor_filters:
                        return False
                    return True

                if has_column_filters:
                    dashboards = [
                        d for d in dashboards if _matches_dashboard_filters(d)
                    ]

                total = len(dashboards)
                total_pages = (total + page_size - 1) // page_size if total > 0 else 1
                start_idx = (page - 1) * page_size
                end_idx = start_idx + page_size
                paginated_dashboards = dashboards[start_idx:end_idx]

            logger.info(
                f"[get_dashboards][Coherence:OK] Returning {len(paginated_dashboards)} dashboards "
                f"(page {page}/{total_pages}, total: {total}, profile_filter_applied={effective_profile_filter.applied})"
            )

            response_dashboards = _project_dashboard_response_items(
                paginated_dashboards
            )

            return DashboardsResponse(
                dashboards=response_dashboards,
                total=total,
                page=page,
                page_size=page_size,
                total_pages=total_pages,
                effective_profile_filter=effective_profile_filter,
            )

        except HTTPException:
            raise
        except Exception as e:
            logger.error(
                f"[get_dashboards][Coherence:Failed] Failed to fetch dashboards: {e}"
            )
            raise HTTPException(
                status_code=503, detail=f"Failed to fetch dashboards: {e!s}"
            )


# #endregion get_dashboards
# #endregion DashboardListingRoutes
