# app/modules/tenancy/routes/api/admin_modules.py
"""
Admin API endpoints for Platform Module Management.

Provides module enablement/disablement for platforms:
- GET /modules - List all available modules
- GET /modules/platforms/{platform_id} - Get modules for a platform
- PUT /modules/platforms/{platform_id} - Update enabled modules
- POST /modules/platforms/{platform_id}/enable - Enable a module
- POST /modules/platforms/{platform_id}/disable - Disable a module

All endpoints require super admin access.
"""

import logging

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

from app.api.deps import get_current_super_admin, get_db
from app.modules.registry import MODULES, get_core_module_codes
from app.modules.service import module_service
from app.modules.tenancy.schemas.auth import UserContext
from app.modules.tenancy.services.platform_service import platform_service

logger = logging.getLogger(__name__)
router = APIRouter(prefix="/modules")


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


class ModuleResponse(BaseModel):
    """Module definition response."""

    code: str
    name: str
    description: str
    is_core: bool
    is_enabled: bool
    requires: list[str] = Field(default_factory=list)
    features: list[str] = Field(default_factory=list)
    menu_items_admin: list[str] = Field(default_factory=list)
    menu_items_store: list[str] = Field(default_factory=list)
    dependent_modules: list[str] = Field(default_factory=list)


class ModuleListResponse(BaseModel):
    """Response for module list."""

    modules: list[ModuleResponse]
    total: int
    enabled: int
    disabled: int


class PlatformModulesResponse(BaseModel):
    """Response for platform module configuration."""

    platform_id: int
    platform_code: str
    platform_name: str
    modules: list[ModuleResponse]
    total: int
    enabled: int
    disabled: int


class EnableModulesRequest(BaseModel):
    """Request to set enabled modules."""

    module_codes: list[str] = Field(..., description="List of module codes to enable")


class ToggleModuleRequest(BaseModel):
    """Request to enable/disable a single module."""

    module_code: str = Field(..., description="Module code to toggle")


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


def _get_dependent_modules(module_code: str) -> list[str]:
    """Get modules that depend on a given module."""
    dependents = []
    for code, module in MODULES.items():
        if module_code in module.requires:
            dependents.append(code)
    return dependents


def _build_module_response(
    code: str,
    is_enabled: bool,
) -> ModuleResponse:
    """Build ModuleResponse from module code."""
    from app.modules.enums import FrontendType  # API-007 - Enum for type safety

    module = MODULES.get(code)
    if not module:
        raise ValueError(f"Unknown module: {code}")

    return ModuleResponse(
        code=module.code,
        name=module.name,
        description=module.description,
        is_core=module.is_core,
        is_enabled=is_enabled,
        requires=module.requires,
        features=module.features,
        menu_items_admin=module.get_menu_items(FrontendType.ADMIN),
        menu_items_store=module.get_menu_items(FrontendType.STORE),
        dependent_modules=_get_dependent_modules(module.code),
    )


# =============================================================================
# API Endpoints
# =============================================================================


@router.get("", response_model=ModuleListResponse)
async def list_all_modules(
    current_user: UserContext = Depends(get_current_super_admin),
):
    """
    List all available modules.

    Returns all module definitions with their metadata.
    Super admin only.
    """
    modules = []
    for code in MODULES:
        # All modules shown as enabled in the global list
        modules.append(_build_module_response(code, is_enabled=True))

    # Sort: core first, then alphabetically
    modules.sort(key=lambda m: (not m.is_core, m.name))

    logger.info(f"[MODULES] Super admin {current_user.email} listed all modules")

    return ModuleListResponse(
        modules=modules,
        total=len(modules),
        enabled=len(modules),
        disabled=0,
    )


@router.get("/platforms/{platform_id}", response_model=PlatformModulesResponse)
async def get_platform_modules(
    platform_id: int = Path(..., description="Platform ID"),
    db: Session = Depends(get_db),
    current_user: UserContext = Depends(get_current_super_admin),
):
    """
    Get module configuration for a platform.

    Returns all modules with their enablement status for the platform.
    Super admin only.
    """
    # Verify platform exists
    platform = platform_service.get_platform_by_id(db, platform_id)

    # Get enabled module codes for this platform
    enabled_codes = module_service.get_enabled_module_codes(db, platform_id)

    modules = []
    for code in MODULES:
        is_enabled = code in enabled_codes
        modules.append(_build_module_response(code, is_enabled))

    # Sort: core first, then alphabetically
    modules.sort(key=lambda m: (not m.is_core, m.name))

    enabled_count = sum(1 for m in modules if m.is_enabled)

    logger.info(
        f"[MODULES] Super admin {current_user.email} fetched modules "
        f"for platform {platform.code} ({enabled_count}/{len(modules)} enabled)"
    )

    return PlatformModulesResponse(
        platform_id=platform.id,
        platform_code=platform.code,
        platform_name=platform.name,
        modules=modules,
        total=len(modules),
        enabled=enabled_count,
        disabled=len(modules) - enabled_count,
    )


@router.put("/platforms/{platform_id}", response_model=PlatformModulesResponse)
async def update_platform_modules(
    update_data: EnableModulesRequest,
    platform_id: int = Path(..., description="Platform ID"),
    db: Session = Depends(get_db),
    current_user: UserContext = Depends(get_current_super_admin),
):
    """
    Update enabled modules for a platform.

    Sets the list of enabled modules. Core modules are automatically included.
    Dependencies are automatically resolved.
    Super admin only.
    """
    # Verify platform exists
    platform = platform_service.get_platform_by_id(db, platform_id)

    # Update enabled modules
    module_service.set_enabled_modules(db, platform_id, update_data.module_codes)
    db.commit()

    # Get updated module list
    enabled_codes = module_service.get_enabled_module_codes(db, platform_id)

    modules = []
    for code in MODULES:
        is_enabled = code in enabled_codes
        modules.append(_build_module_response(code, is_enabled))

    modules.sort(key=lambda m: (not m.is_core, m.name))
    enabled_count = sum(1 for m in modules if m.is_enabled)

    logger.info(
        f"[MODULES] Super admin {current_user.email} updated modules "
        f"for platform {platform.code}: {sorted(update_data.module_codes)}"
    )

    return PlatformModulesResponse(
        platform_id=platform.id,
        platform_code=platform.code,
        platform_name=platform.name,
        modules=modules,
        total=len(modules),
        enabled=enabled_count,
        disabled=len(modules) - enabled_count,
    )


@router.post("/platforms/{platform_id}/enable")
async def enable_module(
    request: ToggleModuleRequest,
    platform_id: int = Path(..., description="Platform ID"),
    db: Session = Depends(get_db),
    current_user: UserContext = Depends(get_current_super_admin),
):
    """
    Enable a single module for a platform.

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

    # Validate module code
    if request.module_code not in MODULES:
        from app.modules.tenancy.exceptions import BadRequestException

        raise BadRequestException(f"Unknown module: {request.module_code}")

    # Enable module
    success = module_service.enable_module(db, platform_id, request.module_code)
    if success:
        db.commit()

    # Check what dependencies were also enabled
    module = MODULES[request.module_code]
    enabled_deps = module.requires if module.requires else []

    logger.info(
        f"[MODULES] Super admin {current_user.email} enabled module "
        f"'{request.module_code}' for platform {platform.code}"
    )

    return {
        "success": success,
        "message": f"Module '{request.module_code}' enabled",
        "also_enabled": enabled_deps,
    }


@router.post("/platforms/{platform_id}/disable")
async def disable_module(
    request: ToggleModuleRequest,
    platform_id: int = Path(..., description="Platform ID"),
    db: Session = Depends(get_db),
    current_user: UserContext = Depends(get_current_super_admin),
):
    """
    Disable a single module for a platform.

    Core modules cannot be disabled.
    Also disables modules that depend on this one.
    Super admin only.
    """
    # Verify platform exists
    platform = platform_service.get_platform_by_id(db, platform_id)

    # Validate module code
    if request.module_code not in MODULES:
        from app.modules.tenancy.exceptions import BadRequestException

        raise BadRequestException(f"Unknown module: {request.module_code}")

    # Check if core module
    if request.module_code in get_core_module_codes():
        from app.modules.tenancy.exceptions import BadRequestException

        raise BadRequestException(f"Cannot disable core module: {request.module_code}")

    # Get dependent modules before disabling
    dependents = _get_dependent_modules(request.module_code)

    # Disable module
    success = module_service.disable_module(db, platform_id, request.module_code)
    if success:
        db.commit()

    logger.info(
        f"[MODULES] Super admin {current_user.email} disabled module "
        f"'{request.module_code}' for platform {platform.code}"
    )

    return {
        "success": success,
        "message": f"Module '{request.module_code}' disabled",
        "also_disabled": dependents if dependents else [],
    }


@router.post("/platforms/{platform_id}/enable-all")
async def enable_all_modules(
    platform_id: int = Path(..., description="Platform ID"),
    db: Session = Depends(get_db),
    current_user: UserContext = Depends(get_current_super_admin),
):
    """
    Enable all modules for a platform.

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

    # Enable all modules
    all_codes = list(MODULES.keys())
    module_service.set_enabled_modules(db, platform_id, all_codes)
    db.commit()

    logger.info(
        f"[MODULES] Super admin {current_user.email} enabled all modules "
        f"for platform {platform.code}"
    )

    return {
        "success": True,
        "message": "All modules enabled",
        "enabled_count": len(all_codes),
    }


@router.post("/platforms/{platform_id}/disable-optional")
async def disable_optional_modules(
    platform_id: int = Path(..., description="Platform ID"),
    db: Session = Depends(get_db),
    current_user: UserContext = Depends(get_current_super_admin),
):
    """
    Disable all optional modules for a platform, keeping only core modules.

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

    # Enable only core modules
    core_codes = list(get_core_module_codes())
    module_service.set_enabled_modules(db, platform_id, core_codes)
    db.commit()

    logger.info(
        f"[MODULES] Super admin {current_user.email} disabled optional modules "
        f"for platform {platform.code} (kept {len(core_codes)} core modules)"
    )

    return {
        "success": True,
        "message": "Optional modules disabled, core modules kept",
        "core_modules": core_codes,
    }
