# app/modules/contracts/widgets.py
"""
Dashboard widget provider protocol for cross-module widget aggregation.

This module defines the protocol that modules implement to expose dashboard widgets.
The core module's WidgetAggregator discovers and aggregates all providers.

Benefits:
- Each module owns its widgets (no cross-module coupling)
- Dashboards always work (aggregator is in core)
- Optional modules are truly optional (can be removed without breaking app)
- Easy to add new widgets (just implement protocol in your module)

Widget Types:
- ListWidget: Displays a list of items (recent imports, recent stores, etc.)
- BreakdownWidget: Displays grouped statistics (by category, by status, etc.)

Usage:
    # 1. Implement the protocol in your module
    class OrderWidgetProvider:
        @property
        def widgets_category(self) -> str:
            return "orders"

        def get_store_widgets(self, db, store_id, context=None) -> list[DashboardWidget]:
            return [
                DashboardWidget(
                    key="orders.recent",
                    widget_type="list",
                    title="Recent Orders",
                    category="orders",
                    data=ListWidget(items=[...]),
                )
            ]

    # 2. Register in module definition
    def _get_widget_provider():
        from app.modules.orders.services.order_widgets import order_widget_provider
        return order_widget_provider

    orders_module = ModuleDefinition(
        code="orders",
        widget_provider=_get_widget_provider,
        # ...
    )

    # 3. Widgets appear automatically in dashboards when module is enabled
"""

from dataclasses import dataclass, field
from datetime import datetime
from typing import TYPE_CHECKING, Any, Protocol, runtime_checkable

if TYPE_CHECKING:
    from sqlalchemy.orm import Session


# =============================================================================
# Context
# =============================================================================


@dataclass
class WidgetContext:
    """
    Context for widget data collection.

    Provides filtering and scoping options for widget providers.

    Attributes:
        date_from: Start of date range filter
        date_to: End of date range filter
        limit: Maximum number of items for list widgets
        include_details: Whether to include extra details (may be expensive)
    """

    date_from: datetime | None = None
    date_to: datetime | None = None
    limit: int = 5
    include_details: bool = False


# =============================================================================
# Storefront Dashboard Card
# =============================================================================


@dataclass
class StorefrontDashboardCard:
    """
    A card contributed by a module to the storefront customer dashboard.

    Modules implement get_storefront_dashboard_cards() to provide these.
    The dashboard template renders them without knowing which module provided them.

    Attributes:
        key: Unique identifier (e.g. "orders.summary", "loyalty.points")
        icon: Lucide icon name (e.g. "shopping-bag", "gift")
        title: Card title (i18n key or plain text)
        subtitle: Card subtitle / description
        route: Link destination relative to base_url (e.g. "account/orders")
        value: Primary display value (e.g. order count, points balance)
        value_label: Label for the value (e.g. "Total Orders", "Points Balance")
        order: Sort order (lower = shown first)
        template: Optional custom template path for complex rendering
        extra_data: Additional data for custom template rendering
    """

    key: str
    icon: str
    title: str
    subtitle: str
    route: str
    value: str | int | None = None
    value_label: str | None = None
    order: int = 100
    template: str | None = None
    extra_data: dict[str, Any] = field(default_factory=dict)


# =============================================================================
# Widget Item Types
# =============================================================================


@dataclass
class WidgetListItem:
    """
    Single item in a list widget (recent stores, orders, imports).

    Attributes:
        id: Unique identifier for the item
        title: Primary display text
        subtitle: Secondary display text (optional)
        status: Status indicator ("success", "warning", "error", "neutral")
        timestamp: When the item was created/updated
        url: Link to item details (optional)
        metadata: Additional data for rendering
    """

    id: int | str
    title: str
    subtitle: str | None = None
    status: str | None = None  # "success", "warning", "error", "neutral"
    timestamp: datetime | None = None
    url: str | None = None
    metadata: dict[str, Any] = field(default_factory=dict)


@dataclass
class WidgetBreakdownItem:
    """
    Single row in a breakdown widget (stats by marketplace, category).

    Attributes:
        label: Display label for the row
        value: Primary numeric value
        secondary_value: Optional secondary value (e.g., comparison)
        percentage: Percentage representation
        icon: Lucide icon name (optional)
    """

    label: str
    value: int | float
    secondary_value: int | float | None = None
    percentage: float | None = None
    icon: str | None = None


# =============================================================================
# Widget Containers
# =============================================================================


@dataclass
class ListWidget:
    """
    Widget containing a list of items.

    Used for: recent imports, recent stores, recent orders, etc.

    Attributes:
        items: List of WidgetListItem objects
        total_count: Total number of items (for "X more" display)
        view_all_url: Link to view all items
    """

    items: list[WidgetListItem]
    total_count: int | None = None
    view_all_url: str | None = None


@dataclass
class BreakdownWidget:
    """
    Widget containing grouped statistics.

    Used for: status breakdown, category distribution, etc.

    Attributes:
        items: List of WidgetBreakdownItem objects
        total: Sum of all values
    """

    items: list[WidgetBreakdownItem]
    total: int | float | None = None


# Type alias for widget data
WidgetData = ListWidget | BreakdownWidget


# =============================================================================
# Main Widget Envelope
# =============================================================================


@dataclass
class DashboardWidget:
    """
    Standard widget envelope with metadata.

    This is the main unit of data returned by widget providers.
    It contains both the widget data and metadata for display.

    Attributes:
        key: Unique identifier for this widget (e.g., "marketplace.recent_imports")
             Format: "{category}.{widget_name}" for consistency
        widget_type: Type of widget ("list" or "breakdown")
        title: Human-readable title for display
        category: Grouping category (should match widgets_category of provider)
        data: The actual widget data (ListWidget or BreakdownWidget)
        icon: Optional Lucide icon name for UI display
        description: Optional longer description
        order: Display order (lower = higher priority)

    Example:
        DashboardWidget(
            key="marketplace.recent_imports",
            widget_type="list",
            title="Recent Imports",
            category="marketplace",
            data=ListWidget(
                items=[
                    WidgetListItem(id=1, title="Import #1", status="success")
                ],
            ),
            icon="download",
            order=10,
        )
    """

    key: str
    widget_type: str  # "list" or "breakdown"
    title: str
    category: str
    data: WidgetData
    icon: str | None = None
    description: str | None = None
    order: int = 100


# =============================================================================
# Protocol Interface
# =============================================================================


@runtime_checkable
class DashboardWidgetProviderProtocol(Protocol):
    """
    Protocol for modules that provide dashboard widgets.

    Each module implements this to expose its own widgets.
    The core module's WidgetAggregator discovers and aggregates all providers.

    Implementation Notes:
    - Providers should be stateless (all data via db session)
    - Return empty list if no widgets available (don't raise)
    - Use consistent key format: "{category}.{widget_name}"
    - Include icon hints for UI rendering
    - Be mindful of query performance (use efficient queries)
    - Translations are handled by the module itself

    Example Implementation:
        class MarketplaceWidgetProvider:
            @property
            def widgets_category(self) -> str:
                return "marketplace"

            def get_store_widgets(
                self, db: Session, store_id: int, context: WidgetContext | None = None
            ) -> list[DashboardWidget]:
                from app.modules.marketplace.models import MarketplaceImportJob
                limit = context.limit if context else 5
                jobs = db.query(MarketplaceImportJob).filter(...).limit(limit).all()
                return [
                    DashboardWidget(
                        key="marketplace.recent_imports",
                        widget_type="list",
                        title="Recent Imports",
                        category="marketplace",
                        data=ListWidget(items=[...]),
                        icon="download"
                    )
                ]

            def get_platform_widgets(
                self, db: Session, platform_id: int, context: WidgetContext | None = None
            ) -> list[DashboardWidget]:
                # Aggregate across all stores in platform
                ...
    """

    @property
    def widgets_category(self) -> str:
        """
        Category name for this provider's widgets.

        Should be a short, lowercase identifier matching the module's domain.
        Examples: "orders", "inventory", "customers", "marketplace"

        Returns:
            Category string used for grouping widgets
        """
        ...

    def get_store_widgets(
        self,
        db: "Session",
        store_id: int,
        context: WidgetContext | None = None,
    ) -> list[DashboardWidget]:
        """
        Get widgets for a specific store dashboard.

        Called by the store dashboard to display store-scoped widgets.
        Should only include data belonging to the specified store.

        Args:
            db: Database session for queries
            store_id: ID of the store to get widgets for
            context: Optional filtering/scoping context

        Returns:
            List of DashboardWidget objects for this store
        """
        ...

    def get_platform_widgets(
        self,
        db: "Session",
        platform_id: int,
        context: WidgetContext | None = None,
    ) -> list[DashboardWidget]:
        """
        Get widgets aggregated for a platform.

        Called by the admin dashboard to display platform-wide widgets.
        Should aggregate data across all stores in the platform.

        Args:
            db: Database session for queries
            platform_id: ID of the platform to get widgets for
            context: Optional filtering/scoping context

        Returns:
            List of DashboardWidget objects aggregated for the platform
        """
        ...

    def get_storefront_dashboard_cards(
        self,
        db: "Session",
        store_id: int,
        customer_id: int,
        context: WidgetContext | None = None,
    ) -> list["StorefrontDashboardCard"]:
        """
        Get cards for the storefront customer dashboard.

        Called by the customer account dashboard. Each module contributes
        its own cards (e.g. orders summary, loyalty points).

        Args:
            db: Database session for queries
            store_id: ID of the store
            customer_id: ID of the logged-in customer
            context: Optional filtering/scoping context

        Returns:
            List of StorefrontDashboardCard objects
        """
        ...


__all__ = [
    # Context
    "WidgetContext",
    # Item types
    "WidgetListItem",
    "WidgetBreakdownItem",
    # Containers
    "ListWidget",
    "BreakdownWidget",
    "WidgetData",
    # Main envelope
    "DashboardWidget",
    # Storefront
    "StorefrontDashboardCard",
    # Protocol
    "DashboardWidgetProviderProtocol",
]
