# Copyright (C) 2018-2025 by BDE ENS Paris-Saclay
# SPDX-License-Identifier: GPL-3.0-or-later

from api.tests import TestAPI
from django.contrib.auth.models import User
from django.test import TestCase
from django.urls import reverse
from django.utils import timezone
from activity.models import Activity, ActivityType
from member.models import Club

from ..api.views import AllergenViewSet, BasicFoodViewSet, TransformedFoodViewSet, QRCodeViewSet, \
    DishViewSet, SupplementViewSet, OrderViewSet, FoodTransactionViewSet
from ..models import Allergen, BasicFood, TransformedFood, QRCode, Dish, Supplement, Order  # TODO FoodTransaction


class TestFood(TestCase):
    """
    Test food
    """
    fixtures = ('initial',)

    def setUp(self):
        self.user = User.objects.create_superuser(
            username='admintoto',
            password='toto1234',
            email='toto@example.com'
        )
        self.client.force_login(self.user)

        sess = self.client.session
        sess['permission_mask'] = 42
        sess.save()

        self.allergen = Allergen.objects.create(
            name='allergen',
        )

        self.basicfood = BasicFood.objects.create(
            name='basicfood',
            owner_id=1,
            expiry_date=timezone.now(),
            is_ready=False,
            date_type='DLC',
        )

        self.transformedfood = TransformedFood.objects.create(
            name='transformedfood',
            owner_id=1,
            expiry_date=timezone.now(),
            is_ready=False,
        )

        self.qrcode = QRCode.objects.create(
            qr_code_number=1,
            food_container=self.basicfood,
        )

    def test_food_list(self):
        """
        Display food list
        """
        response = self.client.get(reverse('food:food_list'))
        self.assertEqual(response.status_code, 200)

    def test_qrcode_create(self):
        """
        Display QRCode creation
        """
        response = self.client.get(reverse('food:qrcode_create', kwargs={"slug": 2}))
        self.assertEqual(response.status_code, 200)

    def test_basicfood_create(self):
        """
        Display BasicFood creation
        """
        response = self.client.get(reverse('food:basicfood_create', kwargs={"slug": 2}))
        self.assertEqual(response.status_code, 200)

    def test_transformedfood_create(self):
        """
        Display TransformedFood creation
        """
        response = self.client.get(reverse('food:transformedfood_create'))
        self.assertEqual(response.status_code, 200)

    def test_food_update(self):
        """
        Display Food update
        """
        response = self.client.get(reverse('food:food_update', args=(self.basicfood.pk,)))
        self.assertEqual(response.status_code, 200)

    def test_food_view(self):
        """
        Display Food detail
        """
        response = self.client.get(reverse('food:food_view', args=(self.basicfood.pk,)))
        self.assertEqual(response.status_code, 302)

    def test_basicfood_view(self):
        """
        Display BasicFood detail
        """
        response = self.client.get(reverse('food:basicfood_view', args=(self.basicfood.pk,)))
        self.assertEqual(response.status_code, 200)

    def test_transformedfood_view(self):
        """
        Display TransformedFood detail
        """
        response = self.client.get(reverse('food:transformedfood_view', args=(self.transformedfood.pk,)))
        self.assertEqual(response.status_code, 200)

    def test_add_ingredient(self):
        """
        Display add ingredient view
        """
        response = self.client.get(reverse('food:add_ingredient', args=(self.transformedfood.pk,)))
        self.assertEqual(response.status_code, 200)


'''class TestFoodOrder(TestCase):
    """
    Test Food Order
    """
    fixtures = ('initial',)

    def setUp(self):
        self.user = User.objects.create_superuser(
            username='admintoto',
            password='toto1234',
            email='toto@example.com'
        )
        self.client.force_login(self.user)

        sess = self.client.session
        sess['permission_mask'] = 42
        sess.save()

        self.basicfood = BasicFood.objects.create(
            id=1,
            name='basicfood',
            owner=Club.objects.get(name="BDE"),
            expiry_date=timezone.now(),
            is_ready=True,
            date_type='DLC',
        )

        self.transformedfood = TransformedFood.objects.create(
            id=2,
            name='transformedfood',
            owner=Club.objects.get(name="BDE"),
            expiry_date=timezone.now(),
            is_ready=True,
        )

        self.second_transformedfood = TransformedFood.objects.create(
            id=3,
            name='second transformedfood',
            owner=Club.objects.get(name="BDE"),
            expiry_date=timezone.now(),
            is_ready=True,
        )

        self.third_transformedfood = TransformedFood.objects.create(
            id=4,
            name='third transformedfood',
            owner=Club.objects.get(name="BDE"),
            expiry_date=timezone.now(),
            is_ready=True,
        )

        self.activity = Activity.objects.create(
            activity_type=ActivityType.objects.get(name="Perm bouffe"),
            organizer=Club.objects.get(name="BDE"),
            creater=self.user,
            attendees_club_id=1,
            date_start=timezone.now(),
            date_end=timezone.now(),
            name="Test activity",
            open=True,
            valid=True,
        )

        self.dish = Dish.objects.create(
            main=self.transformedfood,
            price=500,
            activity=self.activity,
            available=True,
        )

        self.second_dish = Dish.objects.create(
            main=self.second_transformedfood,
            price=1000,
            activity=self.activity,
            available=True,
        )

        self.supplement = Supplement.objects.create(
            dish=self.dish,
            food=self.basicfood,
            price=100,
        )

        self.order = Order.objects.create(
            user=self.user,
            activity=self.activity,
            dish=self.dish,
        )
        self.order.supplements.add(self.supplement)
        self.order.save()

    def test_dish_list(self):
        """
        Try to display dish list
        """
        response = self.client.get(reverse("food:dish_list", kwargs={"activity_pk": self.activity.pk}))
        self.assertEqual(response.status_code, 200)

    def test_dish_create(self):
        """
        Try to create a dish
        """
        response = self.client.get(reverse("food:dish_create", kwargs={"activity_pk": self.activity.pk}))
        self.assertEqual(response.status_code, 200)

        response = self.client.post(reverse("food:dish_create", kwargs={"activity_pk": self.activity.pk}), data={
            "main": self.third_transformedfood.pk,
            "price": 4,
            "activity": self.activity.pk,
            "supplements-0-food": self.basicfood.pk,
            "supplements-0-price": 0.5,
            "supplements-TOTAL_FORMS": 1,
            "supplements-INITIAL_FORMS": 0,
            "supplements-MIN_NUM_FORMS": 0,
            "supplements-MAX_NUM_FORMS": 1000,
        })
        self.assertRedirects(response, reverse("food:dish_list", kwargs={"activity_pk": self.activity.pk}), 302, 200)
        self.assertTrue(Dish.objects.filter(main=self.third_transformedfood).exists())
        self.assertTrue(Supplement.objects.filter(food=self.basicfood, price=50).exists())

    def test_dish_update(self):
        """
        Try to update a dish
        """
        response = self.client.get(reverse("food:dish_update", kwargs={"activity_pk": self.activity.pk, "pk": self.dish.pk}))
        self.assertEqual(response.status_code, 200)

        response = self.client.post(reverse("food:dish_update", kwargs={"activity_pk": self.activity.pk, "pk": self.dish.pk}), data={
            "price": 6,
            "supplements-0-food": self.basicfood.pk,
            "supplements-0-price": 1,
            "supplements-1-food": self.basicfood.pk,
            "supplements-1-price": 0.25,
            "supplements-TOTAL_FORMS": 2,
            "supplements-INITIAL_FORMS": 0,
            "supplements-MIN_NUM_FORMS": 0,
            "supplements-MAX_NUM_FORMS": 1000,
        })
        self.assertRedirects(response, reverse("food:dish_detail", kwargs={"activity_pk": self.activity.pk, "pk": self.dish.pk}), 302, 200)
        self.dish.refresh_from_db()
        self.assertTrue(Dish.objects.filter(main=self.transformedfood, price=600).exists())
        self.assertTrue(Supplement.objects.filter(dish=self.dish, food=self.basicfood, price=25).exists())

    def test_dish_detail(self):
        """
        Try to display dish details
        """
        response = self.client.get(reverse("food:dish_detail", kwargs={"activity_pk": self.activity.pk, "pk": self.dish.pk}))
        self.assertEqual(response.status_code, 200)

    def test_dish_delete(self):
        """
        Try to delete a dish
        """
        response = self.client.get(reverse("food:dish_delete", kwargs={"activity_pk": self.activity.pk, "pk": self.dish.pk}))
        self.assertEqual(response.status_code, 200)

        # Cannot delete already ordered Dish
        response = self.client.delete(reverse("food:dish_delete", kwargs={"activity_pk": self.activity.pk, "pk": self.dish.pk}))
        self.assertEqual(response.status_code, 403)
        self.assertTrue(Dish.objects.filter(pk=self.dish.pk).exists())

        # Can delete a Dish with no order
        response = self.client.delete(reverse("food:dish_delete", kwargs={"activity_pk": self.activity.pk, "pk": self.second_dish.pk}))
        self.assertRedirects(response, reverse("food:dish_list", kwargs={"activity_pk": self.activity.pk}))
        self.assertFalse(Dish.objects.filter(pk=self.second_dish.pk).exists())

    def test_order_food(self):
        """
        Try to make an order
        """
        response = self.client.get(reverse("food:order_create", kwargs={"activity_pk": self.activity.pk}))
        self.assertEqual(response.status_code, 200)

        response = self.client.post(reverse("food:order_create", kwargs={"activity_pk": self.activity.pk}), data=dict(
            user=self.user.pk,
            activity=self.activity.pk,
            dish=self.second_dish.pk,
            supplements=self.supplement.pk
        ))
        self.assertRedirects(response, reverse("food:food_list"))
        self.assertTrue(Order.objects.filter(user=self.user, dish=self.second_dish, activity=self.activity).exists())

    def test_order_list(self):
        """
        Try to display order list
        """
        response = self.client.get(reverse("food:order_list", kwargs={"activity_pk": self.activity.pk}))
        self.assertEqual(response.status_code, 200)

    def test_served_order_list(self):
        """
        Try to display served order list
        """
        response = self.client.get(reverse("food:served_order_list", kwargs={"activity_pk": self.activity.pk}))
        self.assertEqual(response.status_code, 200)

    def test_serve_order(self):
        """
        Try to serve an order, then to unserve it
        """
        response = self.client.patch("/api/food/order/" + str(self.order.pk) + "/", data=dict(
            served=True
        ), content_type="application/json")
        self.assertEqual(response.status_code, 200)
        self.order.refresh_from_db()
        self.assertTrue(Order.objects.filter(dish=self.dish, user=self.user, served=True).exists())
        self.assertIsNotNone(self.order.served_at)

        self.assertTrue(FoodTransaction.objects.filter(order=self.order, valid=True).exists())

        response = self.client.patch("/api/food/order/" + str(self.order.pk) + "/", data=dict(
            served=False
        ), content_type="application/json")
        self.assertEqual(response.status_code, 200)
        self.assertTrue(Order.objects.filter(dish=self.dish, user=self.user, served=False).exists())

        self.assertTrue(FoodTransaction.objects.filter(order=self.order, valid=False).exists())'''


class TestFoodAPI(TestAPI):
    def setUp(self) -> None:
        super().setUp()

        self.allergen = Allergen.objects.create(
            name='name',
        )

        self.basicfood = BasicFood.objects.create(
            name='basicfood',
            owner_id=1,
            expiry_date=timezone.now(),
            is_ready=False,
            date_type='DLC',
        )

        self.transformedfood = TransformedFood.objects.create(
            name='transformedfood',
            owner_id=1,
            expiry_date=timezone.now(),
            is_ready=False,
        )

        self.qrcode = QRCode.objects.create(
            qr_code_number=1,
            food_container=self.basicfood,
        )

        self.activity = Activity.objects.create(
            activity_type=ActivityType.objects.get(name="Perm bouffe"),
            organizer=Club.objects.get(name="BDE"),
            creater=self.user,
            attendees_club_id=1,
            date_start=timezone.now(),
            date_end=timezone.now(),
            name="Test activity",
            open=True,
            valid=True,
        )

        self.dish = Dish.objects.create(
            main=self.transformedfood,
            price=500,
            activity=self.activity,
            available=True,
        )

        self.supplement = Supplement.objects.create(
            dish=self.dish,
            food=self.basicfood,
            price=100,
        )

        self.order = Order.objects.create(
            user=self.user,
            activity=self.activity,
            dish=self.dish,
        )
        self.order.supplements.add(self.supplement)
        self.order.save()

    def test_allergen_api(self):
        """
        Load Allergen API page and test all filters and permissions
        """
        self.check_viewset(AllergenViewSet, '/api/food/allergen/')

    def test_basicfood_api(self):
        """
        Load BasicFood API page and test all filters and permissions
        """
        self.check_viewset(BasicFoodViewSet, '/api/food/basicfood/')

        # TODO Repair and detabulate this test
        def test_transformedfood_api(self):
            """
            Load TransformedFood API page and test all filters and permissions
            """
            self.check_viewset(TransformedFoodViewSet, '/api/food/transformedfood/')

    def test_qrcode_api(self):
        """
        Load QRCode API page and test all filters and permissions
        """
        self.check_viewset(QRCodeViewSet, '/api/food/qrcode/')

    def test_dish_api(self):
        """
        Load Dish API page and test all filters and permissions
        """
        self.check_viewset(DishViewSet, '/api/food/dish/')

    def test_supplement_api(self):
        """
        Load Supplement API page and test all filters and permissions
        """
        self.check_viewset(SupplementViewSet, '/api/food/supplement/')

    def test_order_api(self):
        """
        Load Order API page and test all filters and permissions
        """
        self.check_viewset(OrderViewSet, '/api/food/order/')

    def test_foodtransaction_api(self):
        """
        Load FoodTransaction API page and test all filters and permissions
        """
        self.check_viewset(FoodTransactionViewSet, '/api/food/foodtransaction/')
