"""
Tests for django_stripe_billing.views.

Covers stripe_webhook: signature verification, livemode guard, idempotency.
"""
import json
import pytest
from unittest.mock import patch, MagicMock
from django.test import override_settings, Client
from django.urls import reverse

from django_stripe_billing.models import StripeWebhookEvent


@pytest.fixture
def webhook_client():
    return Client()


@pytest.fixture
def stripe_keys():
    return override_settings(
        STRIPE_BILLING={
            "STRIPE_SECRET_KEY": "sk_test_fake",
            "STRIPE_WEBHOOK_SECRET": "whsec_fake",
            "ENVIRONMENT": "test",
        }
    )


@pytest.mark.django_db
class TestStripeWebhookView:
    """stripe_webhook view security and behavior."""

    def test_returns_400_when_no_stripe_signature_header(self, webhook_client, stripe_keys):
        with stripe_keys:
            response = webhook_client.post(
                reverse("django_stripe_billing:stripe-webhook"),
                data=b'{"id": "evt_1"}',
                content_type="application/json",
            )
        assert response.status_code == 400

    def test_returns_400_on_invalid_payload(self, webhook_client, stripe_keys):
        with stripe_keys:
            with patch(
                "django_stripe_billing.views.stripe.Webhook.construct_event",
                side_effect=ValueError("Invalid payload"),
            ):
                response = webhook_client.post(
                    reverse("django_stripe_billing:stripe-webhook"),
                    data=b"not json",
                    content_type="application/json",
                    HTTP_STRIPE_SIGNATURE="v1,t=123",
                )
        assert response.status_code == 400

    def test_returns_400_on_invalid_signature(self, webhook_client, stripe_keys):
        import stripe
        with stripe_keys:
            with patch(
                "django_stripe_billing.views.stripe.Webhook.construct_event",
                side_effect=stripe.error.SignatureVerificationError(
                    "Bad signature", "sig"
                ),
            ):
                response = webhook_client.post(
                    reverse("django_stripe_billing:stripe-webhook"),
                    data=b'{"id": "evt_1"}',
                    content_type="application/json",
                    HTTP_STRIPE_SIGNATURE="v1,bad",
                )
        assert response.status_code == 400

    def test_returns_200_and_creates_event_on_valid_event(self, webhook_client, stripe_keys):
        payload = json.dumps({
            "id": "evt_test_123",
            "type": "invoice.payment_succeeded",
            "livemode": False,
            "api_version": "2023-10",
            "data": {"object": {"customer": "cus_123"}},
        }).encode("utf-8")
        with stripe_keys:
            with patch(
                "django_stripe_billing.views.stripe.Webhook.construct_event",
                return_value=json.loads(payload.decode()),
            ):
                with patch(
                    "django_stripe_billing.tasks.process_webhook_event_sync"
                ):
                    response = webhook_client.post(
                        reverse("django_stripe_billing:stripe-webhook"),
                        data=payload,
                        content_type="application/json",
                        HTTP_STRIPE_SIGNATURE="v1,valid",
                    )
        assert response.status_code == 200
        assert StripeWebhookEvent.objects.filter(
            stripe_event_id="evt_test_123"
        ).exists()

    def test_returns_200_on_duplicate_event_idempotent(self, webhook_client, stripe_keys):
        StripeWebhookEvent.objects.create(
            stripe_event_id="evt_dup_456",
            event_type="invoice.payment_succeeded",
            payload="{}",
        )
        payload = json.dumps({
            "id": "evt_dup_456",
            "type": "invoice.payment_succeeded",
            "livemode": False,
            "data": {},
        }).encode("utf-8")
        with stripe_keys:
            with patch(
                "django_stripe_billing.views.stripe.Webhook.construct_event",
                return_value=json.loads(payload.decode()),
            ):
                response = webhook_client.post(
                    reverse("django_stripe_billing:stripe-webhook"),
                    data=payload,
                    content_type="application/json",
                    HTTP_STRIPE_SIGNATURE="v1,dup",
                )
        assert response.status_code == 200
        assert StripeWebhookEvent.objects.filter(stripe_event_id="evt_dup_456").count() == 1
