import shutil
from core.factories import IngredientFactory, RecipeFactory
from django.contrib.auth import get_user_model
from django.conf import settings
from django.urls import reverse
from django.test import TestCase, override_settings

from rest_framework import status
from rest_framework.test import APIClient

from core.models import Ingredient

from recipe.serializers import IngredientSerializer


INGREDIENT_URL = reverse("recipe:ingredient-list")


class PublicIngredientApiTest(TestCase):
    """Test publicly available ingredients API"""

    def setUp(self):
        self.client = APIClient()

    def test_login_required(self):
        """Test that login is required to access the endpoint"""
        res = self.client.get(INGREDIENT_URL)

        self.assertEqual(res.status_code, status.HTTP_401_UNAUTHORIZED)


@override_settings(MEDIA_ROOT=settings.TEST_MEDIA_ROOT)
class PrivateIngredientApiTest(TestCase):
    """Test ingredients can retreived by authorized user"""

    def setUp(self):
        self.client = APIClient()
        self.user = get_user_model().objects.create_user("<EMAIL>", "<PASSWORD>")
        self.client.force_authenticate(self.user)
        IngredientFactory.reset_sequence()

    def tearDown(self):
        shutil.rmtree(settings.TEST_MEDIA_ROOT)

    def test_retrieving_ingredient_list(self):
        """Test retrieving a list of ingredients"""
        IngredientFactory.create_batch(2, user=self.user)

        res = self.client.get(INGREDIENT_URL)
        ingredients = Ingredient.objects.all().order_by("-name")
        serializer = IngredientSerializer(ingredients, many=True)
        self.assertEqual(res.status_code, status.HTTP_200_OK)
        self.assertEqual(serializer.data, res.data)

    def test_ingredients_limited_to_user(self):
        """Test only ingredients for the authenticated user are returned"""
        user2 = get_user_model().objects.create_user("<EMAIL>", "<PASSWORD>")
        IngredientFactory.create(user=user2)
        ingredient = IngredientFactory.create(user=self.user)

        res = self.client.get(INGREDIENT_URL)
        self.assertEqual(res.status_code, status.HTTP_200_OK)
        self.assertEqual(len(res.data), 1)
        self.assertEqual(res.data[0]["name"], ingredient.name)

    def test_create_ingredient_successful(self):
        """Test create a new ingredient"""
        payload = {"name": "Cabbage"}
        self.client.post(INGREDIENT_URL, payload)

        exists = Ingredient.objects.filter(user=self.user, name=payload["name"]).exists()
        self.assertTrue(exists)

    def test_create_ingredient_invalid(self):
        """Test creating invalid ingredient fails"""
        payload = {"name": ""}
        res = self.client.post(INGREDIENT_URL, payload)

        self.assertEqual(res.status_code, status.HTTP_400_BAD_REQUEST)

    def test_retrieve_ingredients_assigned_to_recipes(self):
        """Test filtering ingredients by those assinged to recipes"""
        ingredient1 = IngredientFactory.create(user=self.user)
        ingredient2 = IngredientFactory.create(user=self.user)
        recipe = RecipeFactory.create(user=self.user)
        recipe.ingredients.add(ingredient1)

        res = self.client.get(INGREDIENT_URL, {"assigned_only": 1})

        serializer1 = IngredientSerializer(ingredient1)
        serializer2 = IngredientSerializer(ingredient2)
        self.assertIn(serializer1.data, res.data)
        self.assertNotIn(serializer2.data, res.data)

import shutil
from core.factories import IngredientFactory, RecipeFactory
from django.contrib.auth import get_user_model
from django.conf import settings
from django.urls import reverse
from django.test import TestCase, override_settings

from rest_framework import status
from rest_framework.test import APIClient

from core.models import Ingredient

from recipe.serializers import IngredientSerializer


INGREDIENT_URL = reverse("recipe:ingredient-list")


class PublicIngredientApiTest(TestCase):
    """Test publicly available ingredients API"""

    def setUp(self):
        self.client = APIClient()

    def test_login_required(self):
        """Test that login is required to access the endpoint"""
        res = self.client.get(INGREDIENT_URL)

        self.assertEqual(res.status_code, status.HTTP_401_UNAUTHORIZED)


@override_settings(MEDIA_ROOT=settings.TEST_MEDIA_ROOT)
class PrivateIngredientApiTest(TestCase):
    """Test ingredients can retreived by authorized user"""

    def setUp(self):
        self.client = APIClient()
        self.user = get_user_model().objects.create_user("<EMAIL>", "<PASSWORD>")
        self.client.force_authenticate(self.user)
        IngredientFactory.reset_sequence()

    def tearDown(self):
        shutil.rmtree(settings.TEST_MEDIA_ROOT)

    def test_retrieving_ingredient_list(self):
        """Test retrieving a list of ingredients"""
        IngredientFactory.create_batch(2, user=self.user)

        res = self.client.get(INGREDIENT_URL)
        ingredients = Ingredient.objects.all().order_by("-name")
        serializer = IngredientSerializer(ingredients, many=True)
        self.assertEqual(res.status_code, status.HTTP_200_OK)
        self.assertEqual(serializer.data, res.data)

    def test_ingredients_limited_to_user(self):
        """Test only ingredients for the authenticated user are returned"""
        user2 = get_user_model().objects.create_user("<EMAIL>", "<PASSWORD>")
        IngredientFactory.create(user=user2)
        ingredient = IngredientFactory.create(user=self.user)

        res = self.client.get(INGREDIENT_URL)
        self.assertEqual(res.status_code, status.HTTP_200_OK)
        self.assertEqual(len(res.data), 1)
        self.assertEqual(res.data[0]["name"], ingredient.name)

    def test_create_ingredient_successful(self):
        """Test create a new ingredient"""
        payload = {"name": "Cabbage"}
        self.client.post(INGREDIENT_URL, payload)

        exists = Ingredient.objects.filter(user=self.user, name=payload["name"]).exists()
        self.assertTrue(exists)

    def test_create_ingredient_invalid(self):
        """Test creating invalid ingredient fails"""
        payload = {"name": ""}
        res = self.client.post(INGREDIENT_URL, payload)

        self.assertEqual(res.status_code, status.HTTP_400_BAD_REQUEST)

    def test_retrieve_ingredients_assigned_to_recipes(self):
        """Test filtering ingredients by those assinged to recipes"""
        ingredient1 = IngredientFactory.create(user=self.user)
        ingredient2 = IngredientFactory.create(user=self.user)
        recipe = RecipeFactory.create(user=self.user)
        recipe.ingredients.add(ingredient1)

        res = self.client.get(INGREDIENT_URL, {"assigned_only": 1})

        serializer1 = IngredientSerializer(ingredient1)
        serializer2 = IngredientSerializer(ingredient2)
        self.assertIn(serializer1.data, res.data)
        self.assertNotIn(serializer2.data, res.data)

Test publicly available ingredients API Test that login is required to access the endpoint Test ingredients can retreived by authorized user Test retrieving a list of ingredients Test only ingredients for the authenticated user are returned Test create a new ingredient Test creating invalid ingredient fails Test filtering ingredients by those assinged to recipes