# app/modules/billing/tests/unit/test_billing_metrics.py
"""Unit tests for BillingMetricsProvider.get_merchant_metrics."""

import uuid
from datetime import UTC, datetime, timedelta

import pytest

from app.modules.billing.models import (
    MerchantSubscription,
    SubscriptionStatus,
    SubscriptionTier,
)
from app.modules.billing.services.billing_metrics import BillingMetricsProvider
from app.modules.tenancy.models import Merchant, Platform, User


@pytest.fixture
def billing_platform(db):
    """Create a platform for billing metrics tests."""
    platform = Platform(
        code=f"bm_{uuid.uuid4().hex[:8]}",
        name="Billing Metrics Platform",
        is_active=True,
    )
    db.add(platform)
    db.commit()
    db.refresh(platform)
    return platform


@pytest.fixture
def billing_merchant(db):
    """Create a merchant for billing metrics tests."""
    from middleware.auth import AuthManager

    auth = AuthManager()
    user = User(
        email=f"billowner_{uuid.uuid4().hex[:8]}@test.com",
        username=f"billowner_{uuid.uuid4().hex[:8]}",
        hashed_password=auth.hash_password("pass123"),
        role="merchant_owner",
        is_active=True,
    )
    db.add(user)
    db.flush()

    merchant = Merchant(
        name="Billing Metrics Merchant",
        owner_user_id=user.id,
        contact_email=user.email,
        is_active=True,
        is_verified=True,
    )
    db.add(merchant)
    db.commit()
    db.refresh(merchant)
    return merchant


@pytest.fixture
def billing_tier(db, billing_platform):
    """Create a subscription tier."""
    tier = SubscriptionTier(
        code="professional",
        name="Professional",
        description="Pro tier",
        price_monthly_cents=2900,
        price_annual_cents=29000,
        display_order=1,
        is_active=True,
        is_public=True,
        platform_id=billing_platform.id,
    )
    db.add(tier)
    db.commit()
    db.refresh(tier)
    return tier


@pytest.fixture
def billing_extra_platforms(db):
    """Create additional platforms for multiple subscriptions (unique constraint: merchant+platform)."""
    platforms = []
    for i in range(2):
        platforms.append(Platform(
            code=f"bm_extra_{uuid.uuid4().hex[:8]}",
            name=f"Extra Platform {i}",
            is_active=True,
        ))
    db.add_all(platforms)
    db.commit()
    for p in platforms:
        db.refresh(p)
    return platforms


@pytest.fixture
def billing_subscriptions(db, billing_merchant, billing_platform, billing_tier, billing_extra_platforms):
    """Create subscriptions: 1 active, 1 trial, 1 cancelled (each on a different platform)."""
    platforms = [billing_platform, billing_extra_platforms[0], billing_extra_platforms[1]]
    subs = []
    for status, platform in zip(
        [SubscriptionStatus.ACTIVE, SubscriptionStatus.TRIAL, SubscriptionStatus.CANCELLED],
        platforms, strict=False,
    ):
        sub = MerchantSubscription(
            merchant_id=billing_merchant.id,
            platform_id=platform.id,
            tier_id=billing_tier.id,
            status=status.value,
            is_annual=False,
            period_start=datetime.now(UTC),
            period_end=datetime.now(UTC) + timedelta(days=30),
        )
        db.add(sub)
        subs.append(sub)
    db.commit()
    for s in subs:
        db.refresh(s)
    return subs


@pytest.mark.unit
@pytest.mark.billing
class TestBillingMetricsProviderMerchant:
    """Tests for BillingMetricsProvider.get_merchant_metrics."""

    def setup_method(self):
        self.provider = BillingMetricsProvider()

    def test_active_subscriptions_count(self, db, billing_merchant, billing_subscriptions):
        """Counts active + trial subscriptions, excludes cancelled."""
        metrics = self.provider.get_merchant_metrics(db, billing_merchant.id)
        by_key = {m.key: m.value for m in metrics}
        assert by_key["billing.active_subscriptions"] == 2

    def test_no_subscriptions(self, db, billing_merchant):
        """Returns zero when merchant has no subscriptions."""
        metrics = self.provider.get_merchant_metrics(db, billing_merchant.id)
        by_key = {m.key: m.value for m in metrics}
        assert by_key["billing.active_subscriptions"] == 0

    def test_nonexistent_merchant(self, db):
        """Returns zero for a non-existent merchant ID."""
        metrics = self.provider.get_merchant_metrics(db, 999999)
        by_key = {m.key: m.value for m in metrics}
        assert by_key["billing.active_subscriptions"] == 0
