# app/modules/orders/services/order_metrics.py
"""
Metrics provider for the orders module.

Provides metrics for:
- Order counts and status
- Revenue metrics
- Invoice statistics
"""

import logging
from datetime import datetime, timedelta
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 OrderMetricsProvider:
    """
    Metrics provider for orders module.

    Provides order and revenue metrics for store and platform dashboards.
    """

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

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

        Provides:
        - Total orders
        - Orders by status
        - Revenue metrics
        """
        from app.modules.orders.models import Order, OrderItem

        try:
            # Total orders
            total_orders = (
                db.query(Order).filter(Order.store_id == store_id).count()
            )

            # Orders in period (default to last 30 days)
            date_from = context.date_from if context else None
            if date_from is None:
                date_from = datetime.utcnow() - timedelta(days=30)

            orders_in_period_query = db.query(Order).filter(
                Order.store_id == store_id,
                Order.created_at >= date_from,
            )
            if context and context.date_to:
                orders_in_period_query = orders_in_period_query.filter(
                    Order.created_at <= context.date_to
                )
            orders_in_period = orders_in_period_query.count()

            # Total order items
            total_order_items = (
                db.query(OrderItem)
                .join(Order, Order.id == OrderItem.order_id)
                .filter(Order.store_id == store_id)
                .count()
            )

            # Revenue (sum of order totals) - if total_amount field exists
            try:
                total_revenue = (
                    db.query(func.sum(Order.total_amount))
                    .filter(Order.store_id == store_id)
                    .scalar()
                    or 0
                )

                revenue_in_period = (
                    db.query(func.sum(Order.total_amount))
                    .filter(
                        Order.store_id == store_id,
                        Order.created_at >= date_from,
                    )
                    .scalar()
                    or 0
                )
            except Exception:
                # Field may not exist
                total_revenue = 0
                revenue_in_period = 0

            # Average order value
            avg_order_value = round(total_revenue / total_orders, 2) if total_orders > 0 else 0

            return [
                MetricValue(
                    key="orders.total",
                    value=total_orders,
                    label="Total Orders",
                    category="orders",
                    icon="shopping-cart",
                    description="Total orders received",
                ),
                MetricValue(
                    key="orders.in_period",
                    value=orders_in_period,
                    label="Recent Orders",
                    category="orders",
                    icon="clock",
                    description="Orders in the selected period",
                ),
                MetricValue(
                    key="orders.total_items",
                    value=total_order_items,
                    label="Total Items Sold",
                    category="orders",
                    icon="box",
                    description="Total order items",
                ),
                MetricValue(
                    key="orders.total_revenue",
                    value=float(total_revenue),
                    label="Total Revenue",
                    category="orders",
                    icon="currency-euro",
                    unit="EUR",
                    description="Total revenue from orders",
                ),
                MetricValue(
                    key="orders.revenue_period",
                    value=float(revenue_in_period),
                    label="Period Revenue",
                    category="orders",
                    icon="trending-up",
                    unit="EUR",
                    description="Revenue in the selected period",
                ),
                MetricValue(
                    key="orders.avg_value",
                    value=avg_order_value,
                    label="Avg Order Value",
                    category="orders",
                    icon="calculator",
                    unit="EUR",
                    description="Average order value",
                ),
            ]
        except Exception as e:
            logger.warning(f"Failed to get order store metrics: {e}")
            return []

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

        Aggregates order data across all stores.
        """
        from app.modules.orders.models import Order
        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 orders
            total_orders = (
                db.query(Order).filter(Order.store_id.in_(store_ids)).count()
            )

            # Orders in period (default to last 30 days)
            date_from = context.date_from if context else None
            if date_from is None:
                date_from = datetime.utcnow() - timedelta(days=30)

            orders_in_period_query = db.query(Order).filter(
                Order.store_id.in_(store_ids),
                Order.created_at >= date_from,
            )
            if context and context.date_to:
                orders_in_period_query = orders_in_period_query.filter(
                    Order.created_at <= context.date_to
                )
            orders_in_period = orders_in_period_query.count()

            # Stores with orders
            stores_with_orders = (
                db.query(func.count(func.distinct(Order.store_id)))
                .filter(Order.store_id.in_(store_ids))
                .scalar()
                or 0
            )

            # Revenue metrics
            try:
                total_revenue = (
                    db.query(func.sum(Order.total_amount))
                    .filter(Order.store_id.in_(store_ids))
                    .scalar()
                    or 0
                )

                revenue_in_period = (
                    db.query(func.sum(Order.total_amount))
                    .filter(
                        Order.store_id.in_(store_ids),
                        Order.created_at >= date_from,
                    )
                    .scalar()
                    or 0
                )
            except Exception:
                total_revenue = 0
                revenue_in_period = 0

            # Average order value
            avg_order_value = round(total_revenue / total_orders, 2) if total_orders > 0 else 0

            return [
                MetricValue(
                    key="orders.total",
                    value=total_orders,
                    label="Total Orders",
                    category="orders",
                    icon="shopping-cart",
                    description="Total orders across all stores",
                ),
                MetricValue(
                    key="orders.in_period",
                    value=orders_in_period,
                    label="Recent Orders",
                    category="orders",
                    icon="clock",
                    description="Orders in the selected period",
                ),
                MetricValue(
                    key="orders.stores_with_orders",
                    value=stores_with_orders,
                    label="Stores with Orders",
                    category="orders",
                    icon="store",
                    description="Stores that have received orders",
                ),
                MetricValue(
                    key="orders.total_revenue",
                    value=float(total_revenue),
                    label="Total Revenue",
                    category="orders",
                    icon="currency-euro",
                    unit="EUR",
                    description="Total revenue across platform",
                ),
                MetricValue(
                    key="orders.revenue_period",
                    value=float(revenue_in_period),
                    label="Period Revenue",
                    category="orders",
                    icon="trending-up",
                    unit="EUR",
                    description="Revenue in the selected period",
                ),
                MetricValue(
                    key="orders.avg_value",
                    value=avg_order_value,
                    label="Avg Order Value",
                    category="orders",
                    icon="calculator",
                    unit="EUR",
                    description="Average order value",
                ),
            ]
        except Exception as e:
            logger.warning(f"Failed to get order platform metrics: {e}")
            return []


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

        This is an entity-level method (not dashboard-level) that provides
        order statistics for a specific customer. Used by customer detail pages.

        Args:
            db: Database session
            store_id: Store ID (for ownership verification)
            customer_id: Customer ID
            context: Optional filtering context

        Returns:
            List of MetricValue objects for this customer's order activity
        """
        from app.modules.orders.models import Order

        try:
            # Base query for customer orders
            base_query = db.query(Order).filter(
                Order.customer_id == customer_id,
                Order.store_id == store_id,
            )

            # Total orders
            total_orders = base_query.count()

            # Revenue stats
            revenue_query = db.query(
                func.sum(Order.total_amount_cents).label("total_spent_cents"),
                func.avg(Order.total_amount_cents).label("avg_order_cents"),
                func.max(Order.created_at).label("last_order_date"),
                func.min(Order.created_at).label("first_order_date"),
            ).filter(
                Order.customer_id == customer_id,
                Order.store_id == store_id,
            )

            stats = revenue_query.first()

            total_spent_cents = stats.total_spent_cents or 0
            avg_order_cents = stats.avg_order_cents or 0
            last_order_date = stats.last_order_date
            first_order_date = stats.first_order_date

            # Convert cents to currency
            total_spent = total_spent_cents / 100
            avg_order_value = avg_order_cents / 100 if avg_order_cents else 0.0

            return [
                MetricValue(
                    key="customer.total_orders",
                    value=total_orders,
                    label="Total Orders",
                    category="customer_orders",
                    icon="shopping-bag",
                    description="Total orders placed by this customer",
                ),
                MetricValue(
                    key="customer.total_spent",
                    value=round(total_spent, 2),
                    label="Total Spent",
                    category="customer_orders",
                    icon="currency-euro",
                    unit="EUR",
                    description="Total amount spent by this customer",
                ),
                MetricValue(
                    key="customer.avg_order_value",
                    value=round(avg_order_value, 2),
                    label="Avg Order Value",
                    category="customer_orders",
                    icon="calculator",
                    unit="EUR",
                    description="Average order value for this customer",
                ),
                MetricValue(
                    key="customer.last_order_date",
                    value=last_order_date.isoformat() if last_order_date else "",
                    label="Last Order",
                    category="customer_orders",
                    icon="calendar",
                    description="Date of most recent order",
                ),
                MetricValue(
                    key="customer.first_order_date",
                    value=first_order_date.isoformat() if first_order_date else "",
                    label="First Order",
                    category="customer_orders",
                    icon="calendar-plus",
                    description="Date of first order",
                ),
            ]
        except Exception as e:
            logger.warning(f"Failed to get customer order metrics: {e}")
            return []


# Singleton instance
order_metrics_provider = OrderMetricsProvider()

__all__ = ["OrderMetricsProvider", "order_metrics_provider"]
