"""Tests for django-allresponses."""

import json

from django.http import (
    HttpResponseNotFound,
    HttpResponseServerError,
)
from django.test import TestCase

from django_allresponses import (
    HttpResponseContentTooLarge,
    HttpResponseCreated,
    HttpResponseNoContent,
    HttpResponseNotAcceptable,
    HttpResponsePaymentRequired,
    HttpResponseRangeNotSatisfiable,
    HttpResponseResetContent,
    HttpResponseSeeOther,
    HttpResponseTemporaryRedirect,
    HttpResponsePermanentRedirect,
    HttpResponseUnauthorized,
    HttpResponseUnprocessableContent,
    HttpResponseUriTooLong,
    JsonResponseBadRequest,
    JsonResponseCreated,
    JsonResponseNotAllowed,
    JsonResponseOK,
)


class TestResponses(TestCase):
    """Test response classes."""

    def test_no_content(self):
        """Test HttpResponseNoContent."""
        response = HttpResponseNoContent()
        self.assertEqual(response.status_code, 204)
        self.assertEqual(response.content, b"")

    def test_no_content_cannot_have_content(self):
        """Test that HttpResponseNoContent cannot have content set."""
        response = HttpResponseNoContent()
        with self.assertRaises(AttributeError) as cm:
            response.content = b"test"
        self.assertEqual(
            str(cm.exception),
            "You cannot set content to a 204 (No Content) response",
        )

    def test_no_content_strips_content_passed_to_init(self):
        """Test that HttpResponseNoContent ignores content passed to __init__."""
        response = HttpResponseNoContent("oops", content_type="text/plain")
        self.assertEqual(response.status_code, 204)
        self.assertEqual(response.content, b"")
        self.assertNotIn("Content-Type", response)

    def test_reset_content(self):
        """Test HttpResponseResetContent."""
        response = HttpResponseResetContent()
        self.assertEqual(response.status_code, 205)
        self.assertEqual(response.content, b"")
        self.assertNotIn("Content-Type", response)

    def test_reset_content_cannot_have_content(self):
        """Test that HttpResponseResetContent cannot have content set."""
        response = HttpResponseResetContent()
        with self.assertRaises(AttributeError) as cm:
            response.content = b"test"
        self.assertEqual(
            str(cm.exception),
            "You cannot set content to a 205 (Reset Content) response",
        )

    def test_reset_content_strips_content_passed_to_init(self):
        """Test that HttpResponseResetContent ignores content passed to __init__."""
        response = HttpResponseResetContent("oops", content_type="text/plain")
        self.assertEqual(response.status_code, 205)
        self.assertEqual(response.content, b"")
        self.assertNotIn("Content-Type", response)

    def test_created(self):
        """Test HttpResponseCreated."""
        location = "/api/resource/123"
        response = HttpResponseCreated(location=location)
        self.assertEqual(response.status_code, 201)
        self.assertEqual(response["Location"], location)

    def test_payment_required(self):
        """Test HttpResponsePaymentRequired."""
        response = HttpResponsePaymentRequired()
        self.assertEqual(response.status_code, 402)

    def test_not_acceptable(self):
        """Test HttpResponseNotAcceptable."""
        response = HttpResponseNotAcceptable()
        self.assertEqual(response.status_code, 406)

    def test_content_too_large(self):
        """Test HttpResponseContentTooLarge."""
        response = HttpResponseContentTooLarge()
        self.assertEqual(response.status_code, 413)

    def test_uri_too_long(self):
        """Test HttpResponseUriTooLong."""
        response = HttpResponseUriTooLong()
        self.assertEqual(response.status_code, 414)

    def test_range_not_satisfiable(self):
        """Test HttpResponseRangeNotSatisfiable."""
        response = HttpResponseRangeNotSatisfiable()
        self.assertEqual(response.status_code, 416)

    def test_unprocessable_content(self):
        """Test HttpResponseUnprocessableContent."""
        response = HttpResponseUnprocessableContent()
        self.assertEqual(response.status_code, 422)

    def test_not_found(self):
        """Test that HttpResponseNotFound returns 404."""
        response = HttpResponseNotFound()
        self.assertEqual(response.status_code, 404)

    def test_server_error(self):
        """Test that HttpResponseServerError returns 500."""
        response = HttpResponseServerError()
        self.assertEqual(response.status_code, 500)

    def test_unauthorized(self):
        """Test HttpResponseUnauthorized."""
        response = HttpResponseUnauthorized()
        self.assertEqual(response.status_code, 401)

    def test_see_other(self):
        """Test HttpResponseSeeOther."""
        response = HttpResponseSeeOther("/other/")
        self.assertEqual(response.status_code, 303)
        self.assertEqual(response["Location"], "/other/")

    def test_temporary_redirect(self):
        """Test HttpResponseTemporaryRedirect."""
        response = HttpResponseTemporaryRedirect("/temp/")
        self.assertEqual(response.status_code, 307)
        self.assertEqual(response["Location"], "/temp/")

    def test_permanent_redirect(self):
        """Test HttpResponsePermanentRedirect."""
        response = HttpResponsePermanentRedirect("/permanent/")
        self.assertEqual(response.status_code, 308)
        self.assertEqual(response["Location"], "/permanent/")


class TestJsonResponses(TestCase):
    """Test JSON response classes."""

    def test_json_response_ok(self):
        """Test JsonResponseOK."""
        response = JsonResponseOK({"foo": "bar"})
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response["Content-Type"], "application/json")
        self.assertEqual(json.loads(response.content), {"foo": "bar"})

    def test_json_response_bad_request(self):
        """Test JsonResponseBadRequest."""
        response = JsonResponseBadRequest({"reason": "whatever"})
        self.assertEqual(response.status_code, 400)
        self.assertEqual(response["Content-Type"], "application/json")
        self.assertEqual(json.loads(response.content), {"reason": "whatever"})

    def test_json_response_created(self):
        """Test JsonResponseCreated with body and Location."""
        response = JsonResponseCreated({"id": 1}, location="/api/items/1/")
        self.assertEqual(response.status_code, 201)
        self.assertEqual(response["Content-Type"], "application/json")
        self.assertEqual(response["Location"], "/api/items/1/")
        self.assertEqual(json.loads(response.content), {"id": 1})

    def test_json_response_created_empty_body(self):
        """Test JsonResponseCreated with no body."""
        response = JsonResponseCreated(location="/api/items/1/")
        self.assertEqual(response.status_code, 201)
        self.assertEqual(response["Location"], "/api/items/1/")
        self.assertEqual(json.loads(response.content), {})

    def test_json_response_not_allowed(self):
        """Test JsonResponseNotAllowed with Allow header."""
        response = JsonResponseNotAllowed(
            {"error": "POST not allowed"},
            permitted_methods=["GET", "HEAD"],
        )
        self.assertEqual(response.status_code, 405)
        self.assertEqual(response["Allow"], "GET, HEAD")
        self.assertEqual(json.loads(response.content), {"error": "POST not allowed"})
