from django.db import IntegrityError
from django.urls import reverse
from rest_framework import status
from rest_framework.test import APITestCase, APIClient
from django.core.exceptions import ValidationError
import json

from .models import Post, PostComment
from User.models import BasicUser
from .serializers import PostSerializer, SimplePostSerializer, CommentSerializer


# Test Post and Comment Models
class TestModels(APITestCase):
    def setUp(self):
        self.testUser = BasicUser.objects.create(
            username="NormalUser",
            email="normaluser@example.com",
            first_name="Normal",
            last_name="User",
            password="pass"
        )
        self.anonymous_post = Post.objects.create(
            title="Test Post",
            text="body",
            topics=["Pandemic"]
        )
        self.normal_post = Post.objects.create(
            title="Normal Post",
            text="body",
            topics=["Pandemic"],
            user=self.testUser
        )
        self.comment = PostComment.objects.create(
            text="comment",
            user=self.testUser,
            post=self.anonymous_post
        )

    # Create Normal Post without User should default to Anonymous User
    def test_create_post(self):
        self.assertEqual(self.anonymous_post.user.first_name, "Anonymous")
        self.assertEqual(self.anonymous_post.user.last_name, "User")

    # Create Normal Post with User
    def test_normal_post(self):
        self.assertEqual(self.normal_post.user.first_name, "Normal")
        self.assertEqual(self.normal_post.user.last_name, "User")

    # Create a Comment
    def test_comment(self):
        self.assertEqual(self.comment.text, "comment")
        self.assertEqual(self.comment.user.first_name, "Normal")
        self.assertEqual(self.comment.user.last_name, "User")
        self.assertEqual(self.comment.post.id, self.anonymous_post.id)

    # Create Post without Title
    def test_create_post_without_title(self):
        try:
            post = Post.objects.create(
                text="body",
                topics=["Pandemic"],
                user=self.testUser
            )
            post.full_clean()
            self.assertEquals(True, False)
        except ValidationError:
            return True

    # Create Post without Text
    def test_create_post_without_text(self):
        try:
            post = Post.objects.create(
                title="title",
                topics=["Pandemic"],
                user=self.testUser
            )
            post.full_clean()
            self.assertEquals(True, False)
        except ValidationError:
            return True

    # Create Post without Topics
    def test_create_post_without_topics(self):
        try:
            post = Post.objects.create(
                title="title",
                text="body",
                user=self.testUser
            )
            post.full_clean()
            self.assertEquals(True, False)
        except IntegrityError:
            return True

# Test Post and Comment Views


class TestViews(APITestCase):
    def setUp(self):
        self.user = BasicUser.objects.get_or_create(
            username="AnonymousUser",
            email="anonymoususer@example.com",
            first_name="Anonymous",
            last_name="User",
            defaults={'password': "pass"}
        )
        self.client = APIClient()
        self.client.force_authenticate(user=self.user)
        self.testUser = BasicUser.objects.create(
            username="NormalUser",
            email="normaluser@example.com",
            first_name="Normal",
            last_name="User",
            password="pass"
        )
        self.anonymous_post = Post.objects.create(
            title="Test Post",
            text="body",
            topics=["Extreme Weather", "Pandemic"]
        )
        self.normal_post = Post.objects.create(
            title="Normal Post",
            text="body",
            topics=["Pandemic", "Rising Temperatures"],
            user=self.testUser
        )
        self.comment = PostComment.objects.create(
            text="comment",
            user=self.testUser,
            post=self.anonymous_post
        )

    def test_get_all_posts(self):
        response = self.client.get(reverse('Post:get_post_posts'))
        posts = Post.objects.all()
        serializer = SimplePostSerializer(posts, many=True)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(response.data, serializer.data)

    def test_get_all_posts_specific_topics(self):
        response = self.client.get(path=reverse(
            'Post:get_post_posts')+"""?topics=["Pandemic"]""")
        posts = Post.objects.all().filter(topics__contained_by=['Pandemic'])
        serializer = SimplePostSerializer(posts, many=True)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(response.data), len(serializer.data))

    def test_get_a_specific_post_and_comments(self):
        response = self.client.get(f"/posts/{self.anonymous_post.id}/")
        post = Post.objects.get(pk=self.anonymous_post.id)
        serializer = PostSerializer(post)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(response.data, serializer.data)

    def test_get_an_invalid_post(self):
        response = self.client.get(f"/posts/-50/")
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

    def test_create_a_post(self):
        response = self.client.post(
            path=reverse("Post:get_post_posts"),
            data=json.dumps({
                "title": "hello",
                "text": "hi",
                "topics": ["Pandemic"]
            }),
            format='json'
        )
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

    def test_create_invalid_post(self):
        response = self.client.post(
            path=reverse("Post:get_post_posts"),
            data=json.dumps({
                "text": "hi",
                "topics": ["Pandemic"]
            }),
            format='json'
        )
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_create_a_comment_post(self):
        response = self.client.post(
            path=f"/posts/{self.anonymous_post.id}/comments/",
            data=json.dumps({
                "text": "hi"
            }),
            format='json'
        )
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
