# app/modules/billing/tests/integration/test_admin_routes.py
"""
Integration tests for billing admin API routes.

Tests the admin subscription management endpoints at:
    /api/v1/admin/subscriptions/*

Uses super_admin_headers fixture which bypasses module access checks.
"""

import uuid
from datetime import UTC, datetime, timedelta

import pytest

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

# ============================================================================
# Fixtures
# ============================================================================

BASE = "/api/v1/admin/subscriptions"


@pytest.fixture
def rt_platform(db):
    """Create a platform for route tests."""
    platform = Platform(
        code=f"test_{uuid.uuid4().hex[:8]}",
        name="Test Platform",
        is_active=True,
    )
    db.add(platform)
    db.commit()
    db.refresh(platform)
    return platform


@pytest.fixture
def rt_tiers(db, rt_platform):
    """Create subscription tiers for route tests."""
    tiers = []
    for i, (code, name, price) in enumerate([
        ("essential", "Essential", 0),
        ("professional", "Professional", 2900),
        ("business", "Business", 7900),
    ]):
        tier = SubscriptionTier(
            code=code,
            name=name,
            description=f"{name} tier",
            price_monthly_cents=price,
            price_annual_cents=price * 10 if price > 0 else 0,
            display_order=i,
            is_active=True,
            is_public=True,
            platform_id=rt_platform.id,
        )
        db.add(tier)
        tiers.append(tier)
    db.commit()
    for t in tiers:
        db.refresh(t)
    return tiers


@pytest.fixture
def rt_merchant(db, rt_platform):
    """Create a merchant with owner for route tests."""
    from middleware.auth import AuthManager

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

    merchant = Merchant(
        name="Route Test Merchant",
        owner_user_id=owner.id,
        contact_email=owner.email,
        is_active=True,
        is_verified=True,
    )
    db.add(merchant)
    db.commit()
    db.refresh(merchant)
    return merchant


@pytest.fixture
def rt_subscription(db, rt_merchant, rt_platform, rt_tiers):
    """Create a subscription for route tests."""
    sub = MerchantSubscription(
        merchant_id=rt_merchant.id,
        platform_id=rt_platform.id,
        tier_id=rt_tiers[1].id,  # professional
        status=SubscriptionStatus.ACTIVE.value,
        is_annual=False,
        period_start=datetime.now(UTC),
        period_end=datetime.now(UTC) + timedelta(days=30),
    )
    db.add(sub)
    db.commit()
    db.refresh(sub)
    return sub


@pytest.fixture
def rt_billing_history(db, rt_merchant):
    """Create billing history entries for route tests."""
    records = []
    for i in range(3):
        record = BillingHistory(
            merchant_id=rt_merchant.id,
            invoice_number=f"INV-{1000 + i}",
            invoice_date=datetime.now(UTC) - timedelta(days=30 * i),
            subtotal_cents=2900,
            tax_cents=493,
            total_cents=3393,
            amount_paid_cents=3393,
            currency="EUR",
            status="paid",
            description=f"Invoice {i}",
        )
        db.add(record)  # noqa: PERF006
        records.append(record)
    db.commit()
    for r in records:
        db.refresh(r)
    return records


# ============================================================================
# Tier Endpoints
# ============================================================================


class TestAdminListTiers:
    """Tests for GET /api/v1/admin/subscriptions/tiers."""

    def test_list_tiers_success(self, client, super_admin_headers, rt_tiers):
        response = client.get(f"{BASE}/tiers", headers=super_admin_headers)
        assert response.status_code == 200
        data = response.json()
        assert "tiers" in data
        assert "total" in data
        assert data["total"] >= 3

    def test_list_tiers_active_only_by_default(self, client, super_admin_headers, rt_tiers, db):
        # Deactivate one tier
        rt_tiers[2].is_active = False
        db.commit()

        response = client.get(f"{BASE}/tiers", headers=super_admin_headers)
        assert response.status_code == 200
        codes = [t["code"] for t in response.json()["tiers"]]
        assert "business" not in codes

    def test_list_tiers_include_inactive(self, client, super_admin_headers, rt_tiers, db):
        rt_tiers[2].is_active = False
        db.commit()

        response = client.get(
            f"{BASE}/tiers",
            params={"include_inactive": True},
            headers=super_admin_headers,
        )
        assert response.status_code == 200
        codes = [t["code"] for t in response.json()["tiers"]]
        assert "business" in codes

    def test_list_tiers_filter_by_platform(self, client, super_admin_headers, rt_tiers, rt_platform):
        response = client.get(
            f"{BASE}/tiers",
            params={"platform_id": rt_platform.id},
            headers=super_admin_headers,
        )
        assert response.status_code == 200
        assert response.json()["total"] == 3

    def test_list_tiers_unauthorized(self, client):
        response = client.get(f"{BASE}/tiers")
        assert response.status_code in (401, 403)


class TestAdminGetTier:
    """Tests for GET /api/v1/admin/subscriptions/tiers/{tier_code}."""

    def test_get_tier_success(self, client, super_admin_headers, rt_tiers):
        response = client.get(
            f"{BASE}/tiers/professional", headers=super_admin_headers
        )
        assert response.status_code == 200
        data = response.json()
        assert data["code"] == "professional"
        assert data["name"] == "Professional"
        assert data["price_monthly_cents"] == 2900

    def test_get_tier_not_found(self, client, super_admin_headers):
        response = client.get(
            f"{BASE}/tiers/nonexistent", headers=super_admin_headers
        )
        assert response.status_code == 404


class TestAdminCreateTier:
    """Tests for POST /api/v1/admin/subscriptions/tiers."""

    def test_create_tier_success(self, client, super_admin_headers, rt_platform):
        response = client.post(
            f"{BASE}/tiers",
            json={
                "code": "starter",
                "name": "Starter",
                "description": "Starter plan",
                "price_monthly_cents": 990,
                "price_annual_cents": 9900,
                "display_order": 0,
                "is_active": True,
                "is_public": True,
                "platform_id": rt_platform.id,
            },
            headers=super_admin_headers,
        )
        assert response.status_code == 201
        data = response.json()
        assert data["code"] == "starter"
        assert data["price_monthly_cents"] == 990

    def test_create_tier_duplicate_code(self, client, super_admin_headers, rt_tiers):
        response = client.post(
            f"{BASE}/tiers",
            json={
                "code": "essential",
                "name": "Essential Dup",
                "price_monthly_cents": 0,
            },
            headers=super_admin_headers,
        )
        assert response.status_code in (400, 409, 422)


class TestAdminUpdateTier:
    """Tests for PATCH /api/v1/admin/subscriptions/tiers/{tier_code}."""

    def test_update_tier_success(self, client, super_admin_headers, rt_tiers):
        response = client.patch(
            f"{BASE}/tiers/professional",
            json={"name": "Professional Plus", "price_monthly_cents": 3900},
            headers=super_admin_headers,
        )
        assert response.status_code == 200
        data = response.json()
        assert data["name"] == "Professional Plus"
        assert data["price_monthly_cents"] == 3900

    def test_update_tier_not_found(self, client, super_admin_headers):
        response = client.patch(
            f"{BASE}/tiers/nonexistent",
            json={"name": "Updated"},
            headers=super_admin_headers,
        )
        assert response.status_code == 404


class TestAdminDeleteTier:
    """Tests for DELETE /api/v1/admin/subscriptions/tiers/{tier_code}."""

    def test_delete_tier_success(self, client, super_admin_headers, rt_tiers):
        response = client.delete(
            f"{BASE}/tiers/business", headers=super_admin_headers
        )
        assert response.status_code == 204

    def test_delete_tier_with_active_subs(
        self, client, super_admin_headers, rt_subscription, rt_tiers
    ):
        # Try to delete the tier used by rt_subscription (professional)
        response = client.delete(
            f"{BASE}/tiers/professional", headers=super_admin_headers
        )
        assert response.status_code in (400, 409, 422)

    def test_delete_tier_not_found(self, client, super_admin_headers):
        response = client.delete(
            f"{BASE}/tiers/nonexistent", headers=super_admin_headers
        )
        assert response.status_code == 404


# ============================================================================
# Subscription Endpoints
# ============================================================================


class TestAdminListSubscriptions:
    """Tests for GET /api/v1/admin/subscriptions."""

    def test_list_subscriptions_success(
        self, client, super_admin_headers, rt_subscription
    ):
        response = client.get(f"{BASE}", headers=super_admin_headers)
        assert response.status_code == 200
        data = response.json()
        assert "subscriptions" in data
        assert "total" in data
        assert data["total"] >= 1

    def test_list_subscriptions_pagination(
        self, client, super_admin_headers, rt_subscription
    ):
        response = client.get(
            f"{BASE}",
            params={"page": 1, "per_page": 5},
            headers=super_admin_headers,
        )
        assert response.status_code == 200
        data = response.json()
        assert data["page"] == 1
        assert data["per_page"] == 5

    def test_list_subscriptions_filter_by_status(
        self, client, super_admin_headers, rt_subscription
    ):
        response = client.get(
            f"{BASE}",
            params={"status": "active"},
            headers=super_admin_headers,
        )
        assert response.status_code == 200
        for sub in response.json()["subscriptions"]:
            assert sub["status"] == "active"


class TestAdminCreateSubscription:
    """Tests for POST /api/v1/admin/subscriptions/merchants/{id}/platforms/{id}."""

    def test_create_subscription_success(
        self, client, super_admin_headers, rt_merchant, rt_platform, rt_tiers
    ):
        response = client.post(
            f"{BASE}/merchants/{rt_merchant.id}/platforms/{rt_platform.id}",
            json={
                "merchant_id": rt_merchant.id,
                "platform_id": rt_platform.id,
                "tier_code": "essential",
                "status": "trial",
                "trial_days": 14,
                "is_annual": False,
            },
            headers=super_admin_headers,
        )
        assert response.status_code == 201
        data = response.json()
        assert data["merchant_id"] == rt_merchant.id
        assert data["platform_id"] == rt_platform.id


class TestAdminGetSubscription:
    """Tests for GET /api/v1/admin/subscriptions/merchants/{id}/platforms/{id}."""

    def test_get_subscription_success(
        self, client, super_admin_headers, rt_subscription, rt_merchant, rt_platform
    ):
        response = client.get(
            f"{BASE}/merchants/{rt_merchant.id}/platforms/{rt_platform.id}",
            headers=super_admin_headers,
        )
        assert response.status_code == 200
        data = response.json()
        assert data["merchant_id"] == rt_merchant.id
        assert data["status"] == "active"

    def test_get_subscription_not_found(
        self, client, super_admin_headers, rt_platform
    ):
        response = client.get(
            f"{BASE}/merchants/99999/platforms/{rt_platform.id}",
            headers=super_admin_headers,
        )
        assert response.status_code == 404


class TestAdminUpdateSubscription:
    """Tests for PATCH /api/v1/admin/subscriptions/merchants/{id}/platforms/{id}."""

    def test_update_subscription_status(
        self, client, super_admin_headers, rt_subscription, rt_merchant, rt_platform
    ):
        response = client.patch(
            f"{BASE}/merchants/{rt_merchant.id}/platforms/{rt_platform.id}",
            json={"status": "past_due"},
            headers=super_admin_headers,
        )
        assert response.status_code == 200
        assert response.json()["status"] == "past_due"

    def test_update_subscription_tier(
        self,
        client,
        super_admin_headers,
        rt_subscription,
        rt_merchant,
        rt_platform,
        rt_tiers,
    ):
        response = client.patch(
            f"{BASE}/merchants/{rt_merchant.id}/platforms/{rt_platform.id}",
            json={"tier_code": "business"},
            headers=super_admin_headers,
        )
        assert response.status_code == 200


# ============================================================================
# Stats Endpoint
# ============================================================================


class TestAdminStats:
    """Tests for GET /api/v1/admin/subscriptions/stats."""

    def test_get_stats_success(
        self, client, super_admin_headers, rt_subscription
    ):
        response = client.get(
            f"{BASE}/stats", headers=super_admin_headers
        )
        assert response.status_code == 200
        data = response.json()
        assert "total_subscriptions" in data
        assert "active_count" in data
        assert "mrr_cents" in data
        assert "arr_cents" in data
        assert "tier_distribution" in data
        assert data["active_count"] >= 1

    def test_get_stats_empty(self, client, super_admin_headers):
        response = client.get(
            f"{BASE}/stats", headers=super_admin_headers
        )
        assert response.status_code == 200
        data = response.json()
        assert data["total_subscriptions"] == 0


# ============================================================================
# Billing History Endpoint
# ============================================================================


class TestAdminBillingHistory:
    """Tests for GET /api/v1/admin/subscriptions/billing/history."""

    def test_list_billing_history_success(
        self, client, super_admin_headers, rt_billing_history
    ):
        response = client.get(
            f"{BASE}/billing/history", headers=super_admin_headers
        )
        assert response.status_code == 200
        data = response.json()
        assert "invoices" in data
        assert "total" in data
        assert data["total"] >= 3

    def test_list_billing_history_pagination(
        self, client, super_admin_headers, rt_billing_history
    ):
        response = client.get(
            f"{BASE}/billing/history",
            params={"page": 1, "per_page": 2},
            headers=super_admin_headers,
        )
        assert response.status_code == 200
        data = response.json()
        assert data["per_page"] == 2
        assert len(data["invoices"]) <= 2

    def test_list_billing_history_filter_by_merchant(
        self, client, super_admin_headers, rt_billing_history, rt_merchant
    ):
        response = client.get(
            f"{BASE}/billing/history",
            params={"merchant_id": rt_merchant.id},
            headers=super_admin_headers,
        )
        assert response.status_code == 200
        assert response.json()["total"] == 3

    def test_list_billing_history_empty(self, client, super_admin_headers):
        response = client.get(
            f"{BASE}/billing/history", headers=super_admin_headers
        )
        assert response.status_code == 200
        assert response.json()["total"] == 0


# ============================================================================
# Store Subscription Convenience Endpoint
# ============================================================================


class TestAdminStoreSubscription:
    """Tests for GET /api/v1/admin/subscriptions/store/{store_id}."""

    def test_get_subscriptions_for_store(
        self, client, super_admin_headers, rt_subscription, rt_store
    ):
        """Returns subscriptions when store has a merchant with subscriptions."""
        response = client.get(
            f"{BASE}/store/{rt_store.id}",
            headers=super_admin_headers,
        )
        assert response.status_code == 200
        data = response.json()
        assert "subscriptions" in data
        assert len(data["subscriptions"]) >= 1

    def test_get_subscriptions_for_nonexistent_store(
        self, client, super_admin_headers
    ):
        """Returns 404 for non-existent store ID."""
        response = client.get(
            f"{BASE}/store/999999",
            headers=super_admin_headers,
        )
        assert response.status_code == 404


@pytest.fixture
def rt_store(db, rt_merchant):
    """Create a store for route tests."""
    from app.modules.tenancy.models import Store

    store = Store(
        merchant_id=rt_merchant.id,
        store_code=f"RT_{uuid.uuid4().hex[:6].upper()}",
        name="Route Test Store",
        subdomain=f"rt-{uuid.uuid4().hex[:8]}",
        is_active=True,
        is_verified=True,
        created_at=datetime.now(UTC),
        updated_at=datetime.now(UTC),
    )
    db.add(store)
    db.commit()
    db.refresh(store)
    return store
