# app/modules/core/models/admin_menu_config.py
"""
Menu visibility configuration for admin and store frontends.

Supports two frontend types:
- 'admin': Admin panel menus (for super admins and platform admins)
- 'store': Store dashboard menus (configured per platform)

Supports two scopes:
- Platform-level: Menu config for a platform (platform_id is set)
  → For admin frontend: applies to platform admins
  → For store frontend: applies to all stores on that platform
- User-level: Menu config for a specific super admin (user_id is set)
  → Only for admin frontend (super admins configuring their own menu)

Design:
- Opt-out model: All items visible by default, store hidden items
- Mandatory items: Some items cannot be hidden (defined per frontend type)
- Only stores non-default state (is_visible=False) to keep table small
"""

from sqlalchemy import (
    Boolean,
    CheckConstraint,
    Column,
    Enum,
    ForeignKey,
    Index,
    Integer,
    String,
    UniqueConstraint,
)
from sqlalchemy.orm import relationship

from app.core.database import Base

# Import FrontendType and MANDATORY_MENU_ITEMS from the central location
from app.modules.enums import MANDATORY_MENU_ITEMS, FrontendType
from models.database.base import TimestampMixin


class AdminMenuConfig(Base, TimestampMixin):
    """
    Menu visibility configuration for admin and store frontends.

    Supports two frontend types:
    - 'admin': Admin panel menus
    - 'store': Store dashboard menus

    Supports two scopes:
    - Platform scope: platform_id is set
      → Admin: applies to platform admins of that platform
      → Store: applies to all stores on that platform
    - User scope: user_id is set (admin frontend only)
      → Applies to a specific super admin user

    Resolution order for admin frontend:
    - Platform admins: Check platform config → fall back to default
    - Super admins: Check user config → fall back to default

    Resolution order for store frontend:
    - Check platform config → fall back to default

    Examples:
    - Platform "OMS" wants to hide "inventory" from admin panel
      → frontend_type='admin', platform_id=1, menu_item_id="inventory", is_visible=False

    - Platform "OMS" wants to hide "letzshop" from store dashboard
      → frontend_type='store', platform_id=1, menu_item_id="letzshop", is_visible=False

    - Super admin "john" wants to hide "code-quality" from their admin panel
      → frontend_type='admin', user_id=5, menu_item_id="code-quality", is_visible=False
    """

    __tablename__ = "admin_menu_configs"

    id = Column(Integer, primary_key=True, index=True)

    # ========================================================================
    # Frontend Type
    # ========================================================================

    frontend_type = Column(
        Enum(FrontendType, values_callable=lambda obj: [e.value for e in obj]),
        nullable=False,
        default=FrontendType.ADMIN,
        index=True,
        comment="Which frontend this config applies to (admin or store)",
    )

    # ========================================================================
    # Scope: Platform scope OR User scope (for admin frontend only)
    # ========================================================================

    platform_id = Column(
        Integer,
        ForeignKey("platforms.id", ondelete="CASCADE"),
        nullable=True,
        index=True,
        comment="Platform scope - applies to users/stores of this platform",
    )

    # DEPRECATED: user_id scoping is no longer used. Super admins now use platform
    # selection instead of personal menu config. DB migration to drop this column
    # is a separate task.
    user_id = Column(
        Integer,
        ForeignKey("users.id", ondelete="CASCADE"),
        nullable=True,
        index=True,
        comment="DEPRECATED - User scope no longer used. Kept for migration compatibility.",
    )

    # ========================================================================
    # Menu Item Configuration
    # ========================================================================

    menu_item_id = Column(
        String(50),
        nullable=False,
        index=True,
        comment="Menu item identifier from registry (e.g., 'products', 'inventory')",
    )

    is_visible = Column(
        Boolean,
        default=True,
        nullable=False,
        comment="Whether this menu item is visible (False = hidden)",
    )

    # ========================================================================
    # Relationships
    # ========================================================================

    platform = relationship(
        "Platform",
        back_populates="menu_configs",
    )

    user = relationship(
        "User",
        back_populates="menu_configs",
    )

    # ========================================================================
    # Constraints
    # ========================================================================

    __table_args__ = (
        # Unique constraint: one config per frontend+platform+menu_item
        UniqueConstraint(
            "frontend_type",
            "platform_id",
            "menu_item_id",
            name="uq_frontend_platform_menu_config",
        ),
        # Unique constraint: one config per frontend+user+menu_item
        UniqueConstraint(
            "frontend_type",
            "user_id",
            "menu_item_id",
            name="uq_frontend_user_menu_config",
        ),
        # Check: exactly one scope must be set (platform_id XOR user_id)
        CheckConstraint(
            "(platform_id IS NOT NULL AND user_id IS NULL) OR "
            "(platform_id IS NULL AND user_id IS NOT NULL)",
            name="ck_admin_menu_config_scope",
        ),
        # Check: user_id scope only allowed for admin frontend
        CheckConstraint(
            "(user_id IS NULL) OR (frontend_type = 'admin')",
            name="ck_user_scope_admin_only",
        ),
        # Performance indexes
        Index(
            "idx_admin_menu_config_frontend_platform",
            "frontend_type",
            "platform_id",
        ),
        Index(
            "idx_admin_menu_config_frontend_user",
            "frontend_type",
            "user_id",
        ),
        Index(
            "idx_admin_menu_config_platform_visible",
            "platform_id",
            "is_visible",
        ),
        Index(
            "idx_admin_menu_config_user_visible",
            "user_id",
            "is_visible",
        ),
    )

    # ========================================================================
    # Properties
    # ========================================================================

    @property
    def scope_type(self) -> str:
        """Get the scope type for this config."""
        if self.platform_id:
            return "platform"
        return "user"

    @property
    def scope_id(self) -> int:
        """Get the scope ID (platform_id or user_id)."""
        return self.platform_id or self.user_id

    def __repr__(self) -> str:
        scope = f"platform_id={self.platform_id}" if self.platform_id else f"user_id={self.user_id}"
        return (
            f"<AdminMenuConfig("
            f"frontend_type='{self.frontend_type.value}', "
            f"{scope}, "
            f"menu_item_id='{self.menu_item_id}', "
            f"is_visible={self.is_visible})>"
        )


__all__ = ["AdminMenuConfig", "FrontendType", "MANDATORY_MENU_ITEMS"]
