# app/modules/inventory/services/inventory_metrics.py
"""
Metrics provider for the inventory module.

Provides metrics for:
- Inventory quantities
- Stock levels
- Low stock alerts
"""

import logging
from typing import TYPE_CHECKING

from sqlalchemy import func
from sqlalchemy.orm import Session

from app.modules.contracts.metrics import (
    MetricsContext,
    MetricValue,
)

if TYPE_CHECKING:
    pass

logger = logging.getLogger(__name__)


class InventoryMetricsProvider:
    """
    Metrics provider for inventory module.

    Provides stock and inventory metrics for store and platform dashboards.
    """

    @property
    def metrics_category(self) -> str:
        return "inventory"

    def get_store_metrics(
        self,
        db: Session,
        store_id: int,
        context: MetricsContext | None = None,
    ) -> list[MetricValue]:
        """
        Get inventory metrics for a specific store.

        Provides:
        - Total inventory quantity
        - Reserved quantity
        - Available quantity
        - Inventory locations
        - Low stock items
        """
        from app.modules.inventory.models import Inventory

        try:
            # Total inventory
            total_quantity = (
                db.query(func.sum(Inventory.quantity))
                .filter(Inventory.store_id == store_id)
                .scalar()
                or 0
            )

            # Reserved inventory
            reserved_quantity = (
                db.query(func.sum(Inventory.reserved_quantity))
                .filter(Inventory.store_id == store_id)
                .scalar()
                or 0
            )

            # Available inventory
            available_quantity = int(total_quantity) - int(reserved_quantity)

            # Inventory entries (SKU/location combinations)
            inventory_entries = (
                db.query(Inventory).filter(Inventory.store_id == store_id).count()
            )

            # Unique locations
            unique_locations = (
                db.query(func.count(func.distinct(Inventory.bin_location)))
                .filter(Inventory.store_id == store_id)
                .scalar()
                or 0
            )

            # Low stock items (quantity < 10 and > 0)
            low_stock_items = (
                db.query(Inventory)
                .filter(
                    Inventory.store_id == store_id,
                    Inventory.quantity > 0,
                    Inventory.quantity < 10,
                )
                .count()
            )

            # Out of stock items (quantity = 0)
            out_of_stock_items = (
                db.query(Inventory)
                .filter(Inventory.store_id == store_id, Inventory.quantity == 0)
                .count()
            )

            return [
                MetricValue(
                    key="inventory.total_quantity",
                    value=int(total_quantity),
                    label="Total Stock",
                    category="inventory",
                    icon="package",
                    unit="items",
                    description="Total inventory quantity",
                ),
                MetricValue(
                    key="inventory.reserved_quantity",
                    value=int(reserved_quantity),
                    label="Reserved",
                    category="inventory",
                    icon="lock",
                    unit="items",
                    description="Inventory reserved for orders",
                ),
                MetricValue(
                    key="inventory.available_quantity",
                    value=available_quantity,
                    label="Available",
                    category="inventory",
                    icon="check",
                    unit="items",
                    description="Inventory available for sale",
                ),
                MetricValue(
                    key="inventory.entries",
                    value=inventory_entries,
                    label="SKU/Location Entries",
                    category="inventory",
                    icon="list",
                    description="Total inventory entries",
                ),
                MetricValue(
                    key="inventory.locations",
                    value=unique_locations,
                    label="Locations",
                    category="inventory",
                    icon="map-pin",
                    description="Unique storage locations",
                ),
                MetricValue(
                    key="inventory.low_stock",
                    value=low_stock_items,
                    label="Low Stock",
                    category="inventory",
                    icon="alert-triangle",
                    description="Items with quantity < 10",
                ),
                MetricValue(
                    key="inventory.out_of_stock",
                    value=out_of_stock_items,
                    label="Out of Stock",
                    category="inventory",
                    icon="x-circle",
                    description="Items with zero quantity",
                ),
            ]
        except Exception as e:
            logger.warning(f"Failed to get inventory store metrics: {e}")
            return []

    def get_platform_metrics(
        self,
        db: Session,
        platform_id: int,
        context: MetricsContext | None = None,
    ) -> list[MetricValue]:
        """
        Get inventory metrics aggregated for a platform.

        Aggregates stock data across all stores.
        """
        from app.modules.inventory.models import Inventory
        from app.modules.tenancy.services.platform_service import platform_service

        try:
            # Get all store IDs for this platform via platform service
            store_ids = platform_service.get_store_ids_for_platform(db, platform_id)

            # Total inventory
            total_quantity = (
                db.query(func.sum(Inventory.quantity))
                .filter(Inventory.store_id.in_(store_ids))
                .scalar()
                or 0
            )

            # Reserved inventory
            reserved_quantity = (
                db.query(func.sum(Inventory.reserved_quantity))
                .filter(Inventory.store_id.in_(store_ids))
                .scalar()
                or 0
            )

            # Available inventory
            available_quantity = int(total_quantity) - int(reserved_quantity)

            # Total inventory entries
            inventory_entries = (
                db.query(Inventory).filter(Inventory.store_id.in_(store_ids)).count()
            )

            # Stores with inventory
            stores_with_inventory = (
                db.query(func.count(func.distinct(Inventory.store_id)))
                .filter(Inventory.store_id.in_(store_ids))
                .scalar()
                or 0
            )

            # Low stock items across platform
            low_stock_items = (
                db.query(Inventory)
                .filter(
                    Inventory.store_id.in_(store_ids),
                    Inventory.quantity > 0,
                    Inventory.quantity < 10,
                )
                .count()
            )

            # Out of stock items
            out_of_stock_items = (
                db.query(Inventory)
                .filter(Inventory.store_id.in_(store_ids), Inventory.quantity == 0)
                .count()
            )

            return [
                MetricValue(
                    key="inventory.total_quantity",
                    value=int(total_quantity),
                    label="Total Stock",
                    category="inventory",
                    icon="package",
                    unit="items",
                    description="Total inventory across all stores",
                ),
                MetricValue(
                    key="inventory.reserved_quantity",
                    value=int(reserved_quantity),
                    label="Reserved",
                    category="inventory",
                    icon="lock",
                    unit="items",
                    description="Inventory reserved for orders",
                ),
                MetricValue(
                    key="inventory.available_quantity",
                    value=available_quantity,
                    label="Available",
                    category="inventory",
                    icon="check",
                    unit="items",
                    description="Inventory available for sale",
                ),
                MetricValue(
                    key="inventory.entries",
                    value=inventory_entries,
                    label="Total Entries",
                    category="inventory",
                    icon="list",
                    description="Total inventory entries across stores",
                ),
                MetricValue(
                    key="inventory.stores_with_inventory",
                    value=stores_with_inventory,
                    label="Stores with Stock",
                    category="inventory",
                    icon="store",
                    description="Stores managing inventory",
                ),
                MetricValue(
                    key="inventory.low_stock",
                    value=low_stock_items,
                    label="Low Stock Items",
                    category="inventory",
                    icon="alert-triangle",
                    description="Items with quantity < 10",
                ),
                MetricValue(
                    key="inventory.out_of_stock",
                    value=out_of_stock_items,
                    label="Out of Stock",
                    category="inventory",
                    icon="x-circle",
                    description="Items with zero quantity",
                ),
            ]
        except Exception as e:
            logger.warning(f"Failed to get inventory platform metrics: {e}")
            return []


# Singleton instance
inventory_metrics_provider = InventoryMetricsProvider()

__all__ = ["InventoryMetricsProvider", "inventory_metrics_provider"]
