# tests/unit/services/test_order_metrics_customer.py
"""
Unit tests for OrderMetricsProvider customer metrics.

Tests the get_customer_order_metrics method which provides
customer-level order statistics using the MetricsProvider pattern.
"""

from datetime import UTC, datetime

import pytest

from app.modules.orders.models import Order
from app.modules.orders.services.order_metrics import OrderMetricsProvider


@pytest.fixture
def order_metrics_provider():
    """Create OrderMetricsProvider instance."""
    return OrderMetricsProvider()


@pytest.fixture
def customer_with_orders(db, test_store, test_customer):
    """Create a customer with multiple orders for metrics testing."""
    orders = []
    first_name = test_customer.first_name or "Test"
    last_name = test_customer.last_name or "Customer"

    for i in range(3):
        order = Order(
            store_id=test_store.id,
            customer_id=test_customer.id,
            order_number=f"METRICS-{i:04d}",
            status="completed",
            channel="direct",
            order_date=datetime.now(UTC),
            subtotal_cents=1000 * (i + 1),  # 1000, 2000, 3000
            total_amount_cents=1000 * (i + 1),
            currency="EUR",
            # Customer info
            customer_email=test_customer.email,
            customer_first_name=first_name,
            customer_last_name=last_name,
            # Shipping address
            ship_first_name=first_name,
            ship_last_name=last_name,
            ship_address_line_1="123 Test St",
            ship_city="Luxembourg",
            ship_postal_code="L-1234",
            ship_country_iso="LU",
            # Billing address
            bill_first_name=first_name,
            bill_last_name=last_name,
            bill_address_line_1="123 Test St",
            bill_city="Luxembourg",
            bill_postal_code="L-1234",
            bill_country_iso="LU",
        )
        db.add(order)  # noqa: PERF006
        orders.append(order)

    db.commit()
    for order in orders:
        db.refresh(order)

    return test_customer, orders


@pytest.mark.unit
class TestOrderMetricsProviderCustomerMetrics:
    """Tests for get_customer_order_metrics method."""

    def test_get_customer_metrics_no_orders(
        self, db, order_metrics_provider, test_store, test_customer
    ):
        """Test metrics when customer has no orders."""
        metrics = order_metrics_provider.get_customer_order_metrics(
            db=db,
            store_id=test_store.id,
            customer_id=test_customer.id,
        )

        # Should return metrics even with no orders
        assert len(metrics) > 0

        # Find total_orders metric
        total_orders_metric = next(
            (m for m in metrics if m.key == "customer.total_orders"), None
        )
        assert total_orders_metric is not None
        assert total_orders_metric.value == 0

    def test_get_customer_metrics_with_orders(
        self, db, order_metrics_provider, test_store, customer_with_orders
    ):
        """Test metrics when customer has orders."""
        customer, orders = customer_with_orders

        metrics = order_metrics_provider.get_customer_order_metrics(
            db=db,
            store_id=test_store.id,
            customer_id=customer.id,
        )

        # Check total orders
        total_orders = next(
            (m for m in metrics if m.key == "customer.total_orders"), None
        )
        assert total_orders is not None
        assert total_orders.value == 3

        # Check total spent (1000 + 2000 + 3000 = 6000 cents = 60.00)
        total_spent = next(
            (m for m in metrics if m.key == "customer.total_spent"), None
        )
        assert total_spent is not None
        assert total_spent.value == 60.0

        # Check average order value (6000 / 3 = 2000 cents = 20.00)
        avg_value = next(
            (m for m in metrics if m.key == "customer.avg_order_value"), None
        )
        assert avg_value is not None
        assert avg_value.value == 20.0

    def test_get_customer_metrics_has_required_fields(
        self, db, order_metrics_provider, test_store, customer_with_orders
    ):
        """Test that all required metric fields are present."""
        customer, _ = customer_with_orders

        metrics = order_metrics_provider.get_customer_order_metrics(
            db=db,
            store_id=test_store.id,
            customer_id=customer.id,
        )

        expected_keys = [
            "customer.total_orders",
            "customer.total_spent",
            "customer.avg_order_value",
            "customer.last_order_date",
            "customer.first_order_date",
        ]

        metric_keys = [m.key for m in metrics]
        for key in expected_keys:
            assert key in metric_keys, f"Missing metric: {key}"

    def test_get_customer_metrics_has_labels_and_icons(
        self, db, order_metrics_provider, test_store, customer_with_orders
    ):
        """Test that metrics have display metadata."""
        customer, _ = customer_with_orders

        metrics = order_metrics_provider.get_customer_order_metrics(
            db=db,
            store_id=test_store.id,
            customer_id=customer.id,
        )

        for metric in metrics:
            assert metric.label, f"Metric {metric.key} missing label"
            assert metric.category == "customer_orders"

    def test_get_customer_metrics_wrong_store(
        self, db, order_metrics_provider, customer_with_orders
    ):
        """Test metrics with wrong store returns zero values."""
        customer, _ = customer_with_orders

        metrics = order_metrics_provider.get_customer_order_metrics(
            db=db,
            store_id=99999,  # Non-existent store
            customer_id=customer.id,
        )

        total_orders = next(
            (m for m in metrics if m.key == "customer.total_orders"), None
        )
        assert total_orders is not None
        assert total_orders.value == 0
