from unittest import mock
from django.test import TestCase

from apps.lyric.models import PaymentMethod, User


class SetupIntentViewTest(TestCase):
    def setUp(self):
        self.user = User.objects.create(email="capman@test.io")
        self.client.force_login(self.user)

    def test_setup_intent_requires_login(self):
        self.client.logout()
        response = self.client.post("/dashboard/wallet/setup-intent")
        self.assertRedirects(
            response, "/?next=/dashboard/wallet/setup-intent",
            fetch_redirect_response=False,
        )

    @mock.patch("apps.dashboard.views.stripe")
    def test_returns_client_secret(self, mock_stripe):
        mock_stripe.Customer.create.return_value = mock.Mock(id="cus_test123")
        mock_stripe.SetupIntent.create.return_value = mock.Mock(client_secret="seti_secret")
        response = self.client.post("/dashboard/wallet/setup-intent")
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.json()["client_secret"], "seti_secret")
        self.assertIn("publishable_key", response.json())

    @mock.patch("apps.dashboard.views.stripe")
    def test_reuses_existing_stripe_customer(self, mock_stripe):
        self.user.stripe_customer_id = "cus_existing"
        self.user.save()
        mock_stripe.SetupIntent.create.return_value = mock.Mock(client_secret="seti_secret")
        self.client.post("/dashboard/wallet/setup-intent")
        mock_stripe.Customer.create.assert_not_called()
        mock_stripe.SetupIntent.create.assert_called_once_with(customer="cus_existing")

class SavePaymentMethodViewTest(TestCase):
    def setUp(self):
        self.user = User.objects.create(email="capman@test.io")
        self.user.stripe_customer_id = "cus_test123"
        self.user.save()
        self.client.force_login(self.user)

    def test_save_payment_method_requires_login(self):
        self.client.logout()
        response = self.client.post(
            "/dashboard/wallet/save-payment-method", {"payment_method_id": "pm_test"}
        )
        self.assertRedirects(
            response, "/?next=/dashboard/wallet/save-payment-method",
            fetch_redirect_response=False,
        )

    @mock.patch("apps.dashboard.views.stripe")
    def test_creates_payment_method_record(self, mock_stripe):
        mock_stripe.PaymentMethod.retrieve.return_value = mock.Mock(
            card=mock.Mock(last4="4242", brand="visa")
        )
        self.client.post(
            "/dashboard/wallet/save-payment-method",
            {"payment_method_id": "pm_test123"},
        )
        pm = PaymentMethod.objects.get(user=self.user)
        self.assertEqual(pm.last4, "4242")
        self.assertEqual(pm.brand, "visa")

    @mock.patch("apps.dashboard.views.stripe")
    def test_returns_json_with_last4_and_brand(self, mock_stripe):
        mock_stripe.PaymentMethod.retrieve.return_value = mock.Mock(
            card=mock.Mock(last4="4242", brand="visa")
        )
        response = self.client.post(
            "/dashboard/wallet/save-payment-method",
            {"payment_method_id": "pm_test123"},
        )
        data = response.json()
        self.assertEqual(data["last4"], "4242")
        self.assertEqual(data["brand"], "visa")
