"""
Tests for django_lark.decorators module.
"""

from unittest.mock import MagicMock

import lark
import pytest
from django.http import HttpResponse
from django.test import RequestFactory

from django_lark.decorators import subscription_required


@pytest.fixture
def request_factory():
    """Create a Django request factory."""
    return RequestFactory()


@pytest.fixture
def authenticated_user():
    """Create a mock authenticated user."""
    user = MagicMock()
    user.pk = 1
    user.email = "test@example.com"
    user.is_authenticated = True
    return user


@pytest.fixture
def unauthenticated_user():
    """Create a mock unauthenticated user."""
    user = MagicMock()
    user.is_authenticated = False
    return user


class TestSubscriptionRequired:
    """Tests for subscription_required decorator."""

    def test_allows_access_with_active_subscription(
        self, request_factory, authenticated_user, mock_lark_client
    ):
        """Allows access when user has active subscription."""

        @subscription_required()
        def protected_view(request):
            return HttpResponse("Success")

        request = request_factory.get("/protected/")
        request.user = authenticated_user

        response = protected_view(request)

        assert response.status_code == 200
        assert response.content == b"Success"

    def test_denies_access_without_subscription(
        self, request_factory, authenticated_user, mock_lark_client
    ):
        """Denies access when user has no active subscription."""
        mock_lark_client.customer_access.retrieve_billing_state.return_value = MagicMock(
            has_active_subscription=False,
            active_subscriptions=[],
        )

        @subscription_required()
        def protected_view(request):
            return HttpResponse("Success")

        request = request_factory.get("/protected/")
        request.user = authenticated_user

        response = protected_view(request)

        assert response.status_code == 403
        assert b"Active subscription required" in response.content

    def test_denies_access_to_unauthenticated_user(
        self, request_factory, unauthenticated_user
    ):
        """Denies access to unauthenticated users."""

        @subscription_required()
        def protected_view(request):
            return HttpResponse("Success")

        request = request_factory.get("/protected/")
        request.user = unauthenticated_user

        response = protected_view(request)

        assert response.status_code == 403
        assert b"Authentication required" in response.content

    def test_redirects_unauthenticated_user_with_redirect_url(
        self, request_factory, unauthenticated_user
    ):
        """Redirects unauthenticated user when redirect_url is set."""

        @subscription_required(redirect_url="/login/")
        def protected_view(request):
            return HttpResponse("Success")

        request = request_factory.get("/protected/")
        request.user = unauthenticated_user

        response = protected_view(request)

        assert response.status_code == 302
        assert "/login/" in response.url

    def test_redirects_without_subscription_with_redirect_url(
        self, request_factory, authenticated_user, mock_lark_client
    ):
        """Redirects user without subscription when redirect_url is set."""
        mock_lark_client.customer_access.retrieve_billing_state.return_value = MagicMock(
            has_active_subscription=False,
            active_subscriptions=[],
        )

        @subscription_required(redirect_url="/pricing/")
        def protected_view(request):
            return HttpResponse("Success")

        request = request_factory.get("/protected/")
        request.user = authenticated_user

        response = protected_view(request)

        assert response.status_code == 302
        assert "/pricing/" in response.url

    def test_checks_specific_rate_cards(
        self, request_factory, authenticated_user, mock_lark_client
    ):
        """Allows access only with specific rate cards."""
        mock_lark_client.customer_access.retrieve_billing_state.return_value = MagicMock(
            has_active_subscription=True,
            active_subscriptions=[
                MagicMock(rate_card_id="rc_pro"),
            ],
        )

        @subscription_required(rate_card_ids=["rc_pro", "rc_enterprise"])
        def protected_view(request):
            return HttpResponse("Success")

        request = request_factory.get("/protected/")
        request.user = authenticated_user

        response = protected_view(request)

        assert response.status_code == 200

    def test_denies_without_required_rate_card(
        self, request_factory, authenticated_user, mock_lark_client
    ):
        """Denies access when user doesn't have required rate card."""
        mock_lark_client.customer_access.retrieve_billing_state.return_value = MagicMock(
            has_active_subscription=True,
            active_subscriptions=[
                MagicMock(rate_card_id="rc_basic"),
            ],
        )

        @subscription_required(rate_card_ids=["rc_pro", "rc_enterprise"])
        def protected_view(request):
            return HttpResponse("Success")

        request = request_factory.get("/protected/")
        request.user = authenticated_user

        response = protected_view(request)

        assert response.status_code == 403
        assert b"Required subscription tier not found" in response.content

    def test_handles_api_error(
        self, request_factory, authenticated_user, mock_lark_client
    ):
        """Handles API errors gracefully."""
        mock_request = MagicMock()
        mock_lark_client.customer_access.retrieve_billing_state.side_effect = (
            lark.APIError("API Error", mock_request, body=None)
        )

        @subscription_required()
        def protected_view(request):
            return HttpResponse("Success")

        request = request_factory.get("/protected/")
        request.user = authenticated_user

        response = protected_view(request)

        assert response.status_code == 403
        assert b"Unable to verify subscription" in response.content

    def test_uses_external_id_for_lookup(
        self, request_factory, authenticated_user, mock_lark_client
    ):
        """Uses external_id to look up billing state."""

        @subscription_required()
        def protected_view(request):
            return HttpResponse("Success")

        request = request_factory.get("/protected/")
        request.user = authenticated_user

        protected_view(request)

        mock_lark_client.customer_access.retrieve_billing_state.assert_called_once_with(
            "test@example.com"
        )
