"""Minimal integration tests for Stripe adapter with mocked responses."""

import os
from unittest.mock import Mock, patch

import pytest
import stripe

from augint_billing_lib.adapters.stripe import StripeAdapter


@pytest.mark.integration
class TestStripeIntegration:
    """Test Stripe adapter with mocked Stripe API."""

    @pytest.fixture
    def stripe_adapter(self):
        """Create StripeAdapter instance with test key."""
        # Use test key or mock key
        test_key = os.environ.get("STRIPE_TEST_KEY", "sk_test_mock123")
        metered_price_id = os.environ.get("STRIPE_METERED_PRICE_ID", "price_test123")
        return StripeAdapter(test_key, metered_price_id)

    @pytest.fixture
    def mock_stripe_customer(self):
        """Create mock Stripe customer."""
        # Return dict like Stripe API does
        return {
            "id": "cus_test123",
            "email": "test@example.com",
            "invoice_settings": {"default_payment_method": "pm_test123"},
        }

    @pytest.fixture
    def mock_stripe_subscription(self):
        """Create mock Stripe subscription."""
        subscription = Mock(spec=stripe.Subscription)
        subscription.id = "sub_test123"
        subscription.status = "active"
        subscription.items = Mock(data=[Mock(id="si_test123", price=Mock(id="price_test123"))])
        return subscription

    @patch("augint_billing_lib.adapters.stripe.StripeAdapter._retrieve_customer")
    def test_has_default_payment_method(self, mock_retrieve, stripe_adapter, mock_stripe_customer):
        """Test checking for default payment method."""
        mock_retrieve.return_value = mock_stripe_customer

        result = stripe_adapter.has_default_payment_method("cus_test123")

        assert result is True
        mock_retrieve.assert_called_once_with("cus_test123")

    @patch("augint_billing_lib.adapters.stripe.StripeAdapter._retrieve_customer")
    def test_has_no_default_payment_method(self, mock_retrieve, stripe_adapter):
        """Test checking when no default payment method."""
        # Return dict like Stripe API does, not an object
        customer = {"invoice_settings": {"default_payment_method": None}}
        mock_retrieve.return_value = customer

        result = stripe_adapter.has_default_payment_method("cus_test123")

        assert result is False

    @patch("augint_billing_lib.adapters.stripe.StripeAdapter._list_subs")
    @patch("augint_billing_lib.adapters.stripe.StripeAdapter._create_sub")
    def test_ensure_metered_subscription_creates_new(self, mock_create, mock_list, stripe_adapter):
        """Test creating new metered subscription when none exists."""
        # No existing subscriptions
        mock_response = Mock()
        mock_response.auto_paging_iter.return_value = []
        mock_list.return_value = mock_response

        # Return dict format for created subscription
        mock_create.return_value = {"id": "sub_test123", "items": {"data": [{"id": "si_test123"}]}}

        result = stripe_adapter.ensure_metered_subscription("cus_test123")

        assert result == "si_test123"
        mock_list.assert_called_once_with(
            customer="cus_test123", status="active", expand=["data.items.data.price"]
        )
        mock_create.assert_called_once()

    @patch("augint_billing_lib.adapters.stripe.StripeAdapter._list_subs")
    def test_ensure_metered_subscription_returns_existing(self, mock_list, stripe_adapter):
        """Test returning existing metered subscription."""
        # Return dict format like Stripe API
        subscription = {
            "id": "sub_test123",
            "items": {
                "data": [{"id": "si_test123", "price": {"recurring": {"usage_type": "metered"}}}]
            },
        }
        mock_response = Mock()
        mock_response.auto_paging_iter.return_value = [subscription]
        mock_list.return_value = mock_response

        result = stripe_adapter.ensure_metered_subscription("cus_test123")

        assert result == "si_test123"
        mock_list.assert_called_once_with(
            customer="cus_test123", status="active", expand=["data.items.data.price"]
        )

    @patch("augint_billing_lib.adapters.stripe.StripeAdapter._list_subs")
    @patch("augint_billing_lib.adapters.stripe.StripeAdapter._modify_sub")
    def test_cancel_subscription_if_any(self, mock_modify, mock_list, stripe_adapter):
        """Test canceling existing subscription."""
        subscription = {"id": "sub_test123"}
        mock_response = Mock()
        mock_response.auto_paging_iter.return_value = [subscription]
        mock_list.return_value = mock_response

        stripe_adapter.cancel_subscription_if_any("cus_test123")

        mock_list.assert_called_once_with(customer="cus_test123", status="active")
        mock_modify.assert_called_once_with("sub_test123", cancel_at_period_end=True)

    @patch("augint_billing_lib.adapters.stripe.StripeAdapter._list_subs")
    def test_cancel_subscription_no_active(self, mock_list, stripe_adapter):
        """Test canceling when no active subscription."""
        mock_response = Mock()
        mock_response.auto_paging_iter.return_value = []
        mock_list.return_value = mock_response

        # Should not raise exception
        stripe_adapter.cancel_subscription_if_any("cus_test123")

        mock_list.assert_called_once_with(customer="cus_test123", status="active")

    @patch("augint_billing_lib.adapters.stripe.stripe")
    def test_report_usage(self, mock_stripe, stripe_adapter):
        """Test reporting usage to Stripe via meter events."""
        # Mock subscription item and subscription retrieval
        mock_sub_item = Mock()
        mock_sub_item.subscription = "sub_test123"
        mock_stripe.SubscriptionItem.retrieve.return_value = mock_sub_item

        mock_subscription = Mock()
        mock_subscription.customer = "cus_test123"
        mock_stripe.Subscription.retrieve.return_value = mock_subscription

        # Mock the meter event response
        mock_response = {
            "id": "evt_test123",
            "object": "billing.meter_event",
            "event_name": "api_usage",
            "payload": {"stripe_customer_id": "cus_test123", "value": "1000"},
        }
        mock_stripe.billing.MeterEvent.create.return_value = mock_response

        # Use timestamp as int
        timestamp = 1704067200  # Fixed timestamp for test
        result = stripe_adapter.report_usage(
            subscription_item_id="si_test123",
            units=1000,
            timestamp=timestamp,
            idempotency_key="key_test123",
        )

        assert result == mock_response  # report_usage now returns the meter event response
        assert result["id"] == "evt_test123"
        mock_stripe.billing.MeterEvent.create.assert_called_once_with(
            event_name="api_usage",
            payload={"stripe_customer_id": "cus_test123", "value": "1000"},
            timestamp=timestamp,
            idempotency_key="key_test123",
        )

    @patch("augint_billing_lib.adapters.stripe.StripeAdapter._list_prices")
    def test_discover_metered_price_id(self, mock_list, stripe_adapter):
        """Test discovering metered price ID."""
        mock_price = {"id": "price_discovered123", "recurring": {"usage_type": "metered"}}
        mock_response = Mock()
        mock_response.auto_paging_iter.return_value = [mock_price]
        mock_list.return_value = mock_response

        result = stripe_adapter.discover_metered_price_id()

        assert result == "price_discovered123"
        mock_list.assert_called_once_with(active=True, limit=100)

    @patch("augint_billing_lib.adapters.stripe.StripeAdapter._list_prices")
    def test_discover_metered_price_id_not_found(self, mock_list, stripe_adapter):
        """Test when no metered price found."""
        mock_response = Mock()
        mock_response.auto_paging_iter.return_value = []
        mock_list.return_value = mock_response

        result = stripe_adapter.discover_metered_price_id()
        assert result is None
