"""
Unit tests for Payments Views.

Tests view methods with mocks to avoid database access.
Comprehensive coverage for all views, actions, permissions, and business logic.
"""
from unittest.mock import Mock, patch, MagicMock, PropertyMock
from rest_framework.test import APIRequestFactory, force_authenticate
from rest_framework.request import Request
from rest_framework import status
import pytest
from decimal import Decimal
from datetime import datetime
import stripe


# ============================================================================
# Helper Function Tests
# ============================================================================

class TestMaskKeyHelper:
    """Test the mask_key helper function."""

    def test_mask_key_empty_string(self):
        """Test mask_key with empty string."""
        from smoothschedule.commerce.payments.views import mask_key

        result = mask_key('')
        assert result == ''

    def test_mask_key_none(self):
        """Test mask_key with None."""
        from smoothschedule.commerce.payments.views import mask_key

        result = mask_key(None)
        assert result == ''

    def test_mask_key_short_key(self):
        """Test mask_key with key shorter than 12 chars."""
        from smoothschedule.commerce.payments.views import mask_key

        result = mask_key('short')
        assert result == '*****'  # All masked

    def test_mask_key_exactly_12_chars(self):
        """Test mask_key with exactly 12 characters."""
        from smoothschedule.commerce.payments.views import mask_key

        result = mask_key('123456789012')
        assert result == '************'  # All masked (<=12)

    def test_mask_key_long_key(self):
        """Test mask_key with key longer than 12 chars."""
        from smoothschedule.commerce.payments.views import mask_key

        # 20 char key: first 7 + (20-11=9 stars) + last 4
        result = mask_key('sk_test_12345678901234567890')
        assert result.startswith('sk_test')
        assert result.endswith('7890')
        assert '*' in result

    def test_mask_key_typical_stripe_key(self):
        """Test mask_key with typical Stripe key format."""
        from smoothschedule.commerce.payments.views import mask_key

        key = 'sk_test_51ABC123XYZ'
        result = mask_key(key)
        assert result[:7] == 'sk_test'
        assert result[-4:] == '3XYZ'


# ============================================================================
# PaymentConfigStatusView Tests
# ============================================================================

class TestPaymentConfigStatusView:
    """Test PaymentConfigStatusView."""

    def test_returns_none_mode_when_not_configured(self):
        """Test response when no payment mode configured."""
        from smoothschedule.commerce.payments.views import PaymentConfigStatusView

        # Arrange
        factory = APIRequestFactory()
        request = factory.get('/payments/config/status/')
        request.user = Mock(is_authenticated=True)

        mock_tenant = Mock()
        mock_tenant.payment_mode = 'none'
        mock_tenant.stripe_secret_key = None
        mock_tenant.stripe_connect_id = None
        mock_tenant.subscription_tier = 'free'
        mock_tenant.can_accept_payments = False

        view = PaymentConfigStatusView()
        view.request = request
        view.tenant = mock_tenant

        # Act
        response = view.get(request)

        # Assert
        assert response.data['payment_mode'] == 'none'
        assert response.data['can_accept_payments'] is False
        assert response.data['api_keys'] is None
        assert response.data['connect_account'] is None

    def test_returns_direct_api_mode_info(self):
        """Test response with direct API mode configured."""
        from smoothschedule.commerce.payments.views import PaymentConfigStatusView

        # Arrange
        factory = APIRequestFactory()
        request = factory.get('/payments/config/status/')
        request.user = Mock(is_authenticated=True)

        mock_tenant = Mock()
        mock_tenant.id = 1
        mock_tenant.payment_mode = 'direct_api'
        mock_tenant.stripe_secret_key = 'sk_test_123456789012345678901234'
        mock_tenant.stripe_publishable_key = 'pk_test_123456789012345678901234'
        mock_tenant.stripe_api_key_status = 'active'
        mock_tenant.stripe_api_key_validated_at = None
        mock_tenant.stripe_api_key_account_id = 'acct_123'
        mock_tenant.stripe_api_key_account_name = 'Test Business'
        mock_tenant.stripe_api_key_error = None
        mock_tenant.created_on = None
        mock_tenant.subscription_tier = 'pro'
        mock_tenant.can_accept_payments = True
        mock_tenant.stripe_connect_id = None

        view = PaymentConfigStatusView()
        view.request = request
        view.tenant = mock_tenant

        # Act
        response = view.get(request)

        # Assert
        assert response.data['payment_mode'] == 'direct_api'
        assert response.data['stripe_configured'] is True
        assert response.data['can_accept_payments'] is True
        assert response.data['api_keys'] is not None
        assert response.data['api_keys']['status'] == 'active'

    def test_returns_connect_mode_info(self):
        """Test response with Connect mode configured."""
        from smoothschedule.commerce.payments.views import PaymentConfigStatusView

        # Arrange
        factory = APIRequestFactory()
        request = factory.get('/payments/config/status/')
        request.user = Mock(is_authenticated=True)

        mock_tenant = Mock()
        mock_tenant.id = 1
        mock_tenant.name = 'Test Business'
        mock_tenant.schema_name = 'test'
        mock_tenant.payment_mode = 'connect'
        mock_tenant.stripe_connect_id = 'acct_123'
        mock_tenant.stripe_connect_status = 'active'
        mock_tenant.stripe_charges_enabled = True
        mock_tenant.stripe_payouts_enabled = True
        mock_tenant.stripe_details_submitted = True
        mock_tenant.stripe_onboarding_complete = True
        mock_tenant.stripe_secret_key = None
        mock_tenant.created_on = None
        mock_tenant.subscription_tier = 'pro'
        mock_tenant.can_accept_payments = True

        view = PaymentConfigStatusView()
        view.request = request
        view.tenant = mock_tenant

        # Act
        response = view.get(request)

        # Assert
        assert response.data['payment_mode'] == 'connect'
        assert response.data['stripe_configured'] is True
        assert response.data['can_accept_payments'] is True
        assert response.data['connect_account'] is not None
        assert response.data['connect_account']['charges_enabled'] is True

    def test_not_ready_when_connect_charges_disabled(self):
        """Test that payments not ready when Connect charges disabled."""
        from smoothschedule.commerce.payments.views import PaymentConfigStatusView

        # Arrange
        factory = APIRequestFactory()
        request = factory.get('/payments/config/status/')
        request.user = Mock(is_authenticated=True)

        mock_tenant = Mock()
        mock_tenant.id = 1
        mock_tenant.name = 'Test Business'
        mock_tenant.schema_name = 'test'
        mock_tenant.payment_mode = 'connect'
        mock_tenant.stripe_connect_id = 'acct_123'
        mock_tenant.stripe_connect_status = 'pending'
        mock_tenant.stripe_charges_enabled = False  # Not enabled yet
        mock_tenant.stripe_payouts_enabled = False
        mock_tenant.stripe_details_submitted = False
        mock_tenant.stripe_onboarding_complete = False
        mock_tenant.stripe_secret_key = None
        mock_tenant.created_on = None
        mock_tenant.subscription_tier = 'pro'
        mock_tenant.can_accept_payments = True

        view = PaymentConfigStatusView()
        view.request = request
        view.tenant = mock_tenant

        # Act
        response = view.get(request)

        # Assert
        assert response.data['stripe_configured'] is False
        assert response.data['can_accept_payments'] is False

    def test_not_ready_when_tier_disallows_payments(self):
        """Test can_accept_payments is False when tier doesn't allow it."""
        from smoothschedule.commerce.payments.views import PaymentConfigStatusView

        factory = APIRequestFactory()
        request = factory.get('/payments/config/status/')
        request.user = Mock(is_authenticated=True)

        mock_tenant = Mock()
        mock_tenant.id = 1
        mock_tenant.payment_mode = 'direct_api'
        mock_tenant.stripe_secret_key = 'sk_test_key'
        mock_tenant.stripe_publishable_key = 'pk_test_key'
        mock_tenant.stripe_api_key_status = 'active'
        mock_tenant.stripe_connect_id = None
        mock_tenant.subscription_tier = 'free'
        mock_tenant.can_accept_payments = False  # Tier doesn't allow

        view = PaymentConfigStatusView()
        view.request = request
        view.tenant = mock_tenant

        # Act
        response = view.get(request)

        # Assert
        assert response.data['stripe_configured'] is True
        assert response.data['tier_allows_payments'] is False
        assert response.data['can_accept_payments'] is False


# ============================================================================
# SubscriptionPlansView Tests
# ============================================================================

class TestSubscriptionPlansView:
    """Test SubscriptionPlansView."""

    def test_view_has_correct_permissions(self):
        """Test that SubscriptionPlansView requires authentication."""
        from smoothschedule.commerce.payments.views import SubscriptionPlansView
        from rest_framework.permissions import IsAuthenticated

        assert IsAuthenticated in SubscriptionPlansView.permission_classes

    @patch('smoothschedule.commerce.payments.views.SubscriptionPlan.objects.filter')
    def test_get_returns_base_plans_and_addons(self, mock_filter):
        """Test GET returns both base plans and addons."""
        from smoothschedule.commerce.payments.views import SubscriptionPlansView

        # Arrange
        mock_plan = Mock()
        mock_plan.id = 1
        mock_plan.name = 'Pro'
        mock_plan.description = 'Pro plan'
        mock_plan.plan_type = 'base'
        mock_plan.business_tier = 'Pro'
        mock_plan.price_monthly = Decimal('99.00')
        mock_plan.price_yearly = Decimal('999.00')
        mock_plan.features = ['feature1']
        mock_plan.permissions = {'can_accept_payments': True}
        mock_plan.limits = {}
        mock_plan.transaction_fee_percent = Decimal('5.0')
        mock_plan.transaction_fee_fixed = Decimal('0.30')
        mock_plan.is_most_popular = True
        mock_plan.show_price = True
        mock_plan.stripe_price_id = 'price_123'

        mock_addon = Mock()
        mock_addon.id = 2
        mock_addon.name = 'Extra Storage'
        mock_addon.description = 'More storage'
        mock_addon.plan_type = 'addon'
        mock_addon.business_tier = None
        mock_addon.price_monthly = Decimal('10.00')
        mock_addon.price_yearly = Decimal('100.00')
        mock_addon.features = []
        mock_addon.permissions = {'can_use_advanced_reports': True}
        mock_addon.limits = {}
        mock_addon.transaction_fee_percent = Decimal('0.0')
        mock_addon.transaction_fee_fixed = Decimal('0.0')
        mock_addon.is_most_popular = False
        mock_addon.show_price = True
        mock_addon.stripe_price_id = 'price_456'

        def filter_side_effect(**kwargs):
            plan_type = kwargs.get('plan_type')
            mock_queryset = Mock()
            if plan_type == 'base':
                mock_queryset.__iter__ = Mock(return_value=iter([mock_plan]))
                mock_queryset.filter.return_value.first.return_value = mock_plan
            else:
                mock_queryset.__iter__ = Mock(return_value=iter([mock_addon]))
            mock_queryset.order_by.return_value = mock_queryset
            return mock_queryset

        mock_filter.side_effect = filter_side_effect

        factory = APIRequestFactory()
        request = factory.get('/payments/plans/')
        request.user = Mock(is_authenticated=True)
        request.tenant = Mock(subscription_tier='Free', can_use_advanced_reports=False)

        view = SubscriptionPlansView.as_view()

        # Act
        response = view(request)

        # Assert
        assert response.status_code == status.HTTP_200_OK
        assert 'plans' in response.data
        assert 'addons' in response.data


# ============================================================================
# CreateCheckoutSessionView Tests
# ============================================================================

class TestCreateCheckoutSessionView:
    """Test CreateCheckoutSessionView."""

    def test_requires_plan_id(self):
        """Test that plan_id is required."""
        from smoothschedule.commerce.payments.views import CreateCheckoutSessionView

        factory = APIRequestFactory()
        data = {}
        wsgi_request = factory.post('/payments/checkout/', data, format='json')
        wsgi_request.user = Mock(is_authenticated=True)
        wsgi_request.tenant = Mock()
        wsgi_request.data = data

        view = CreateCheckoutSessionView()
        view.request = wsgi_request

        # Act
        response = view.post(wsgi_request)

        # Assert
        assert response.status_code == status.HTTP_400_BAD_REQUEST
        assert 'plan_id' in response.data['error']

    @patch('smoothschedule.commerce.payments.views.SubscriptionPlan.objects.get')
    def test_returns_404_for_invalid_plan(self, mock_get):
        """Test 404 when plan doesn't exist."""
        from smoothschedule.commerce.payments.views import CreateCheckoutSessionView
        from smoothschedule.platform.admin.models import SubscriptionPlan

        # Arrange
        mock_get.side_effect = SubscriptionPlan.DoesNotExist()

        factory = APIRequestFactory()
        data = {'plan_id': 999}
        wsgi_request = factory.post('/payments/checkout/', data, format='json')
        wsgi_request.user = Mock(is_authenticated=True)
        wsgi_request.tenant = Mock()
        wsgi_request.data = data

        view = CreateCheckoutSessionView()
        view.request = wsgi_request

        # Act
        response = view.post(wsgi_request)

        # Assert
        assert response.status_code == status.HTTP_404_NOT_FOUND

    @patch('smoothschedule.commerce.payments.views.stripe.checkout.Session.create')
    @patch('smoothschedule.commerce.payments.views.stripe.Customer.create')
    @patch('smoothschedule.commerce.payments.views.SubscriptionPlan.objects.get')
    @patch('smoothschedule.commerce.payments.views.settings')
    def test_creates_checkout_session_successfully(self, mock_settings, mock_get_plan, mock_customer_create, mock_session_create):
        """Test successful checkout session creation."""
        from smoothschedule.commerce.payments.views import CreateCheckoutSessionView

        # Arrange
        mock_settings.STRIPE_SECRET_KEY = 'sk_test_key'
        mock_settings.DEBUG = True

        mock_plan = Mock()
        mock_plan.id = 1
        mock_plan.stripe_price_id = 'price_123'
        mock_plan.plan_type = 'base'
        mock_get_plan.return_value = mock_plan

        mock_customer = Mock(id='cus_123')
        mock_customer_create.return_value = mock_customer

        mock_session = Mock()
        mock_session.url = 'https://checkout.stripe.com/session_123'
        mock_session.id = 'cs_123'
        mock_session_create.return_value = mock_session

        mock_tenant = Mock()
        mock_tenant.id = 1
        mock_tenant.stripe_customer_id = None
        mock_tenant.contact_email = 'test@example.com'
        mock_tenant.name = 'Test Business'
        mock_tenant.schema_name = 'test'

        factory = APIRequestFactory()
        data = {'plan_id': 1}
        wsgi_request = factory.post('/payments/checkout/', data, format='json')
        wsgi_request.user = Mock(email='user@example.com', is_authenticated=True)
        wsgi_request.tenant = mock_tenant
        wsgi_request.data = data

        view = CreateCheckoutSessionView()
        view.request = wsgi_request

        # Act
        response = view.post(wsgi_request)

        # Assert
        assert response.status_code == status.HTTP_200_OK
        assert response.data['checkout_url'] == 'https://checkout.stripe.com/session_123'
        assert response.data['session_id'] == 'cs_123'
        mock_session_create.assert_called_once()

    @patch('smoothschedule.commerce.payments.views.SubscriptionPlan.objects.get')
    def test_returns_400_when_plan_has_no_stripe_price(self, mock_get):
        """Test error when plan doesn't have Stripe price configured."""
        from smoothschedule.commerce.payments.views import CreateCheckoutSessionView

        # Arrange
        mock_plan = Mock()
        mock_plan.stripe_price_id = None
        mock_get.return_value = mock_plan

        factory = APIRequestFactory()
        data = {'plan_id': 1}
        wsgi_request = factory.post('/payments/checkout/', data, format='json')
        wsgi_request.user = Mock(is_authenticated=True)
        wsgi_request.tenant = Mock()
        wsgi_request.data = data

        view = CreateCheckoutSessionView()
        view.request = wsgi_request

        # Act
        response = view.post(wsgi_request)

        # Assert
        assert response.status_code == status.HTTP_400_BAD_REQUEST
        assert 'not available for purchase' in response.data['error']


# ============================================================================
# SubscriptionsView Tests
# ============================================================================

class TestSubscriptionsView:
    """Test SubscriptionsView."""

    @patch('smoothschedule.commerce.payments.views.settings')
    def test_returns_empty_when_no_customer_id(self, mock_settings):
        """Test response when tenant has no Stripe customer ID."""
        from smoothschedule.commerce.payments.views import SubscriptionsView

        mock_settings.STRIPE_SECRET_KEY = 'sk_test_key'

        factory = APIRequestFactory()
        request = factory.get('/payments/subscriptions/')
        request.user = Mock(is_authenticated=True)
        request.tenant = Mock(stripe_customer_id=None)

        view = SubscriptionsView()
        view.request = request

        # Act
        response = view.get(request)

        # Assert
        assert response.status_code == status.HTTP_200_OK
        assert response.data['subscriptions'] == []
        assert response.data['has_active_subscription'] is False

    @patch('smoothschedule.commerce.payments.views.stripe.Product.retrieve')
    @patch('smoothschedule.commerce.payments.views.stripe.Subscription.list')
    @patch('smoothschedule.commerce.payments.views.settings')
    def test_lists_active_subscriptions(self, mock_settings, mock_sub_list, mock_product_retrieve):
        """Test listing active subscriptions."""
        from smoothschedule.commerce.payments.views import SubscriptionsView

        # Arrange
        mock_settings.STRIPE_SECRET_KEY = 'sk_test_key'

        # Create a properly structured mock for price with fixed attributes
        mock_recurring = Mock()
        mock_recurring.interval = 'month'

        mock_price = Mock()
        mock_price.unit_amount = 9900  # Integer value for division
        mock_price.currency = 'usd'
        mock_price.recurring = mock_recurring
        mock_price.product = 'prod_123'

        # Create item dict (not Mock) to avoid attribute access issues
        mock_item = {
            'price': mock_price,
            'current_period_start': 1704067200,  # Jan 1, 2024
            'current_period_end': 1706745600  # Feb 1, 2024
        }

        mock_sub = Mock()
        mock_sub.id = 'sub_123'
        mock_sub.status = 'active'
        mock_sub.__getitem__ = lambda self, key: {'items': {'data': [mock_item]}, 'start_date': 1704067200, 'billing_cycle_anchor': 1706745600}.get(key)
        mock_sub.get = lambda key, default=None: {'items': {'data': [mock_item]}, 'start_date': 1704067200, 'billing_cycle_anchor': 1706745600}.get(key, default)
        mock_sub.cancel_at_period_end = False
        mock_sub.cancel_at = None
        mock_sub.canceled_at = None

        mock_sub_list_result = Mock()
        mock_sub_list_result.data = [mock_sub]
        mock_sub_list.return_value = mock_sub_list_result

        mock_product = Mock()
        mock_product.name = 'Pro Plan'
        mock_product.metadata = {'plan_type': 'base'}
        mock_product_retrieve.return_value = mock_product

        factory = APIRequestFactory()
        request = factory.get('/payments/subscriptions/')
        request.user = Mock(is_authenticated=True)
        request.tenant = Mock(stripe_customer_id='cus_123')

        view = SubscriptionsView()
        view.request = request

        # Act
        response = view.get(request)

        # Assert
        assert response.status_code == status.HTTP_200_OK
        assert response.data['has_active_subscription'] is True
        assert len(response.data['subscriptions']) == 1
        assert response.data['subscriptions'][0]['plan_name'] == 'Pro Plan'


# ============================================================================
# CancelSubscriptionView Tests
# ============================================================================

class TestCancelSubscriptionView:
    """Test CancelSubscriptionView."""

    def test_requires_subscription_id(self):
        """Test that subscription_id is required."""
        from smoothschedule.commerce.payments.views import CancelSubscriptionView

        factory = APIRequestFactory()
        data = {}
        wsgi_request = factory.post('/payments/subscriptions/cancel/', data, format='json')
        wsgi_request.user = Mock(is_authenticated=True)
        wsgi_request.tenant = Mock()
        wsgi_request.data = data

        view = CancelSubscriptionView()
        view.request = wsgi_request

        # Act
        response = view.post(wsgi_request)

        # Assert
        assert response.status_code == status.HTTP_400_BAD_REQUEST
        assert 'subscription_id' in response.data['error']

    @patch('smoothschedule.commerce.payments.views.stripe.Subscription.modify')
    @patch('smoothschedule.commerce.payments.views.stripe.Subscription.retrieve')
    @patch('smoothschedule.commerce.payments.views.settings')
    def test_cancel_at_period_end(self, mock_settings, mock_retrieve, mock_modify):
        """Test canceling subscription at period end."""
        from smoothschedule.commerce.payments.views import CancelSubscriptionView

        # Arrange
        mock_settings.STRIPE_SECRET_KEY = 'sk_test_key'

        mock_sub = Mock()
        mock_sub.customer = 'cus_123'
        mock_retrieve.return_value = mock_sub

        mock_canceled = Mock()
        mock_canceled.__getitem__ = lambda self, key: {'cancel_at_period_end': True, 'items': {'data': [{'current_period_end': 1706745600}]}}.get(key)
        mock_canceled.get = lambda key, default=None: {'items': {'data': [{'current_period_end': 1706745600}]}, 'billing_cycle_anchor': 1706745600}.get(key, default)
        mock_modify.return_value = mock_canceled

        factory = APIRequestFactory()
        data = {
            'subscription_id': 'sub_123',
            'immediate': False
        }
        wsgi_request = factory.post('/payments/subscriptions/cancel/', data, format='json')
        wsgi_request.user = Mock(is_authenticated=True)
        wsgi_request.tenant = Mock(stripe_customer_id='cus_123')
        wsgi_request.data = data

        view = CancelSubscriptionView()
        view.request = wsgi_request

        # Act
        response = view.post(wsgi_request)

        # Assert
        assert response.status_code == status.HTTP_200_OK
        assert response.data['success'] is True
        assert 'end of the billing period' in response.data['message']

    @patch('smoothschedule.commerce.payments.views.stripe.Subscription.cancel')
    @patch('smoothschedule.commerce.payments.views.stripe.Subscription.retrieve')
    @patch('smoothschedule.commerce.payments.views.settings')
    def test_cancel_immediately(self, mock_settings, mock_retrieve, mock_cancel):
        """Test immediate subscription cancellation."""
        from smoothschedule.commerce.payments.views import CancelSubscriptionView

        # Arrange
        mock_settings.STRIPE_SECRET_KEY = 'sk_test_key'

        mock_sub = Mock()
        mock_sub.customer = 'cus_123'
        mock_retrieve.return_value = mock_sub

        mock_canceled = Mock()
        mock_canceled.__getitem__ = lambda self, key: {'cancel_at_period_end': False}.get(key)
        mock_canceled.get = lambda key, default=None: {'items': {'data': []}}.get(key, default)
        mock_cancel.return_value = mock_canceled

        factory = APIRequestFactory()
        data = {
            'subscription_id': 'sub_123',
            'immediate': True
        }
        wsgi_request = factory.post('/payments/subscriptions/cancel/', data, format='json')
        wsgi_request.user = Mock(is_authenticated=True)
        wsgi_request.tenant = Mock(stripe_customer_id='cus_123')
        wsgi_request.data = data

        view = CancelSubscriptionView()
        view.request = wsgi_request

        # Act
        response = view.post(wsgi_request)

        # Assert
        assert response.status_code == status.HTTP_200_OK
        assert 'immediately' in response.data['message']


# ============================================================================
# ReactivateSubscriptionView Tests
# ============================================================================

class TestReactivateSubscriptionView:
    """Test ReactivateSubscriptionView."""

    @patch('smoothschedule.commerce.payments.views.stripe.Subscription.modify')
    @patch('smoothschedule.commerce.payments.views.stripe.Subscription.retrieve')
    @patch('smoothschedule.commerce.payments.views.settings')
    def test_reactivates_subscription(self, mock_settings, mock_retrieve, mock_modify):
        """Test successful reactivation."""
        from smoothschedule.commerce.payments.views import ReactivateSubscriptionView

        # Arrange
        mock_settings.STRIPE_SECRET_KEY = 'sk_test_key'

        mock_sub = Mock()
        mock_sub.customer = 'cus_123'
        mock_retrieve.return_value = mock_sub

        mock_reactivated = Mock()
        mock_modify.return_value = mock_reactivated

        factory = APIRequestFactory()
        data = {
            'subscription_id': 'sub_123'
        }
        wsgi_request = factory.post('/payments/subscriptions/reactivate/', data, format='json')
        wsgi_request.user = Mock(is_authenticated=True)
        wsgi_request.tenant = Mock(stripe_customer_id='cus_123')
        wsgi_request.data = data

        view = ReactivateSubscriptionView()
        view.request = wsgi_request

        # Act
        response = view.post(wsgi_request)

        # Assert
        assert response.status_code == status.HTTP_200_OK
        assert response.data['success'] is True
        mock_modify.assert_called_once_with('sub_123', cancel_at_period_end=False)


# ============================================================================
# ApiKeysView Tests
# ============================================================================

class TestApiKeysView:
    """Test ApiKeysView."""

    def test_get_returns_not_configured_when_no_keys(self):
        """Test GET response when no API keys configured."""
        from smoothschedule.commerce.payments.views import ApiKeysView

        # Arrange
        factory = APIRequestFactory()
        request = factory.get('/payments/api-keys/')
        request.user = Mock(is_authenticated=True)

        mock_tenant = Mock()
        mock_tenant.stripe_secret_key = None

        view = ApiKeysView()
        view.request = request
        view.tenant = mock_tenant

        # Act
        response = view.get(request)

        # Assert
        assert response.status_code == status.HTTP_200_OK
        assert response.data['configured'] is False

    def test_get_returns_masked_keys_when_configured(self):
        """Test GET response returns masked keys."""
        from smoothschedule.commerce.payments.views import ApiKeysView

        # Arrange
        factory = APIRequestFactory()
        request = factory.get('/payments/api-keys/')
        request.user = Mock(is_authenticated=True)

        mock_tenant = Mock()
        mock_tenant.id = 1
        mock_tenant.stripe_secret_key = 'sk_test_1234567890abcdef'
        mock_tenant.stripe_publishable_key = 'pk_test_1234567890abcdef'
        mock_tenant.stripe_api_key_status = 'active'
        mock_tenant.stripe_api_key_validated_at = None
        mock_tenant.stripe_api_key_account_id = 'acct_123'
        mock_tenant.stripe_api_key_account_name = 'Test'
        mock_tenant.stripe_api_key_error = None

        view = ApiKeysView()
        view.request = request
        view.tenant = mock_tenant

        # Act
        response = view.get(request)

        # Assert
        assert response.status_code == status.HTTP_200_OK
        assert response.data['configured'] is True
        assert response.data['status'] == 'active'
        assert 'sk_test' in response.data['secret_key_masked']
        assert '*' in response.data['secret_key_masked']

    @patch('smoothschedule.commerce.payments.views.validate_stripe_keys')
    @patch('smoothschedule.commerce.payments.views.timezone')
    def test_post_saves_and_validates_keys(self, mock_timezone, mock_validate):
        """Test POST saves and validates keys."""
        from smoothschedule.commerce.payments.views import ApiKeysView

        # Arrange
        mock_now = Mock()
        mock_timezone.now.return_value = mock_now

        mock_validate.return_value = {
            'valid': True,
            'account_id': 'acct_123',
            'account_name': 'Test Business'
        }

        mock_tenant = Mock()
        mock_tenant.id = 1

        factory = APIRequestFactory()
        data = {
            'secret_key': 'sk_test_valid',
            'publishable_key': 'pk_test_valid'
        }
        wsgi_request = factory.post('/payments/api-keys/', data, format='json')
        wsgi_request.user = Mock(is_authenticated=True)
        wsgi_request.data = data

        view = ApiKeysView()
        view.request = wsgi_request
        view.tenant = mock_tenant

        # Act
        response = view.post(wsgi_request)

        # Assert
        assert response.status_code == status.HTTP_201_CREATED
        assert mock_tenant.stripe_secret_key == 'sk_test_valid'
        assert mock_tenant.stripe_publishable_key == 'pk_test_valid'
        assert mock_tenant.stripe_api_key_status == 'active'
        assert mock_tenant.payment_mode == 'direct_api'
        mock_tenant.save.assert_called_once()

    def test_post_requires_both_keys(self):
        """Test POST validates both keys are provided."""
        from smoothschedule.commerce.payments.views import ApiKeysView

        factory = APIRequestFactory()
        data = {
            'secret_key': 'sk_test_key'
            # Missing publishable_key
        }
        wsgi_request = factory.post('/payments/api-keys/', data, format='json')
        wsgi_request.user = Mock(is_authenticated=True)
        wsgi_request.data = data

        view = ApiKeysView()
        view.request = wsgi_request
        view.tenant = Mock()

        # Act
        response = view.post(wsgi_request)

        # Assert
        assert response.status_code == status.HTTP_400_BAD_REQUEST


# ============================================================================
# validate_stripe_keys Function Tests
# ============================================================================

class TestValidateStripeKeysFunction:
    """Test validate_stripe_keys helper function."""

    @patch('smoothschedule.commerce.payments.views.stripe.Account.retrieve')
    @patch('smoothschedule.commerce.payments.views.settings')
    def test_returns_valid_for_correct_keys(self, mock_settings, mock_retrieve):
        """Test validation succeeds with correct keys."""
        from smoothschedule.commerce.payments.views import validate_stripe_keys

        # Arrange
        mock_settings.STRIPE_SECRET_KEY = 'sk_platform_key'
        mock_account = Mock()
        mock_account.id = 'acct_123'
        mock_account.get.return_value = {'name': 'Test Business'}
        mock_retrieve.return_value = mock_account

        # Act
        result = validate_stripe_keys('sk_test_valid', 'pk_test_valid')

        # Assert
        assert result['valid'] is True
        assert result['account_id'] == 'acct_123'

    @patch('smoothschedule.commerce.payments.views.stripe.Account.retrieve')
    def test_returns_invalid_for_wrong_publishable_key_format(self, mock_retrieve):
        """Test validation fails for incorrect publishable key format."""
        from smoothschedule.commerce.payments.views import validate_stripe_keys

        # Arrange
        mock_account = Mock()
        mock_account.id = 'acct_123'
        mock_retrieve.return_value = mock_account

        # Act
        result = validate_stripe_keys('sk_test_valid', 'sk_test_wrong')

        # Assert
        assert result['valid'] is False
        assert 'publishable key format' in result['error']

    @patch('smoothschedule.commerce.payments.views.stripe.Account.retrieve')
    @patch('smoothschedule.commerce.payments.views.settings')
    def test_returns_invalid_for_authentication_error(self, mock_settings, mock_retrieve):
        """Test validation fails for invalid secret key."""
        from smoothschedule.commerce.payments.views import validate_stripe_keys

        # Arrange
        mock_settings.STRIPE_SECRET_KEY = 'sk_platform_key'
        mock_retrieve.side_effect = stripe.error.AuthenticationError('Invalid key')

        # Act
        result = validate_stripe_keys('sk_test_bad', 'pk_test_valid')

        # Assert
        assert result['valid'] is False
        assert 'Invalid secret key' in result['error']

    @patch('smoothschedule.commerce.payments.views.stripe.Account.retrieve')
    @patch('smoothschedule.commerce.payments.views.settings')
    def test_handles_generic_stripe_error(self, mock_settings, mock_retrieve):
        """Test handles generic Stripe errors."""
        from smoothschedule.commerce.payments.views import validate_stripe_keys

        # Arrange
        mock_settings.STRIPE_SECRET_KEY = 'sk_platform_key'
        mock_retrieve.side_effect = stripe.error.StripeError('Generic error')

        # Act
        result = validate_stripe_keys('sk_test_key', 'pk_test_valid')

        # Assert
        assert result['valid'] is False
        assert 'Generic error' in result['error']


# ============================================================================
# ApiKeysValidateView Tests
# ============================================================================

class TestApiKeysValidateView:
    """Test ApiKeysValidateView."""

    @patch('smoothschedule.commerce.payments.views.validate_stripe_keys')
    def test_validates_keys_without_saving(self, mock_validate):
        """Test validation without saving."""
        from smoothschedule.commerce.payments.views import ApiKeysValidateView

        # Arrange
        mock_validate.return_value = {
            'valid': True,
            'account_id': 'acct_123'
        }

        factory = APIRequestFactory()
        data = {
            'secret_key': 'sk_test_key',
            'publishable_key': 'pk_test_key'
        }
        wsgi_request = factory.post('/payments/api-keys/validate/', data, format='json')
        wsgi_request.user = Mock(is_authenticated=True)
        wsgi_request.data = data

        view = ApiKeysValidateView()
        view.request = wsgi_request

        # Act
        response = view.post(wsgi_request)

        # Assert
        assert response.status_code == status.HTTP_200_OK
        assert response.data['valid'] is True


# ============================================================================
# ApiKeysRevalidateView Tests
# ============================================================================

class TestApiKeysRevalidateView:
    """Test ApiKeysRevalidateView."""

    @patch('smoothschedule.commerce.payments.views.stripe.Account.retrieve')
    @patch('smoothschedule.commerce.payments.views.timezone')
    @patch('smoothschedule.commerce.payments.views.settings')
    def test_revalidates_stored_keys(self, mock_settings, mock_timezone, mock_retrieve):
        """Test revalidation of stored keys."""
        from smoothschedule.commerce.payments.views import ApiKeysRevalidateView

        # Arrange
        mock_settings.STRIPE_SECRET_KEY = 'sk_platform_key'
        mock_now = Mock()
        mock_timezone.now.return_value = mock_now

        mock_account = Mock()
        mock_account.id = 'acct_123'
        mock_account.get.return_value = {'name': 'Test Business'}
        mock_retrieve.return_value = mock_account

        mock_tenant = Mock()
        mock_tenant.stripe_secret_key = 'sk_test_key'

        factory = APIRequestFactory()
        request = factory.post('/payments/api-keys/revalidate/', {}, format='json')
        request.user = Mock(is_authenticated=True)
        request.tenant = mock_tenant

        view = ApiKeysRevalidateView()
        view.request = request

        # Act
        response = view.post(request)

        # Assert
        assert response.status_code == status.HTTP_200_OK
        assert response.data['valid'] is True
        assert mock_tenant.stripe_api_key_status == 'active'


# ============================================================================
# ApiKeysDeleteView Tests
# ============================================================================

class TestApiKeysDeleteView:
    """Test ApiKeysDeleteView."""

    def test_deletes_keys(self):
        """Test key deletion."""
        from smoothschedule.commerce.payments.views import ApiKeysDeleteView

        # Arrange
        mock_tenant = Mock()
        mock_tenant.payment_mode = 'direct_api'
        mock_tenant.stripe_secret_key = 'sk_test_key'

        factory = APIRequestFactory()
        request = factory.delete('/payments/api-keys/delete/')
        request.user = Mock(is_authenticated=True)
        request.tenant = mock_tenant

        view = ApiKeysDeleteView()
        view.request = request

        # Act
        response = view.delete(request)

        # Assert
        assert response.status_code == status.HTTP_200_OK
        assert mock_tenant.stripe_secret_key == ''
        assert mock_tenant.payment_mode == 'none'


# ============================================================================
# ConnectStatusView Tests
# ============================================================================

class TestConnectStatusView:
    """Test ConnectStatusView."""

    def test_returns_404_when_no_connect_account(self):
        """Test 404 when no Connect account exists."""
        from smoothschedule.commerce.payments.views import ConnectStatusView

        factory = APIRequestFactory()
        request = factory.get('/payments/connect/status/')
        request.user = Mock(is_authenticated=True)
        request.tenant = Mock(stripe_connect_id=None)

        view = ConnectStatusView()
        view.request = request

        # Act
        response = view.get(request)

        # Assert
        assert response.status_code == status.HTTP_404_NOT_FOUND


# ============================================================================
# ConnectOnboardView Tests
# ============================================================================

class TestConnectOnboardView:
    """Test ConnectOnboardView."""

    def test_requires_refresh_and_return_urls(self):
        """Test that both URLs are required."""
        from smoothschedule.commerce.payments.views import ConnectOnboardView

        factory = APIRequestFactory()
        data = {}
        wsgi_request = factory.post('/payments/connect/onboard/', data, format='json')
        wsgi_request.user = Mock(is_authenticated=True)
        wsgi_request.tenant = Mock()
        wsgi_request.data = data

        view = ConnectOnboardView()
        view.request = wsgi_request

        # Act
        response = view.post(wsgi_request)

        # Assert
        assert response.status_code == status.HTTP_400_BAD_REQUEST

    @patch('smoothschedule.commerce.payments.views.stripe.AccountLink.create')
    @patch('smoothschedule.commerce.payments.views.stripe.Account.create')
    @patch('smoothschedule.commerce.payments.views.settings')
    def test_creates_new_connect_account(self, mock_settings, mock_account_create, mock_link_create):
        """Test creation of new Connect account."""
        from smoothschedule.commerce.payments.views import ConnectOnboardView

        # Arrange
        mock_settings.STRIPE_SECRET_KEY = 'sk_test_key'

        mock_account = Mock(id='acct_123')
        mock_account_create.return_value = mock_account

        mock_link = Mock(url='https://connect.stripe.com/setup/123')
        mock_link_create.return_value = mock_link

        mock_tenant = Mock()
        mock_tenant.id = 1
        mock_tenant.stripe_connect_id = None
        mock_tenant.contact_email = 'test@example.com'
        mock_tenant.name = 'Test Business'
        mock_tenant.schema_name = 'test'

        factory = APIRequestFactory()
        data = {
            'refresh_url': 'http://example.com/refresh',
            'return_url': 'http://example.com/return'
        }
        wsgi_request = factory.post('/payments/connect/onboard/', data, format='json')
        wsgi_request.user = Mock(is_authenticated=True)
        wsgi_request.tenant = mock_tenant
        wsgi_request.data = data

        view = ConnectOnboardView()
        view.request = wsgi_request

        # Act
        response = view.post(wsgi_request)

        # Assert
        assert response.status_code == status.HTTP_200_OK
        assert response.data['url'] == 'https://connect.stripe.com/setup/123'
        assert mock_tenant.stripe_connect_id == 'acct_123'


# ============================================================================
# ConnectRefreshStatusView Tests
# ============================================================================

class TestConnectRefreshStatusView:
    """Test ConnectRefreshStatusView."""

    @patch('smoothschedule.commerce.payments.views.stripe.Account.retrieve')
    @patch('smoothschedule.commerce.payments.views.settings')
    def test_syncs_account_status(self, mock_settings, mock_retrieve):
        """Test status sync from Stripe."""
        from smoothschedule.commerce.payments.views import ConnectRefreshStatusView

        # Arrange
        mock_settings.STRIPE_SECRET_KEY = 'sk_test_key'

        mock_account = Mock()
        mock_account.charges_enabled = True
        mock_account.payouts_enabled = True
        mock_account.details_submitted = True
        mock_retrieve.return_value = mock_account

        mock_tenant = Mock()
        mock_tenant.id = 1
        mock_tenant.name = 'Test'
        mock_tenant.schema_name = 'test'
        mock_tenant.stripe_connect_id = 'acct_123'
        mock_tenant.created_on = None

        factory = APIRequestFactory()
        request = factory.post('/payments/connect/refresh-status/', {}, format='json')
        request.user = Mock(is_authenticated=True)
        request.tenant = mock_tenant

        view = ConnectRefreshStatusView()
        view.request = request

        # Act
        response = view.post(request)

        # Assert
        assert response.status_code == status.HTTP_200_OK
        assert mock_tenant.stripe_charges_enabled is True
        assert mock_tenant.stripe_connect_status == 'active'


# ============================================================================
# ConnectAccountSessionView Tests
# ============================================================================

class TestConnectAccountSessionView:
    """Test ConnectAccountSessionView."""

    @patch('smoothschedule.commerce.payments.views.stripe.AccountSession.create')
    @patch('smoothschedule.commerce.payments.views.stripe.Account.create')
    @patch('smoothschedule.commerce.payments.views.settings')
    def test_creates_account_session(self, mock_settings, mock_account_create, mock_session_create):
        """Test account session creation."""
        from smoothschedule.commerce.payments.views import ConnectAccountSessionView

        # Arrange
        mock_settings.STRIPE_SECRET_KEY = 'sk_test_key'
        mock_settings.STRIPE_PUBLISHABLE_KEY = 'pk_test_key'

        mock_account = Mock(id='acct_123')
        mock_account_create.return_value = mock_account

        mock_session = Mock(client_secret='secret_123')
        mock_session_create.return_value = mock_session

        mock_tenant = Mock()
        mock_tenant.id = 1
        mock_tenant.stripe_connect_id = None
        mock_tenant.contact_email = 'test@example.com'
        mock_tenant.name = 'Test'
        mock_tenant.schema_name = 'test'

        factory = APIRequestFactory()
        request = factory.post('/payments/connect/account-session/', {}, format='json')
        request.user = Mock(is_authenticated=True)
        request.tenant = mock_tenant

        view = ConnectAccountSessionView()
        view.request = request

        # Act
        response = view.post(request)

        # Assert
        assert response.status_code == status.HTTP_200_OK
        assert response.data['client_secret'] == 'secret_123'


# ============================================================================
# TransactionListView Tests
# ============================================================================

class TestTransactionListView:
    """Test TransactionListView."""

    def test_pagination_calculation(self):
        """Test pagination logic."""
        # Business logic test
        total_count = 100
        page = 2
        page_size = 20

        total_pages = (total_count + page_size - 1) // page_size
        offset = (page - 1) * page_size

        assert total_pages == 5
        assert offset == 20

    @patch('smoothschedule.commerce.payments.views.TransactionLink.objects.all')
    def test_filters_by_status(self, mock_all):
        """Test filtering by status."""
        from smoothschedule.commerce.payments.views import TransactionListView

        # Arrange
        mock_queryset = Mock()
        mock_filtered = Mock()
        mock_filtered.count.return_value = 0
        mock_filtered.__getitem__ = Mock(return_value=[])
        mock_queryset.filter.return_value = mock_filtered
        mock_all.return_value = mock_queryset

        factory = APIRequestFactory()
        wsgi_request = factory.get('/payments/transactions/?status=succeeded')
        wsgi_request.user = Mock(is_authenticated=True)
        wsgi_request.tenant = Mock(id=1, name='Test')
        wsgi_request.query_params = wsgi_request.GET

        view = TransactionListView()
        view.request = wsgi_request

        # Act
        response = view.get(wsgi_request)

        # Assert
        mock_queryset.filter.assert_called_once()


# ============================================================================
# TransactionSummaryView Tests
# ============================================================================

class TestTransactionSummaryView:
    """Test TransactionSummaryView."""

    @patch('smoothschedule.commerce.payments.views.TransactionLink.objects.all')
    def test_calculates_summary_stats(self, mock_all):
        """Test summary calculation."""
        from smoothschedule.commerce.payments.views import TransactionSummaryView
        from smoothschedule.commerce.payments.models import TransactionLink

        # Arrange
        mock_queryset = Mock()
        mock_queryset.filter.return_value = mock_queryset
        mock_queryset.aggregate.return_value = {
            'total_transactions': 10,
            'total_volume': Decimal('1000.00'),
            'total_fees': Decimal('50.00'),
            'average_transaction': Decimal('100.00')
        }
        mock_queryset.count.side_effect = [5, 2, 1]  # succeeded, failed, refunded
        mock_all.return_value = mock_queryset

        factory = APIRequestFactory()
        wsgi_request = factory.get('/payments/transactions/summary/')
        wsgi_request.user = Mock(is_authenticated=True)
        wsgi_request.query_params = wsgi_request.GET

        view = TransactionSummaryView()
        view.request = wsgi_request

        # Act
        response = view.get(wsgi_request)

        # Assert
        assert response.status_code == status.HTTP_200_OK
        assert response.data['total_transactions'] == 10
        assert float(response.data['total_volume']) == 1000.00


# ============================================================================
# StripeChargesView Tests
# ============================================================================

class TestStripeChargesView:
    """Test StripeChargesView."""

    @patch('smoothschedule.commerce.payments.views.stripe.Charge.list')
    @patch('smoothschedule.commerce.payments.views.settings')
    def test_lists_charges_in_direct_api_mode(self, mock_settings, mock_charge_list):
        """Test charge listing in direct API mode."""
        from smoothschedule.commerce.payments.views import StripeChargesView

        # Arrange
        mock_settings.STRIPE_SECRET_KEY = 'sk_platform_key'

        mock_charge = Mock()
        mock_charge.id = 'ch_123'
        mock_charge.amount = 10000
        mock_charge.amount_refunded = 0
        mock_charge.currency = 'usd'
        mock_charge.status = 'succeeded'
        mock_charge.paid = True
        mock_charge.refunded = False
        mock_charge.description = 'Test charge'
        mock_charge.receipt_email = 'test@example.com'
        mock_charge.receipt_url = 'https://stripe.com/receipt'
        mock_charge.created = 1704067200
        mock_charge.payment_method_details = None
        mock_charge.billing_details = None

        mock_charges = Mock()
        mock_charges.data = [mock_charge]
        mock_charges.has_more = False
        mock_charge_list.return_value = mock_charges

        mock_tenant = Mock()
        mock_tenant.payment_mode = 'direct_api'
        mock_tenant.stripe_secret_key = 'sk_test_key'

        factory = APIRequestFactory()
        wsgi_request = factory.get('/payments/transactions/charges/')
        wsgi_request.user = Mock(is_authenticated=True)
        wsgi_request.tenant = mock_tenant
        wsgi_request.query_params = wsgi_request.GET

        view = StripeChargesView()
        view.request = wsgi_request

        # Act
        response = view.get(wsgi_request)

        # Assert
        assert response.status_code == status.HTTP_200_OK
        assert len(response.data['charges']) == 1


# ============================================================================
# CreatePaymentIntentView Tests
# ============================================================================

class TestCreatePaymentIntentView:
    """Test CreatePaymentIntentView."""

    def test_requires_event_id(self):
        """Test that event_id is required."""
        from smoothschedule.commerce.payments.views import CreatePaymentIntentView

        factory = APIRequestFactory()
        data = {}
        wsgi_request = factory.post('/payments/payment-intents/', data, format='json')
        wsgi_request.user = Mock(is_authenticated=True)
        wsgi_request.data = data

        view = CreatePaymentIntentView()
        view.request = wsgi_request

        # Act
        response = view.post(wsgi_request)

        # Assert
        assert response.status_code == status.HTTP_400_BAD_REQUEST
        assert 'event_id' in response.data['error']

    @patch('smoothschedule.commerce.payments.views.Event.objects.get')
    def test_requires_amount(self, mock_get_event):
        """Test that amount is required."""
        from smoothschedule.commerce.payments.views import CreatePaymentIntentView

        # Arrange - mock event exists
        mock_get_event.return_value = Mock(id=1)

        factory = APIRequestFactory()
        data = {'event_id': 1}
        wsgi_request = factory.post('/payments/payment-intents/', data, format='json')
        wsgi_request.user = Mock(is_authenticated=True)
        wsgi_request.data = data

        view = CreatePaymentIntentView()
        view.request = wsgi_request

        # Act
        response = view.post(wsgi_request)

        # Assert
        assert response.status_code == status.HTTP_400_BAD_REQUEST
        assert 'amount' in response.data['error']

    @patch('smoothschedule.commerce.payments.views.Event.objects.get')
    def test_returns_404_for_invalid_event(self, mock_get):
        """Test 404 when event doesn't exist."""
        from smoothschedule.commerce.payments.views import CreatePaymentIntentView
        from smoothschedule.scheduling.schedule.models import Event

        # Arrange
        mock_get.side_effect = Event.DoesNotExist()

        factory = APIRequestFactory()
        data = {
            'event_id': 999,
            'amount': '100.00'
        }
        wsgi_request = factory.post('/payments/payment-intents/', data, format='json')
        wsgi_request.user = Mock(is_authenticated=True)
        wsgi_request.data = data

        view = CreatePaymentIntentView()
        view.request = wsgi_request

        # Act
        response = view.post(wsgi_request)

        # Assert
        assert response.status_code == status.HTTP_404_NOT_FOUND

    @patch('smoothschedule.commerce.payments.views.get_stripe_service_for_tenant')
    @patch('smoothschedule.commerce.payments.views.Event.objects.get')
    def test_creates_payment_intent_successfully(self, mock_get_event, mock_get_service):
        """Test successful payment intent creation."""
        from smoothschedule.commerce.payments.views import CreatePaymentIntentView

        # Arrange
        mock_event = Mock(id=1)
        mock_get_event.return_value = mock_event

        mock_pi = Mock()
        mock_pi.client_secret = 'secret_123'
        mock_pi.id = 'pi_123'

        mock_tx = Mock()
        mock_tx.amount = Decimal('100.00')
        mock_tx.currency = 'USD'
        mock_tx.application_fee_amount = Decimal('5.00')
        mock_tx.status = 'pending'

        mock_service = Mock()
        mock_service.create_payment_intent.return_value = (mock_pi, mock_tx)
        mock_get_service.return_value = mock_service

        factory = APIRequestFactory()
        data = {
            'event_id': 1,
            'amount': '100.00'
        }
        wsgi_request = factory.post('/payments/payment-intents/', data, format='json')
        wsgi_request.user = Mock(is_authenticated=True)
        wsgi_request.tenant = Mock()
        wsgi_request.data = data

        view = CreatePaymentIntentView()
        view.request = wsgi_request

        # Act
        response = view.post(wsgi_request)

        # Assert
        assert response.status_code == status.HTTP_201_CREATED
        assert response.data['client_secret'] == 'secret_123'


# ============================================================================
# RefundPaymentView Tests
# ============================================================================

class TestRefundPaymentView:
    """Test RefundPaymentView."""

    def test_requires_payment_intent_id(self):
        """Test that payment_intent_id is required."""
        from smoothschedule.commerce.payments.views import RefundPaymentView

        factory = APIRequestFactory()
        data = {}
        wsgi_request = factory.post('/payments/refunds/', data, format='json')
        wsgi_request.user = Mock(is_authenticated=True)
        wsgi_request.data = data

        view = RefundPaymentView()
        view.request = wsgi_request

        # Act
        response = view.post(wsgi_request)

        # Assert
        assert response.status_code == status.HTTP_400_BAD_REQUEST

    @patch('smoothschedule.commerce.payments.views.get_stripe_service_for_tenant')
    def test_creates_refund_successfully(self, mock_get_service):
        """Test successful refund creation."""
        from smoothschedule.commerce.payments.views import RefundPaymentView

        # Arrange
        mock_refund = Mock()
        mock_refund.id = 'refund_123'
        mock_refund.amount = 10000
        mock_refund.status = 'succeeded'
        mock_refund.reason = 'requested_by_customer'

        mock_service = Mock()
        mock_service.refund_payment.return_value = mock_refund
        mock_get_service.return_value = mock_service

        factory = APIRequestFactory()
        data = {
            'payment_intent_id': 'pi_123'
        }
        wsgi_request = factory.post('/payments/refunds/', data, format='json')
        wsgi_request.user = Mock(is_authenticated=True)
        wsgi_request.tenant = Mock()
        wsgi_request.data = data

        view = RefundPaymentView()
        view.request = wsgi_request

        # Act
        response = view.post(wsgi_request)

        # Assert
        assert response.status_code == status.HTTP_201_CREATED
        assert response.data['refund_id'] == 'refund_123'


# ============================================================================
# CustomerBillingView Tests
# ============================================================================

class TestCustomerBillingView:
    """Test CustomerBillingView."""

    def test_returns_403_for_non_customer(self):
        """Test 403 when user is not a customer."""
        from smoothschedule.commerce.payments.views import CustomerBillingView
        from smoothschedule.identity.users.models import User

        factory = APIRequestFactory()
        request = factory.get('/payments/customer/billing/')
        request.user = Mock(role=User.Role.TENANT_STAFF)

        view = CustomerBillingView()
        view.request = request

        # Act
        response = view.get(request)

        # Assert
        assert response.status_code == status.HTTP_403_FORBIDDEN


# ============================================================================
# CustomerPaymentMethodsView Tests
# ============================================================================

class TestCustomerPaymentMethodsView:
    """Test CustomerPaymentMethodsView."""

    def test_returns_error_for_non_customer_user(self):
        """Test response when user is not a customer."""
        from smoothschedule.commerce.payments.views import CustomerPaymentMethodsView

        # Arrange
        factory = APIRequestFactory()
        request = factory.get('/payments/customer/payment-methods/')

        mock_user = Mock()
        mock_user.role = 'staff'  # Not a customer
        request.user = mock_user

        view = CustomerPaymentMethodsView()
        view.request = request

        # Act
        response = view.get(request)

        # Assert
        assert response.status_code == status.HTTP_403_FORBIDDEN
        assert 'only for customers' in response.data['error']

    def test_returns_empty_when_no_stripe_customer_id(self):
        """Test response when customer has no Stripe customer ID."""
        from smoothschedule.commerce.payments.views import CustomerPaymentMethodsView
        from smoothschedule.identity.users.models import User

        # Arrange
        factory = APIRequestFactory()
        request = factory.get('/payments/customer/payment-methods/')

        mock_user = Mock()
        mock_user.role = User.Role.CUSTOMER
        mock_user.stripe_customer_id = None
        request.user = mock_user

        view = CustomerPaymentMethodsView()
        view.request = request

        # Act
        response = view.get(request)

        # Assert
        assert response.status_code == status.HTTP_200_OK
        assert response.data['payment_methods'] == []
        assert response.data['has_stripe_customer'] is False

    @patch('smoothschedule.commerce.payments.views.get_stripe_service_for_tenant')
    def test_lists_payment_methods_successfully(self, mock_service_factory):
        """Test successful retrieval of payment methods."""
        from smoothschedule.commerce.payments.views import CustomerPaymentMethodsView
        from smoothschedule.identity.users.models import User

        # Arrange
        mock_card1 = Mock()
        mock_card1.brand = 'visa'
        mock_card1.last4 = '4242'
        mock_card1.exp_month = 12
        mock_card1.exp_year = 2025

        mock_pm1 = Mock()
        mock_pm1.id = 'pm_123'
        mock_pm1.type = 'card'
        mock_pm1.card = mock_card1

        mock_pm_list = Mock()
        mock_pm_list.data = [mock_pm1]

        mock_service = Mock()
        mock_service.list_payment_methods.return_value = mock_pm_list
        mock_service_factory.return_value = mock_service

        factory = APIRequestFactory()
        request = factory.get('/payments/customer/payment-methods/')

        mock_user = Mock()
        mock_user.role = User.Role.CUSTOMER
        mock_user.stripe_customer_id = 'cus_123'
        mock_user.default_payment_method_id = None
        request.user = mock_user
        request.tenant = Mock()

        view = CustomerPaymentMethodsView()
        view.request = request

        # Act
        response = view.get(request)

        # Assert
        assert response.status_code == status.HTTP_200_OK
        assert len(response.data['payment_methods']) == 1
        assert response.data['payment_methods'][0]['brand'] == 'visa'


# ============================================================================
# CustomerSetupIntentView Tests
# ============================================================================

class TestCustomerSetupIntentView:
    """Test CustomerSetupIntentView."""

    def test_returns_403_for_non_customer(self):
        """Test 403 when user is not a customer."""
        from smoothschedule.commerce.payments.views import CustomerSetupIntentView
        from smoothschedule.identity.users.models import User

        factory = APIRequestFactory()
        request = factory.post('/payments/customer/setup-intent/', {}, format='json')
        request.user = Mock(role=User.Role.TENANT_STAFF)
        request.tenant = Mock()

        view = CustomerSetupIntentView()
        view.request = request

        # Act
        response = view.post(request)

        # Assert
        assert response.status_code == status.HTTP_403_FORBIDDEN

    @patch('smoothschedule.commerce.payments.views.stripe.SetupIntent.create')
    @patch('smoothschedule.commerce.payments.views.stripe.Customer.create')
    @patch('smoothschedule.commerce.payments.views.settings')
    def test_creates_setup_intent_in_direct_api_mode(self, mock_settings, mock_customer_create, mock_si_create):
        """Test SetupIntent creation in direct API mode."""
        from smoothschedule.commerce.payments.views import CustomerSetupIntentView
        from smoothschedule.identity.users.models import User

        # Arrange
        mock_settings.STRIPE_SECRET_KEY = 'sk_platform_key'

        mock_customer = Mock(id='cus_123')
        mock_customer_create.return_value = mock_customer

        mock_si = Mock()
        mock_si.client_secret = 'seti_secret_123'
        mock_si.id = 'seti_123'
        mock_si_create.return_value = mock_si

        mock_user = Mock()
        mock_user.role = User.Role.CUSTOMER
        mock_user.stripe_customer_id = None
        mock_user.email = 'test@example.com'
        mock_user.get_full_name.return_value = 'Test User'
        mock_user.username = 'testuser'
        mock_user.id = 1

        mock_tenant = Mock()
        mock_tenant.payment_mode = 'direct_api'
        mock_tenant.stripe_secret_key = 'sk_test_key'
        mock_tenant.stripe_publishable_key = 'pk_test_key'
        mock_tenant.name = 'Test Business'

        factory = APIRequestFactory()
        request = factory.post('/payments/customer/setup-intent/', {}, format='json')
        request.user = mock_user
        request.tenant = mock_tenant

        view = CustomerSetupIntentView()
        view.request = request

        # Act
        response = view.post(request)

        # Assert
        assert response.status_code == status.HTTP_200_OK
        assert response.data['client_secret'] == 'seti_secret_123'


# ============================================================================
# SetFinalPriceView Tests
# ============================================================================

class TestSetFinalPriceView:
    """Test SetFinalPriceView."""

    def test_calculates_remaining_balance_correctly(self):
        """Test remaining balance calculation."""
        final_price = Decimal('150.00')
        deposit = Decimal('50.00')
        remaining_balance = max(final_price - deposit, Decimal('0.00'))

        assert remaining_balance == Decimal('100.00')

    def test_calculates_overpaid_amount_correctly(self):
        """Test overpaid amount calculation."""
        final_price = Decimal('50.00')
        deposit = Decimal('100.00')
        overpaid = max(deposit - final_price, Decimal('0.00'))

        assert overpaid == Decimal('50.00')

    def test_requires_final_price(self):
        """Test that final_price is required."""
        from smoothschedule.commerce.payments.views import SetFinalPriceView

        factory = APIRequestFactory()
        data = {}
        wsgi_request = factory.post('/payments/events/1/final-price/', data, format='json')
        wsgi_request.user = Mock(is_authenticated=True)
        wsgi_request.data = data

        view = SetFinalPriceView()
        view.request = wsgi_request

        # Act
        response = view.post(wsgi_request, event_id=1)

        # Assert
        assert response.status_code == status.HTTP_400_BAD_REQUEST

    @patch('smoothschedule.commerce.payments.views.Event.objects.get')
    def test_returns_404_for_invalid_event(self, mock_get):
        """Test 404 when event doesn't exist."""
        from smoothschedule.commerce.payments.views import SetFinalPriceView
        from smoothschedule.scheduling.schedule.models import Event

        # Arrange
        mock_get.side_effect = Event.DoesNotExist()

        factory = APIRequestFactory()
        data = {
            'final_price': '100.00'
        }
        wsgi_request = factory.post('/payments/events/999/final-price/', data, format='json')
        wsgi_request.user = Mock(is_authenticated=True)
        wsgi_request.data = data

        view = SetFinalPriceView()
        view.request = wsgi_request

        # Act
        response = view.post(wsgi_request, event_id=999)

        # Assert
        assert response.status_code == status.HTTP_404_NOT_FOUND


# ============================================================================
# EventPricingInfoView Tests
# ============================================================================

class TestEventPricingInfoView:
    """Test EventPricingInfoView."""

    @patch('smoothschedule.commerce.payments.views.TransactionLink.objects.filter')
    @patch('smoothschedule.commerce.payments.views.Event.objects.select_related')
    def test_returns_pricing_info(self, mock_select, mock_filter):
        """Test event pricing info retrieval."""
        from smoothschedule.commerce.payments.views import EventPricingInfoView

        # Arrange
        mock_service = Mock()
        mock_service.name = 'Test Service'
        mock_service.price = Decimal('100.00')

        mock_event = Mock()
        mock_event.id = 1
        mock_event.service_id = 1
        mock_event.service = mock_service
        mock_event.is_variable_pricing = True
        mock_event.status = 'SCHEDULED'
        mock_event.deposit_amount = Decimal('50.00')
        mock_event.final_price = None
        mock_event.remaining_balance = None
        mock_event.overpaid_amount = None
        mock_event.deposit_transaction_id = None
        mock_event.final_charge_transaction_id = None

        mock_queryset = Mock()
        mock_queryset.get.return_value = mock_event
        mock_select.return_value = mock_queryset

        # Mock TransactionLink.objects.filter() to avoid database query
        mock_tx_queryset = Mock()
        mock_tx_queryset.order_by.return_value = []
        mock_filter.return_value = mock_tx_queryset

        factory = APIRequestFactory()
        request = factory.get('/payments/events/1/pricing/')
        request.user = Mock(is_authenticated=True)

        view = EventPricingInfoView()
        view.request = request

        # Act
        response = view.get(request, event_id=1)

        # Assert
        assert response.status_code == status.HTTP_200_OK
        assert response.data['event_id'] == 1
        assert response.data['is_variable_pricing'] is True


# ============================================================================
# TransactionExportView Tests
# ============================================================================

class TestTransactionExportView:
    """Test TransactionExportView."""

    def test_returns_not_implemented(self):
        """Test that export returns 501 (not implemented)."""
        from smoothschedule.commerce.payments.views import TransactionExportView

        factory = APIRequestFactory()
        data = {}
        wsgi_request = factory.post('/payments/transactions/export/', data, format='json')
        wsgi_request.user = Mock(is_authenticated=True)
        wsgi_request.data = data

        view = TransactionExportView()
        view.request = wsgi_request

        # Act
        response = view.post(wsgi_request)

        # Assert
        assert response.status_code == status.HTTP_501_NOT_IMPLEMENTED


# ============================================================================
# StripePayoutsView Tests
# ============================================================================

class TestStripePayoutsView:
    """Test StripePayoutsView."""

    @patch('smoothschedule.commerce.payments.views.stripe.Payout.list')
    @patch('smoothschedule.commerce.payments.views.settings')
    def test_lists_payouts(self, mock_settings, mock_payout_list):
        """Test payout listing."""
        from smoothschedule.commerce.payments.views import StripePayoutsView

        # Arrange
        mock_settings.STRIPE_SECRET_KEY = 'sk_platform_key'

        mock_payout = Mock()
        mock_payout.id = 'po_123'
        mock_payout.amount = 50000
        mock_payout.currency = 'usd'
        mock_payout.status = 'paid'
        mock_payout.arrival_date = 1704067200
        mock_payout.created = 1704067200
        mock_payout.description = 'Test payout'
        mock_payout.destination = 'ba_123'
        mock_payout.failure_message = None
        mock_payout.method = 'standard'
        mock_payout.type = 'bank_account'

        mock_payouts = Mock()
        mock_payouts.data = [mock_payout]
        mock_payouts.has_more = False
        mock_payout_list.return_value = mock_payouts

        mock_tenant = Mock()
        mock_tenant.payment_mode = 'direct_api'
        mock_tenant.stripe_secret_key = 'sk_test_key'

        factory = APIRequestFactory()
        wsgi_request = factory.get('/payments/transactions/payouts/')
        wsgi_request.user = Mock(is_authenticated=True)
        wsgi_request.tenant = mock_tenant
        wsgi_request.query_params = wsgi_request.GET

        view = StripePayoutsView()
        view.request = wsgi_request

        # Act
        response = view.get(wsgi_request)

        # Assert
        assert response.status_code == status.HTTP_200_OK
        assert len(response.data['payouts']) == 1


# ============================================================================
# StripeBalanceView Tests
# ============================================================================

class TestStripeBalanceView:
    """Test StripeBalanceView."""

    @patch('smoothschedule.commerce.payments.views.stripe.Balance.retrieve')
    @patch('smoothschedule.commerce.payments.views.settings')
    def test_retrieves_balance(self, mock_settings, mock_balance_retrieve):
        """Test balance retrieval."""
        from smoothschedule.commerce.payments.views import StripeBalanceView

        # Arrange
        mock_settings.STRIPE_SECRET_KEY = 'sk_platform_key'

        mock_available_item = Mock()
        mock_available_item.amount = 100000
        mock_available_item.currency = 'usd'

        mock_pending_item = Mock()
        mock_pending_item.amount = 50000
        mock_pending_item.currency = 'usd'

        mock_balance = Mock()
        mock_balance.available = [mock_available_item]
        mock_balance.pending = [mock_pending_item]
        mock_balance_retrieve.return_value = mock_balance

        mock_tenant = Mock()
        mock_tenant.payment_mode = 'direct_api'
        mock_tenant.stripe_secret_key = 'sk_test_key'

        factory = APIRequestFactory()
        request = factory.get('/payments/transactions/balance/')
        request.user = Mock(is_authenticated=True)
        request.tenant = mock_tenant

        view = StripeBalanceView()
        view.request = request

        # Act
        response = view.get(request)

        # Assert
        assert response.status_code == status.HTTP_200_OK
        assert response.data['available_total'] == 100000
        assert response.data['pending_total'] == 50000


# ============================================================================
# TerminalConnectionTokenView Tests
# ============================================================================

class TestTerminalConnectionTokenView:
    """Test TerminalConnectionTokenView."""

    @patch('smoothschedule.commerce.payments.views.get_stripe_service_for_tenant')
    def test_gets_terminal_token(self, mock_service_factory):
        """Test terminal token retrieval."""
        from smoothschedule.commerce.payments.views import TerminalConnectionTokenView

        # Arrange
        mock_token = Mock()
        mock_token.secret = 'terminal_secret_123'

        mock_service = Mock()
        mock_service.get_terminal_token.return_value = mock_token
        mock_service_factory.return_value = mock_service

        factory = APIRequestFactory()
        request = factory.post('/payments/terminal/connection-token/', {}, format='json')
        request.user = Mock(is_authenticated=True)
        request.tenant = Mock()

        view = TerminalConnectionTokenView()
        view.request = request

        # Act
        response = view.post(request)

        # Assert
        assert response.status_code == status.HTTP_200_OK
        assert response.data['secret'] == 'terminal_secret_123'


# ============================================================================
# CustomerPaymentMethodDeleteView Tests
# ============================================================================

class TestCustomerPaymentMethodDeleteView:
    """Test CustomerPaymentMethodDeleteView."""

    @patch('smoothschedule.commerce.payments.views.get_stripe_service_for_tenant')
    def test_deletes_payment_method(self, mock_service_factory):
        """Test payment method deletion."""
        from smoothschedule.commerce.payments.views import CustomerPaymentMethodDeleteView
        from smoothschedule.identity.users.models import User

        # Arrange
        mock_pm = Mock(id='pm_123')
        mock_pm_list = Mock(data=[mock_pm])

        mock_service = Mock()
        mock_service.list_payment_methods.return_value = mock_pm_list
        mock_service.detach_payment_method.return_value = None
        mock_service_factory.return_value = mock_service

        mock_user = Mock()
        mock_user.role = User.Role.CUSTOMER
        mock_user.stripe_customer_id = 'cus_123'

        factory = APIRequestFactory()
        request = factory.delete('/payments/customer/payment-methods/pm_123/')
        request.user = mock_user
        request.tenant = Mock()

        view = CustomerPaymentMethodDeleteView()
        view.request = request

        # Act
        response = view.delete(request, payment_method_id='pm_123')

        # Assert
        assert response.status_code == status.HTTP_200_OK
        assert response.data['success'] is True


# ============================================================================
# CustomerPaymentMethodDefaultView Tests
# ============================================================================

class TestCustomerPaymentMethodDefaultView:
    """Test CustomerPaymentMethodDefaultView."""

    @patch('smoothschedule.commerce.payments.views.get_stripe_service_for_tenant')
    def test_sets_default_payment_method(self, mock_service_factory):
        """Test setting default payment method."""
        from smoothschedule.commerce.payments.views import CustomerPaymentMethodDefaultView
        from smoothschedule.identity.users.models import User

        # Arrange
        mock_pm = Mock(id='pm_123')
        mock_pm_list = Mock(data=[mock_pm])

        mock_service = Mock()
        mock_service.list_payment_methods.return_value = mock_pm_list
        mock_service.set_default_payment_method.return_value = None
        mock_service_factory.return_value = mock_service

        mock_user = Mock()
        mock_user.role = User.Role.CUSTOMER
        mock_user.stripe_customer_id = 'cus_123'

        factory = APIRequestFactory()
        request = factory.post('/payments/customer/payment-methods/pm_123/default/')
        request.user = mock_user
        request.tenant = Mock()

        view = CustomerPaymentMethodDefaultView()
        view.request = request

        # Act
        response = view.post(request, payment_method_id='pm_123')

        # Assert
        assert response.status_code == status.HTTP_200_OK
        assert mock_user.default_payment_method_id == 'pm_123'


# ============================================================================
# ConnectRefreshLinkView Tests
# ============================================================================

class TestConnectRefreshLinkView:
    """Test ConnectRefreshLinkView."""

    @patch('smoothschedule.commerce.payments.views.stripe.AccountLink.create')
    @patch('smoothschedule.commerce.payments.views.settings')
    def test_creates_refresh_link(self, mock_settings, mock_link_create):
        """Test refresh link creation."""
        from smoothschedule.commerce.payments.views import ConnectRefreshLinkView

        # Arrange
        mock_settings.STRIPE_SECRET_KEY = 'sk_test_key'

        mock_link = Mock(url='https://connect.stripe.com/refresh/123')
        mock_link_create.return_value = mock_link

        mock_tenant = Mock()
        mock_tenant.stripe_connect_id = 'acct_123'

        factory = APIRequestFactory()
        data = {
            'refresh_url': 'http://example.com/refresh',
            'return_url': 'http://example.com/return'
        }
        wsgi_request = factory.post('/payments/connect/refresh-link/', data, format='json')
        wsgi_request.user = Mock(is_authenticated=True)
        wsgi_request.tenant = mock_tenant
        wsgi_request.data = data

        view = ConnectRefreshLinkView()
        view.request = wsgi_request

        # Act
        response = view.post(wsgi_request)

        # Assert
        assert response.status_code == status.HTTP_200_OK
        assert response.data['url'] == 'https://connect.stripe.com/refresh/123'
