# app/modules/core/routes/api/admin_menu_config.py
"""
Admin API endpoints for Platform Menu Configuration.

Provides menu visibility configuration for admin and store frontends:
- GET /menu-config/platforms/{platform_id} - Get menu config for a platform
- PUT /menu-config/platforms/{platform_id} - Update menu visibility for a platform
- POST /menu-config/platforms/{platform_id}/reset - Reset to defaults
- GET /menu/admin - Get rendered admin menu for current user
- GET /menu/store - Get rendered store menu for current platform

All configuration endpoints require super admin access.
Menu rendering endpoints require authenticated admin/store access.
"""

import logging
from typing import Any

from fastapi import APIRouter, Depends, Path, Query, Request
from pydantic import BaseModel, Field
from sqlalchemy.orm import Session

from app.api.deps import (
    get_current_admin_from_cookie_or_header,
    get_current_super_admin,
    get_db,
)
from app.modules.core.services.menu_service import MenuItemConfig, menu_service
from app.modules.enums import FrontendType  # API-007 - Enum for type safety
from app.modules.tenancy.schemas.auth import UserContext
from app.modules.tenancy.services.platform_service import platform_service
from app.utils.i18n import DEFAULT_LANGUAGE, translate

logger = logging.getLogger(__name__)
router = APIRouter(prefix="/menu-config")


# =============================================================================
# Pydantic Schemas
# =============================================================================


class MenuItemResponse(BaseModel):
    """Menu item configuration response."""

    id: str
    label: str
    icon: str
    url: str
    section_id: str
    section_label: str | None = None
    is_visible: bool = True
    is_mandatory: bool = False
    is_super_admin_only: bool = False


class MenuConfigResponse(BaseModel):
    """Menu configuration response for a platform or user."""

    frontend_type: str
    platform_id: int | None = None
    user_id: int | None = None
    items: list[MenuItemResponse]
    total_items: int
    visible_items: int
    hidden_items: int


class MenuVisibilityUpdateRequest(BaseModel):
    """Request to update menu item visibility."""

    menu_item_id: str = Field(..., description="Menu item ID to update")
    is_visible: bool = Field(..., description="Whether the item should be visible")


class BulkMenuVisibilityUpdateRequest(BaseModel):
    """Request to update multiple menu items at once."""

    visibility: dict[str, bool] = Field(
        ...,
        description="Map of menu_item_id to is_visible",
        examples=[{"inventory": False, "orders": True}],
    )


class MenuSectionResponse(BaseModel):
    """Menu section for rendering."""

    id: str
    label: str | None = None
    items: list[dict[str, Any]]


class RenderedMenuResponse(BaseModel):
    """Rendered menu for frontend."""

    frontend_type: str
    sections: list[MenuSectionResponse]


class MenuActionResponse(BaseModel):
    """Response for menu action operations (reset, show-all, etc.)."""

    success: bool
    message: str


# =============================================================================
# Helper Functions
# =============================================================================


def _translate_label(label_key: str | None, language: str) -> str | None:
    """
    Translate a label key to the user's language.

    Falls back to a readable version of the key if translation not found.
    """
    if not label_key:
        return None

    translated = translate(label_key, language=language)

    # If translation returned the key itself, it wasn't found
    # Create a readable fallback from the last part of the key
    if translated == label_key:
        parts = label_key.split(".")
        last_part = parts[-1]
        # Convert snake_case to Title Case
        return last_part.replace("_", " ").title()

    return translated


def _build_menu_item_response(
    item: MenuItemConfig, language: str = DEFAULT_LANGUAGE
) -> MenuItemResponse:
    """Convert MenuItemConfig to API response with translated labels."""
    return MenuItemResponse(
        id=item.id,
        label=_translate_label(item.label, language),
        icon=item.icon,
        url=item.url,
        section_id=item.section_id,
        section_label=_translate_label(item.section_label, language),
        is_visible=item.is_visible,
        is_mandatory=item.is_mandatory,
        is_super_admin_only=item.is_super_admin_only,
    )


def _build_menu_config_response(
    items: list[MenuItemConfig],
    frontend_type: FrontendType,
    language: str = DEFAULT_LANGUAGE,
    platform_id: int | None = None,
    user_id: int | None = None,
) -> MenuConfigResponse:
    """Build menu configuration response with translated labels."""
    item_responses = [_build_menu_item_response(item, language) for item in items]
    visible_count = sum(1 for item in items if item.is_visible)

    return MenuConfigResponse(
        frontend_type=frontend_type.value,
        platform_id=platform_id,
        user_id=user_id,
        items=item_responses,
        total_items=len(items),
        visible_items=visible_count,
        hidden_items=len(items) - visible_count,
    )


# =============================================================================
# Platform Menu Configuration (Super Admin Only)
# =============================================================================


@router.get("/platforms/{platform_id}", response_model=MenuConfigResponse)
async def get_platform_menu_config(
    request: Request,
    platform_id: int = Path(..., description="Platform ID"),
    frontend_type: FrontendType = Query(
        FrontendType.ADMIN, description="Frontend type (admin or store)"
    ),
    db: Session = Depends(get_db),
    current_user: UserContext = Depends(get_current_super_admin),
):
    """
    Get menu configuration for a platform.

    Returns all menu items with their visibility status for the specified
    platform and frontend type. Super admin only.
    """
    # Verify platform exists
    platform = platform_service.get_platform_by_id(db, platform_id)

    items = menu_service.get_platform_menu_config(db, frontend_type, platform_id)

    logger.info(
        f"[MENU_CONFIG] Super admin {current_user.email} fetched menu config "
        f"for platform {platform.code} ({frontend_type.value})"
    )

    # Use user's preferred language, falling back to middleware-resolved language
    language = current_user.preferred_language or getattr(
        request.state, "language", "en"
    )

    return _build_menu_config_response(
        items, frontend_type, language=language, platform_id=platform_id
    )


@router.put("/platforms/{platform_id}")
async def update_platform_menu_visibility(
    update_data: MenuVisibilityUpdateRequest,
    platform_id: int = Path(..., description="Platform ID"),
    frontend_type: FrontendType = Query(
        FrontendType.ADMIN, description="Frontend type (admin or store)"
    ),
    db: Session = Depends(get_db),
    current_user: UserContext = Depends(get_current_super_admin),
):
    """
    Update visibility for a single menu item for a platform.

    Super admin only. Cannot hide mandatory items.
    """
    # Verify platform exists
    platform = platform_service.get_platform_by_id(db, platform_id)

    menu_service.update_menu_visibility(
        db=db,
        frontend_type=frontend_type,
        menu_item_id=update_data.menu_item_id,
        is_visible=update_data.is_visible,
        platform_id=platform_id,
    )
    db.commit()

    logger.info(
        f"[MENU_CONFIG] Super admin {current_user.email} updated menu visibility: "
        f"{update_data.menu_item_id}={update_data.is_visible} "
        f"for platform {platform.code} ({frontend_type.value})"
    )

    return {"success": True, "message": "Menu visibility updated"}


@router.put("/platforms/{platform_id}/bulk")
async def bulk_update_platform_menu_visibility(
    update_data: BulkMenuVisibilityUpdateRequest,
    platform_id: int = Path(..., description="Platform ID"),
    frontend_type: FrontendType = Query(
        FrontendType.ADMIN, description="Frontend type (admin or store)"
    ),
    db: Session = Depends(get_db),
    current_user: UserContext = Depends(get_current_super_admin),
):
    """
    Update visibility for multiple menu items at once.

    Super admin only. Skips mandatory items silently.
    """
    # Verify platform exists
    platform = platform_service.get_platform_by_id(db, platform_id)

    menu_service.bulk_update_menu_visibility(
        db=db,
        frontend_type=frontend_type,
        visibility_map=update_data.visibility,
        platform_id=platform_id,
    )
    db.commit()

    logger.info(
        f"[MENU_CONFIG] Super admin {current_user.email} bulk updated menu visibility: "
        f"{len(update_data.visibility)} items for platform {platform.code} ({frontend_type.value})"
    )

    return {
        "success": True,
        "message": f"Updated {len(update_data.visibility)} menu items",
    }


@router.post("/platforms/{platform_id}/reset")
async def reset_platform_menu_config(
    platform_id: int = Path(..., description="Platform ID"),
    frontend_type: FrontendType = Query(
        FrontendType.ADMIN, description="Frontend type (admin or store)"
    ),
    db: Session = Depends(get_db),
    current_user: UserContext = Depends(get_current_super_admin),
):
    """
    Reset menu configuration for a platform to defaults.

    Removes all visibility overrides, making all items visible.
    Super admin only.
    """
    # Verify platform exists
    platform = platform_service.get_platform_by_id(db, platform_id)

    menu_service.reset_platform_menu_config(db, frontend_type, platform_id)
    db.commit()

    logger.info(
        f"[MENU_CONFIG] Super admin {current_user.email} reset menu config "
        f"for platform {platform.code} ({frontend_type.value})"
    )

    return {"success": True, "message": "Menu configuration reset to defaults"}


@router.post("/platforms/{platform_id}/show-all")
async def show_all_platform_menu_config(
    platform_id: int = Path(..., description="Platform ID"),
    frontend_type: FrontendType = Query(
        FrontendType.ADMIN, description="Frontend type (admin or store)"
    ),
    db: Session = Depends(get_db),
    current_user: UserContext = Depends(get_current_super_admin),
):
    """
    Show all menu items for a platform.

    Super admin only.
    """
    # Verify platform exists
    platform = platform_service.get_platform_by_id(db, platform_id)

    menu_service.show_all_platform_menu_config(db, frontend_type, platform_id)
    db.commit()

    logger.info(
        f"[MENU_CONFIG] Super admin {current_user.email} enabled all menu items "
        f"for platform {platform.code} ({frontend_type.value})"
    )

    return {"success": True, "message": "All menu items are now visible"}


# =============================================================================
# Menu Rendering (For Sidebar)
# =============================================================================


@router.get("/render/admin", response_model=RenderedMenuResponse)
async def get_rendered_admin_menu(
    request: Request,
    db: Session = Depends(get_db),
    current_user: UserContext = Depends(get_current_admin_from_cookie_or_header),
):
    """
    Get the rendered admin menu for the current user.

    Returns the filtered menu structure based on:
    - Super admins: user-level config
    - Platform admins: platform-level config

    Used by the frontend to render the sidebar.
    """
    if current_user.is_super_admin:
        # Super admin: use platform config if platform selected, else global (all modules)
        platform_id = current_user.token_platform_id
        menu = menu_service.get_menu_for_rendering(
            db=db,
            frontend_type=FrontendType.ADMIN,
            platform_id=platform_id,
            is_super_admin=True,
        )
    else:
        # Platform admin: use platform-level config
        # Get the selected platform from the JWT token
        platform_id = current_user.token_platform_id

        # Fallback to first accessible platform if no platform in token (shouldn't happen)
        if platform_id is None and current_user.accessible_platform_ids:
            platform_id = current_user.accessible_platform_ids[0]
            logger.warning(
                f"[MENU_CONFIG] No platform_id in token for {current_user.email}, "
                f"falling back to first accessible platform: {platform_id}"
            )

        menu = menu_service.get_menu_for_rendering(
            db=db,
            frontend_type=FrontendType.ADMIN,
            platform_id=platform_id,
            is_super_admin=False,
        )

    # Use user's preferred language, falling back to middleware-resolved language
    language = current_user.preferred_language or getattr(
        request.state, "language", "en"
    )

    # Translate section and item labels
    # menu is a list of DiscoveredMenuSection dataclasses
    sections = []
    for section in menu:
        # Translate item labels
        translated_items = []
        for item in section.items:
            translated_items.append(
                {
                    "id": item.id,
                    "label": _translate_label(item.label_key, language),
                    "icon": item.icon,
                    "url": item.route,
                    "super_admin_only": item.is_super_admin_only,
                }
            )

        sections.append(
            MenuSectionResponse(
                id=section.id,
                label=_translate_label(section.label_key, language),
                items=translated_items,
            )
        )

    return RenderedMenuResponse(
        frontend_type=FrontendType.ADMIN.value,
        sections=sections,
    )
