# app/modules/customers/services/customer_metrics.py
"""
Metrics provider for the customers module.

Provides metrics for:
- Customer counts
- New customers
- Customer addresses
"""

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 CustomerMetricsProvider:
    """
    Metrics provider for customers module.

    Provides customer-related metrics for store and platform dashboards.
    """

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

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

        Provides:
        - Total customers
        - New customers (in period)
        - Customers with addresses
        """
        from app.modules.customers.models import Customer, CustomerAddress

        try:
            # Total customers
            total_customers = (
                db.query(Customer).filter(Customer.store_id == store_id).count()
            )

            # New customers (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)

            new_customers_query = db.query(Customer).filter(
                Customer.store_id == store_id,
                Customer.created_at >= date_from,
            )
            if context and context.date_to:
                new_customers_query = new_customers_query.filter(
                    Customer.created_at <= context.date_to
                )
            new_customers = new_customers_query.count()

            # Customers with addresses
            customers_with_addresses = (
                db.query(func.count(func.distinct(CustomerAddress.customer_id)))
                .join(Customer, Customer.id == CustomerAddress.customer_id)
                .filter(Customer.store_id == store_id)
                .scalar()
                or 0
            )

            return [
                MetricValue(
                    key="customers.total",
                    value=total_customers,
                    label="Total Customers",
                    category="customers",
                    icon="users",
                    description="Total number of customers",
                ),
                MetricValue(
                    key="customers.new",
                    value=new_customers,
                    label="New Customers",
                    category="customers",
                    icon="user-plus",
                    description="Customers acquired in the period",
                ),
                MetricValue(
                    key="customers.with_addresses",
                    value=customers_with_addresses,
                    label="With Addresses",
                    category="customers",
                    icon="map-pin",
                    description="Customers who have saved addresses",
                ),
            ]
        except Exception as e:
            logger.warning(f"Failed to get customer store metrics: {e}")
            return []

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

        For platforms, aggregates customer data across all stores.
        """
        from app.modules.customers.models import Customer
        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 customers across all stores
            total_customers = (
                db.query(Customer).filter(Customer.store_id.in_(store_ids)).count()
            )

            # Unique customers (by email across platform)
            unique_customer_emails = (
                db.query(func.count(func.distinct(Customer.email)))
                .filter(Customer.store_id.in_(store_ids))
                .scalar()
                or 0
            )

            # New customers (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)

            new_customers_query = db.query(Customer).filter(
                Customer.store_id.in_(store_ids),
                Customer.created_at >= date_from,
            )
            if context and context.date_to:
                new_customers_query = new_customers_query.filter(
                    Customer.created_at <= context.date_to
                )
            new_customers = new_customers_query.count()

            return [
                MetricValue(
                    key="customers.total",
                    value=total_customers,
                    label="Total Customers",
                    category="customers",
                    icon="users",
                    description="Total customer records across all stores",
                ),
                MetricValue(
                    key="customers.unique_emails",
                    value=unique_customer_emails,
                    label="Unique Customers",
                    category="customers",
                    icon="user",
                    description="Unique customer emails across platform",
                ),
                MetricValue(
                    key="customers.new",
                    value=new_customers,
                    label="New Customers",
                    category="customers",
                    icon="user-plus",
                    description="Customers acquired in the period",
                ),
            ]
        except Exception as e:
            logger.warning(f"Failed to get customer platform metrics: {e}")
            return []

    def get_merchant_metrics(
        self,
        db: Session,
        merchant_id: int,
        context: MetricsContext | None = None,
    ) -> list[MetricValue]:
        """
        Get customer metrics scoped to a merchant.

        Aggregates customer counts across all stores owned by the merchant.
        """
        from app.modules.customers.models import Customer
        from app.modules.tenancy.services.store_service import store_service

        try:
            merchant_stores = store_service.get_stores_by_merchant_id(db, merchant_id)
            merchant_store_ids = [s.id for s in merchant_stores]

            total_customers = (
                db.query(Customer)
                .filter(Customer.store_id.in_(merchant_store_ids))
                .count()
            )

            return [
                MetricValue(
                    key="customers.total",
                    value=total_customers,
                    label="Total Customers",
                    category="customers",
                    icon="users",
                    description="Total customers across all merchant stores",
                ),
            ]
        except Exception as e:
            logger.warning(f"Failed to get customer merchant metrics: {e}")
            return []


# Singleton instance
customer_metrics_provider = CustomerMetricsProvider()

__all__ = ["CustomerMetricsProvider", "customer_metrics_provider"]
