import json
from unittest.mock import patch

from django.test import TestCase
from django.urls import reverse
from rest_framework.renderers import BrowsableAPIRenderer, JSONRenderer

from wagtail.api.v2.views import BaseAPIViewSet
from wagtail.test.numberformat import ignore_numberformat
from wagtail.test.utils import WagtailTestUtils


class TestBaseAPIViewSetRendererClasses(WagtailTestUtils, TestCase):
    def setUp(self):
        self.user = self.login()

    def test_renderer_classes_with_rest_framework_installed(self):
        """Test that both JSONRenderer and BrowsableAPIRenderer are included when rest_framework is installed."""
        renderer_classes = BaseAPIViewSet.renderer_classes
        # Should have both renderers when rest_framework is installed
        self.assertEqual(renderer_classes, [JSONRenderer, BrowsableAPIRenderer])

    @patch("wagtail.api.v2.views.apps.is_installed")
    def test_renderer_classes_without_rest_framework(self, mock_is_installed):
        """Test that only JSONRenderer is included when rest_framework is not installed."""

        # Mock rest_framework as not installed
        def mock_installed(app):
            return app != "rest_framework"

        mock_is_installed.side_effect = mock_installed

        renderer_classes = BaseAPIViewSet.renderer_classes
        self.assertEqual(renderer_classes, [JSONRenderer])

    def test_api_response_returns_json_by_default(self):
        """Test that API returns JSON by default."""
        response = self.client.get(reverse("wagtailapi_v2:pages:listing"))

        self.assertEqual(response.status_code, 200)
        self.assertEqual(response["Content-Type"], "application/json")

        # Should be valid JSON
        content = json.loads(response.content.decode("UTF-8"))
        self.assertIn("meta", content)
        self.assertIn("items", content)

    def test_api_response_returns_json_with_json_accept_header(self):
        """Test that API returns JSON when JSON is explicitly requested."""
        response = self.client.get(
            reverse("wagtailapi_v2:pages:listing"), HTTP_ACCEPT="application/json"
        )

        self.assertEqual(response.status_code, 200)
        self.assertEqual(response["Content-Type"], "application/json")

        # Should be valid JSON
        content = json.loads(response.content.decode("UTF-8"))
        self.assertIn("meta", content)
        self.assertIn("items", content)

    def test_api_response_returns_html_with_html_accept_header(self):
        """Test that API returns HTML when HTML is explicitly requested via Accept header."""
        with ignore_numberformat(["rest_framework/base.html"]):
            response = self.client.get(
                reverse("wagtailapi_v2:pages:listing"), HTTP_ACCEPT="text/html"
            )

        self.assertEqual(response.status_code, 200)
        self.assertEqual(response["Content-Type"], "text/html; charset=utf-8")

        # Should contain HTML content
        content = response.content.decode("UTF-8")
        self.assertIn("<html", content)
        self.assertIn("</html>", content)

    def test_api_response_returns_html_with_browser_accept_header(self):
        """Test that API returns HTML when accessed with typical browser Accept headers."""
        with ignore_numberformat(["rest_framework/base.html"]):
            response = self.client.get(
                reverse("wagtailapi_v2:pages:listing"),
                HTTP_ACCEPT="text/html,application/xhtml+xml,application/xml;q=0.9",
            )

        self.assertEqual(response.status_code, 200)
        self.assertEqual(response["Content-Type"], "text/html; charset=utf-8")

        # Should contain HTML content
        content = response.content.decode("UTF-8")
        self.assertIn("<html", content)
        self.assertIn("</html>", content)
