import pytest, pytz
from django.contrib.auth import get_user_model
from model_bakery import baker
from products.models import Products, ProductGallery, Categories, Series
import json, uuid, pandas as pd
from django.core.files.uploadedfile import SimpleUploadedFile
from unittest.mock import patch
from datetime import datetime

Users = get_user_model()


@pytest.mark.django_db()
class TestProductsModel:
    def test_return_str_model(self):
        category = baker.make(Categories)
        modified_description = json.dumps({"delta": "", "html": "Hello World"})

        product = baker.make(
            Products, description=modified_description, category=category
        )
        assert (
            str(product)
            == f"{product.name} - {product.edp_number} | {'Active' if product.is_active else 'Inactive'}"
        )


@pytest.mark.django_db()
class TestProductsFetch:
    def setup_method(self):
        self.category_1 = baker.make(Categories, main_category_name=["Living"])
        self.category_2 = baker.make(Categories, main_category_name=["Dining"])
        self.modified_description = json.dumps({"delta": "", "html": "Hello World"})

        timezone = pytz.timezone("Asia/Manila")
        old_naive_dt = datetime(2025, 4, 4, 8, 0, 0)
        old_arrival_date = timezone.localize(old_naive_dt)

        latest_naive_dt = datetime(2025, 4, 4, 9, 0, 0)
        latest_arrival_date = timezone.localize(latest_naive_dt)

        self.product_1 = baker.make(
            Products,
            name="Z Product",
            price=100.0,
            description=self.modified_description,
            category=self.category_1,
            arrival_date=old_arrival_date,
        )
        self.product_2 = baker.make(
            Products,
            name="A Product",
            price=200.0,
            description=self.modified_description,
            category=self.category_2,
            arrival_date=latest_arrival_date,
        )

    def test_fetch_products_by_any_authenticated_user_to_view_price_return_200(
        self, authenticate_user
    ):
        api_client = authenticate_user()

        response = api_client.get("/api/products/products/")

        assert response.status_code == 200
        assert response.data["count"] == 2
        # Check atleast one product if 'price' key exists
        assert "price" in response.data["results"][0]

    def test_fetch_products_by_any_not_authenticated_user_to_hide_price_return_200(
        self, api_client
    ):
        response = api_client.get("/api/products/products/")

        assert response.status_code == 200
        assert response.data["count"] == 2
        # Check atleast one product if 'price' key is hidden
        assert "price" not in response.data["results"][0]

    def test_fetch_products_by_any_authenticated_user_with_search_return_200(
        self, authenticate_user
    ):
        api_client = authenticate_user()

        response = api_client.get(
            f"/api/products/products/?search={str(self.product_1.name)}"
        )

        assert response.status_code == 200
        assert response.data["count"] == 1

    def test_fetch_products_by_any_authenticated_user_with_price_filter_return_200(
        self, authenticate_user
    ):
        api_client = authenticate_user()

        response = api_client.get(
            "/api/products/products/?start_price=100&end_price=150"
        )

        assert response.status_code == 200
        assert response.data["count"] == 1

    def test_fetch_products_by_any_authenticated_user_with_sort_AtoZ_alphabetical_filter_return_200(
        self, authenticate_user
    ):
        api_client = authenticate_user()

        response = api_client.get("/api/products/products/?sort_by=a-z")

        assert response.status_code == 200
        assert response.data["count"] == 2
        assert response.data["results"][0]["name"].startswith("A")

    def test_fetch_products_by_any_authenticated_user_with_sort_ZtoA_alphabetical_filter_return_200(
        self, authenticate_user
    ):
        api_client = authenticate_user()

        response = api_client.get("/api/products/products/?sort_by=z-a")

        assert response.status_code == 200
        assert response.data["count"] == 2
        assert response.data["results"][0]["name"].startswith("Z")

    def test_fetch_products_by_any_authenticated_user_with_sort_oldest_filter_return_200(
        self, authenticate_user
    ):
        api_client = authenticate_user()

        response = api_client.get("/api/products/products/?sort_by=oldest")

        assert response.status_code == 200
        assert response.data["count"] == 2
        assert response.data["results"][0]["id"] == str(self.product_1.id)

    def test_fetch_products_by_any_authenticated_user_with_sort_newest_filter_return_200(
        self, authenticate_user
    ):
        api_client = authenticate_user()

        response = api_client.get("/api/products/products/?sort_by=newest")

        assert response.status_code == 200
        assert response.data["count"] == 2
        assert response.data["results"][0]["id"] == str(self.product_2.id)

    def test_fetch_products_by_any_authenticated_user_with_sort_price_LowToHigh_filter_return_200(
        self, authenticate_user
    ):
        api_client = authenticate_user()

        response = api_client.get("/api/products/products/?sort_by=price: low to high")

        assert response.status_code == 200
        assert response.data["count"] == 2
        assert response.data["results"][0]["id"] == str(self.product_1.id)

    def test_fetch_products_by_any_authenticated_user_with_sort_price_HighToLow_filter_return_200(
        self, authenticate_user
    ):
        api_client = authenticate_user()

        response = api_client.get("/api/products/products/?sort_by=price: high to low")

        assert response.status_code == 200
        assert response.data["count"] == 2
        assert response.data["results"][0]["id"] == str(self.product_2.id)

    def test_fetch_products_by_any_authenticated_user_with_main_category_filter_return_200(
        self, authenticate_user
    ):
        api_client = authenticate_user()

        response = api_client.get("/api/products/products/?main_category=living")

        assert response.status_code == 200
        assert response.data["count"] == 1
        assert response.data["results"][0]["id"] == str(self.product_1.id)

    def test_fetch_products_by_any_authenticated_user_with_start_arrival_date_filter_return_200(
        self, authenticate_user
    ):
        api_client = authenticate_user()

        response = api_client.get(
            f"/api/products/products/?start_arrival_date=2025-04-04"
        )

        assert response.status_code == 200
        assert response.data["count"] == 2

    def test_fetch_products_by_any_authenticated_user_with_start_and_end_arrival_date_filter_return_200(
        self, authenticate_user
    ):
        api_client = authenticate_user()

        response = api_client.get(
            f"/api/products/products/?start_arrival_date=2025-04-02&end_arrival_date=2025-04-03"
        )

        assert response.status_code == 200
        assert response.data["count"] == 0

    def test_fetch_ten_random_related_products_with_less_than_ten_existing_data_by_any_user_return_200(
        self, api_client
    ):
        for i in range(0, 8):
            baker.make(Products, price=100.0, description=self.modified_description)

        products_count = Products.objects.all().count()
        response = api_client.get("/api/products/products/related-products/")

        assert response.status_code == 200
        assert len(response.data) == products_count

    def test_fetch_ten_random_related_products_with_more_than_ten_existing_data_by_any_user_return_200(
        self, api_client
    ):
        for i in range(0, 9):
            baker.make(Products, price=100.0, description=self.modified_description)

        response = api_client.get("/api/products/products/related-products/")

        assert response.status_code == 200
        assert len(response.data) == 10

    def test_fetch_ten_random_related_products_by_any_user_but_an_exception_was_caught_return_500(
        self, api_client
    ):
        for i in range(0, 9):
            baker.make(Products, price=100.0, description=self.modified_description)

        with patch(
            "products.views.random.randint",
            side_effect=Exception("Mocked error"),
        ):
            response = api_client.get("/api/products/products/related-products/")

            assert response.status_code == 500
            assert (
                response.data["message"]
                == "An error occurred while retrieving related products. Try again."
            )

    def test_fetch_ten_random_related_products_but_no_existing_data_by_any_user_return_200_and_message(
        self, api_client
    ):
        # Delete all products
        Products.objects.all().delete()

        response = api_client.get("/api/products/products/related-products/")

        assert response.status_code == 200
        assert response.data["message"] == "No products were found."


@pytest.mark.django_db()
class TestProductsCreate:
    def setup_method(self):
        self.copywriter = baker.make(Users, is_staff=True, role="Copywriter")
        self.web_admin = baker.make(Users, is_staff=True, role="Web Admin")

        self.series = baker.make(Series)
        self.category = baker.make(Categories)
        self.modified_description = json.dumps({"delta": "", "html": "Hello World"})

        self.product_1 = baker.make(
            Products,
            name="Product 1",
            edp_number="EDP-000",
            article_number="ART-000",
            price=100.0,
            description=self.modified_description,
            category=self.category,
        )

    def test_create_product_by_non_admin_return_403(self, authenticate_user):
        api_client = authenticate_user()

        data = {
            "name": "Test Product",
            "image_path": "/test/product.jpeg",
            "edp_number": "ABC-123",
            "article_number": "ART-123",
            "description": "Test Description",
        }

        response = api_client.post("/api/products/products/", data=data)

        assert response.status_code == 403

    def test_create_product_by_non_shop_manager_or_web_admin_return_403(
        self, authenticate_user
    ):
        api_client = authenticate_user(user=self.copywriter)

        data = {
            "name": "Test Product",
            "image_path": "/test/product.jpeg",
            "edp_number": "ABC-123",
            "article_number": "ART-123",
            "description": "Test Description",
        }

        response = api_client.post("/api/products/products/", data=data)

        assert response.status_code == 403

    def test_create_product_by_shop_manager_or_web_admin_with_less_than_two_lifestyle_images_return_400(
        self, authenticate_user
    ):
        api_client = authenticate_user(user=self.web_admin)

        mock_image = SimpleUploadedFile(
            "image.jpg", b"mock-image-content", content_type="image/jpeg"
        )
        mock_lifestyle_image_1 = SimpleUploadedFile(
            "l_image_1.jpg", b"mock-image-content", content_type="image/jpeg"
        )

        data = {
            "name": "Test Product",
            "image_path": mock_image,
            "edp_number": "ABC-123",
            "article_number": "ART-123",
            "description": "Test Description",
            "finish": "Chrome",
            "size": "Large",
            "category": str(self.category.id),
            "price": 200.0,
            "lifestyle_images[]": [mock_lifestyle_image_1],
        }

        response = api_client.post("/api/products/products/", data=data)

        assert response.status_code == 400
        assert (
            response.data["message"]
            == "At least 2 lifestyle images are required per product."
        )

    def test_create_product_by_shop_manager_or_web_admin_with_existing_product_name_return_400(
        self, authenticate_user
    ):
        api_client = authenticate_user(user=self.web_admin)

        mock_image = SimpleUploadedFile(
            "image.jpg", b"mock-image-content", content_type="image/jpeg"
        )
        mock_lifestyle_image_1 = SimpleUploadedFile(
            "l_image_1.jpg", b"mock-image-content", content_type="image/jpeg"
        )
        mock_lifestyle_image_2 = SimpleUploadedFile(
            "l_image_2.jpg", b"mock-image-content", content_type="image/jpeg"
        )

        data = {
            "name": "Product 1",
            "image_path": mock_image,
            "edp_number": "ABC-123",
            "article_number": "ART-123",
            "description": "Test Description",
            "finish": "Chrome",
            "size": "Large",
            "category": str(self.category.id),
            "price": 200.0,
            "lifestyle_images[]": [mock_lifestyle_image_1, mock_lifestyle_image_2],
        }

        response = api_client.post("/api/products/products/", data=data)

        assert response.status_code == 400
        assert (
            response.data["message"]
            == f"Product with name {data['name'].title()} already exists."
        )

    def test_create_product_by_shop_manager_or_web_admin_with_existing_product_edp_return_400(
        self, authenticate_user
    ):
        api_client = authenticate_user(user=self.web_admin)

        mock_image = SimpleUploadedFile(
            "image.jpg", b"mock-image-content", content_type="image/jpeg"
        )
        mock_lifestyle_image_1 = SimpleUploadedFile(
            "l_image_1.jpg", b"mock-image-content", content_type="image/jpeg"
        )
        mock_lifestyle_image_2 = SimpleUploadedFile(
            "l_image_2.jpg", b"mock-image-content", content_type="image/jpeg"
        )

        data = {
            "name": "Product 2",
            "image_path": mock_image,
            "edp_number": "EDP-000",
            "article_number": "ART-123",
            "description": "Test Description",
            "finish": "Chrome",
            "size": "Large",
            "category": str(self.category.id),
            "price": 200.0,
            "lifestyle_images[]": [mock_lifestyle_image_1, mock_lifestyle_image_2],
        }

        response = api_client.post("/api/products/products/", data=data)

        assert response.status_code == 400
        assert (
            response.data["message"]
            == f"Product with EDP number {data['edp_number']} already exists."
        )

    # def test_create_product_by_shop_manager_or_web_admin_with_existing_product_article_number_return_400(
    #     self, authenticate_user
    # ):
    #     api_client = authenticate_user(user=self.web_admin)

    #     mock_image = SimpleUploadedFile(
    #         "image.jpg", b"mock-image-content", content_type="image/jpeg"
    #     )
    #     mock_lifestyle_image_1 = SimpleUploadedFile(
    #         "l_image_1.jpg", b"mock-image-content", content_type="image/jpeg"
    #     )
    #     mock_lifestyle_image_2 = SimpleUploadedFile(
    #         "l_image_2.jpg", b"mock-image-content", content_type="image/jpeg"
    #     )

    #     data = {
    #         "name": "Product 2",
    #         "image_path": mock_image,
    #         "edp_number": "EDP-001",
    #         "article_number": "ART-000",
    #         "description": "Test Description",
    #         "finish": "Chrome",
    #         "size": "Large",
    #         "category": str(self.category.id),
    #         "price": 200.0,
    #         "lifestyle_images[]": [mock_lifestyle_image_1, mock_lifestyle_image_2],
    #     }

    #     response = api_client.post("/api/products/products/", data=data)

    #     assert response.status_code == 400
    #     assert (
    #         response.data["message"]
    #         == f"Product with article number {data['article_number']} already exists."
    #     )

    def test_create_product_by_shop_manager_or_web_admin_with_non_existing_category_return_404(
        self, authenticate_user
    ):
        api_client = authenticate_user(user=self.web_admin)

        mock_image = SimpleUploadedFile(
            "image.jpg", b"mock-image-content", content_type="image/jpeg"
        )
        mock_lifestyle_image_1 = SimpleUploadedFile(
            "l_image_1.jpg", b"mock-image-content", content_type="image/jpeg"
        )
        mock_lifestyle_image_2 = SimpleUploadedFile(
            "l_image_2.jpg", b"mock-image-content", content_type="image/jpeg"
        )

        random_uuid = uuid.uuid4()

        data = {
            "name": "Product 2",
            "image_path": mock_image,
            "edp_number": "EDP-001",
            "article_number": "ART-123",
            "description": "Test Description",
            "finish": "Chrome",
            "size": "Large",
            "category": str(random_uuid),
            "price": 200.0,
            "lifestyle_images[]": [mock_lifestyle_image_1, mock_lifestyle_image_2],
        }

        response = api_client.post("/api/products/products/", data=data)

        assert response.status_code == 404
        assert response.data["message"] == "Selected category does not exists."

    def test_create_product_by_shop_manager_or_web_admin_with_non_existing_series_return_404(
        self, authenticate_user
    ):
        api_client = authenticate_user(user=self.web_admin)

        mock_image = SimpleUploadedFile(
            "image.jpg", b"mock-image-content", content_type="image/jpeg"
        )
        mock_lifestyle_image_1 = SimpleUploadedFile(
            "l_image_1.jpg", b"mock-image-content", content_type="image/jpeg"
        )
        mock_lifestyle_image_2 = SimpleUploadedFile(
            "l_image_2.jpg", b"mock-image-content", content_type="image/jpeg"
        )

        random_uuid = uuid.uuid4()

        data = {
            "name": "Product 2",
            "image_path": mock_image,
            "edp_number": "EDP-001",
            "article_number": "ART-123",
            "description": "Test Description",
            "finish": "Chrome",
            "size": "Large",
            "category": str(self.category.id),
            "series": str(random_uuid),
            "price": 200.0,
            "lifestyle_images[]": [mock_lifestyle_image_1, mock_lifestyle_image_2],
        }

        response = api_client.post("/api/products/products/", data=data)

        assert response.status_code == 404
        assert response.data["message"] == "Selected series does not exists."

    @patch("products.views.R2")
    def test_create_product_by_shop_manager_or_web_admin_return_201(
        self, mock_r2, authenticate_user
    ):
        api_client = authenticate_user(user=self.web_admin)

        mock_r2_instance = mock_r2.return_value
        mock_r2_instance.upload_fileobj.return_value = "/product_images/image.jpg"
        mock_image = SimpleUploadedFile(
            "image.jpg", b"mock-image-content", content_type="image/jpeg"
        )
        mock_lifestyle_image_1 = SimpleUploadedFile(
            "l_image_1.jpg", b"mock-image-content", content_type="image/jpeg"
        )
        mock_lifestyle_image_2 = SimpleUploadedFile(
            "l_image_2.jpg", b"mock-image-content", content_type="image/jpeg"
        )

        data = {
            "name": "Test Product",
            "image_path": mock_image,
            "edp_number": "ABC-123",
            "article_number": "ART-123",
            "description": "Test Description",
            "finish": "Chrome",
            "size": "Large",
            "category": str(self.category.id),
            "series": str(self.series.id),
            "price": 200.0,
            "lifestyle_images[]": [mock_lifestyle_image_1, mock_lifestyle_image_2],
        }

        response = api_client.post("/api/products/products/", data=data)

        assert response.status_code == 201
        assert response.data["id"] is not None


@pytest.mark.django_db()
class TestProductsUpdate:
    def setup_method(self):
        self.shop_manager = baker.make(Users, is_staff=True, role="Shop Manager")
        self.copywriter = baker.make(Users, is_staff=True, role="Copywriter")

        self.series = baker.make(Series)
        self.category = baker.make(Categories)
        self.modified_description = json.dumps({"delta": "", "html": "Hello World"})

        self.product_1 = baker.make(
            Products,
            name="Product 1",
            edp_number="EDP-000",
            article_number="ART-000",
            price=100.0,
            description=self.modified_description,
            category=self.category,
        )

        self.product_2 = baker.make(
            Products,
            name="Product Test",
            edp_number="EDP-TEST",
            article_number="ART-TEST",
            price=100.0,
            description=self.modified_description,
            category=self.category,
        )

        self.product_lifestyle_image_1 = baker.make(
            ProductGallery, product=self.product_1, image_path="test/image.jpeg"
        )

    def test_update_product_by_non_admin_return_403(self, authenticate_user):
        api_client = authenticate_user()

        data = {
            "name": "Test Product",
            "image_path": "/test/product.jpeg",
            "edp_number": "ABC-123",
            "article_number": "ART-123",
            "description": "Test Description",
        }

        response = api_client.put(
            f"/api/products/products/{self.product_1.id}/", data=data
        )

        assert response.status_code == 403

    def test_update_product_by_non_shop_manager_admin_return_403(
        self, authenticate_user
    ):
        api_client = authenticate_user(user=self.copywriter)

        data = {
            "name": "Test Product",
            "image_path": "/test/product.jpeg",
            "edp_number": "ABC-123",
            "article_number": "ART-123",
            "description": "Test Description",
        }

        response = api_client.put(
            f"/api/products/products/{self.product_1.id}/", data=data
        )

        assert response.status_code == 403

    # def test_update_product_with_less_than_two_lifestyle_images_by_shop_manager_admin_return_400(
    #     self, authenticate_user
    # ):
    #     api_client = authenticate_user(user=self.shop_manager)

    #     mock_image = SimpleUploadedFile(
    #         "image.jpg", b"mock-image-content", content_type="image/jpeg"
    #     )
    #     mock_lifestyle_image_1 = SimpleUploadedFile(
    #         "l_image_1.jpg", b"mock-image-content", content_type="image/jpeg"
    #     )

    #     data = {
    #         "name": "Test Product",
    #         "image_path": mock_image,
    #         "edp_number": "ABC-123",
    #         "article_number": "ART-123",
    #         "description": "Test Description",
    #         "finish": "Chrome",
    #         "size": "Large",
    #         "category": str(self.category.id),
    #         "series": str(self.series.id),
    #         "price": 200.0,
    #         "lifestyle_images[]": [mock_lifestyle_image_1],
    #     }

    #     response = api_client.put(
    #         f"/api/products/products/{self.product_1.id}/", data=data
    #     )

    #     assert response.status_code == 400
    #     assert (
    #         response.data["message"]
    #         == "At least 2 lifestyle images are required per product."
    #     )

    # def test_update_product_with_less_than_two_existing_images_by_shop_manager_admin_return_400(
    #     self, authenticate_user
    # ):
    #     api_client = authenticate_user(user=self.shop_manager)

    #     mock_image = SimpleUploadedFile(
    #         "image.jpg", b"mock-image-content", content_type="image/jpeg"
    #     )

    #     data = {
    #         "name": "Test Product",
    #         "image_path": mock_image,
    #         "edp_number": "ABC-123",
    #         "article_number": "ART-123",
    #         "description": "Test Description",
    #         "finish": "Chrome",
    #         "size": "Large",
    #         "category": str(self.category.id),
    #         "series": str(self.series.id),
    #         "price": 200.0,
    #         "existing_images_id[]": [self.product_lifestyle_image_1.id],
    #     }

    #     response = api_client.put(
    #         f"/api/products/products/{self.product_1.id}/", data=data
    #     )

    #     assert response.status_code == 400
    #     assert (
    #         response.data["message"]
    #         == "At least 2 lifestyle images are required per product."
    #     )

    @patch("products.views.R2")
    def test_update_product_without_existing_images_by_shop_manager_or_web_admin_return_200(
        self, mock_r2, authenticate_user
    ):
        api_client = authenticate_user(user=self.shop_manager)

        mock_r2_instance = mock_r2.return_value
        mock_r2_instance.upload_fileobj.return_value = "/product_images/image.jpg"
        mock_image = SimpleUploadedFile(
            "image.jpg", b"mock-image-content", content_type="image/jpeg"
        )
        mock_lifestyle_image_1 = SimpleUploadedFile(
            "l_image_1.jpg", b"mock-image-content", content_type="image/jpeg"
        )
        mock_lifestyle_image_2 = SimpleUploadedFile(
            "l_image_2.jpg", b"mock-image-content", content_type="image/jpeg"
        )

        data = {
            "name": "Test Product",
            "image_path": mock_image,
            "edp_number": "ABC-123",
            "article_number": "ART-123",
            "description": "Test Description",
            "finish": "Chrome",
            "size": "Large",
            "category": str(self.category.id),
            "series": str(self.series.id),
            "price": 200.0,
            "lifestyle_images[]": [mock_lifestyle_image_1, mock_lifestyle_image_2],
        }

        response = api_client.put(
            f"/api/products/products/{self.product_1.id}/", data=data
        )

        assert response.status_code == 200
        assert response.data["id"] is not None

    def test_update_product_with_existing_product_edp_by_shop_manager_or_web_admin_return_400(
        self, authenticate_user
    ):
        api_client = authenticate_user(user=self.shop_manager)

        mock_image = SimpleUploadedFile(
            "image.jpg", b"mock-image-content", content_type="image/jpeg"
        )
        mock_lifestyle_image_1 = SimpleUploadedFile(
            "l_image_1.jpg", b"mock-image-content", content_type="image/jpeg"
        )
        mock_lifestyle_image_2 = SimpleUploadedFile(
            "l_image_2.jpg", b"mock-image-content", content_type="image/jpeg"
        )

        data = {
            "name": "Product Sample",
            "image_path": mock_image,
            "edp_number": "EDP-TEST",
            "article_number": "ART-123",
            "description": "Test Description",
            "finish": "Chrome",
            "size": "Large",
            "category": str(self.category.id),
            "series": str(self.series.id),
            "price": 200.0,
            "lifestyle_images[]": [mock_lifestyle_image_1, mock_lifestyle_image_2],
            "existing_images_id[]": [self.product_lifestyle_image_1.id],
        }

        response = api_client.put(
            f"/api/products/products/{self.product_1.id}/", data=data
        )

        assert response.status_code == 400
        assert (
            response.data["message"]
            == f"Product with EDP number {data['edp_number']} already exists."
        )

    # def test_update_product_with_existing_product_article_number_by_shop_manager_or_web_admin_return_400(
    #     self, authenticate_user
    # ):
    #     api_client = authenticate_user(user=self.shop_manager)

    #     mock_image = SimpleUploadedFile(
    #         "image.jpg", b"mock-image-content", content_type="image/jpeg"
    #     )
    #     mock_lifestyle_image_1 = SimpleUploadedFile(
    #         "l_image_1.jpg", b"mock-image-content", content_type="image/jpeg"
    #     )
    #     mock_lifestyle_image_2 = SimpleUploadedFile(
    #         "l_image_2.jpg", b"mock-image-content", content_type="image/jpeg"
    #     )

    #     data = {
    #         "name": "Product Sample",
    #         "image_path": mock_image,
    #         "edp_number": "ABC-TEST",
    #         "article_number": "ART-TEST",
    #         "description": "Test Description",
    #         "finish": "Chrome",
    #         "size": "Large",
    #         "category": str(self.category.id),
    #         "series": str(self.series.id),
    #         "price": 200.0,
    #         "lifestyle_images[]": [mock_lifestyle_image_1, mock_lifestyle_image_2],
    #         "existing_images_id[]": [self.product_lifestyle_image_1.id],
    #     }

    #     response = api_client.put(
    #         f"/api/products/products/{self.product_1.id}/", data=data
    #     )

    #     assert response.status_code == 400
    #     assert (
    #         response.data["message"]
    #         == f"Product with article number {data['article_number']} already exists."
    #     )

    @patch("products.views.R2")
    def test_update_product_with_existing_images_by_shop_manager_or_web_admin_return_200(
        self, mock_r2, authenticate_user
    ):
        api_client = authenticate_user(user=self.shop_manager)

        mock_r2_instance = mock_r2.return_value
        mock_r2_instance.upload_fileobj.return_value = "/product_images/image.jpg"
        mock_image = SimpleUploadedFile(
            "image.jpg", b"mock-image-content", content_type="image/jpeg"
        )
        mock_lifestyle_image_1 = SimpleUploadedFile(
            "l_image_1.jpg", b"mock-image-content", content_type="image/jpeg"
        )
        mock_lifestyle_image_2 = SimpleUploadedFile(
            "l_image_2.jpg", b"mock-image-content", content_type="image/jpeg"
        )

        data = {
            "name": "Test Product",
            "image_path": mock_image,
            "edp_number": "ABC-123",
            "article_number": "ART-123",
            "description": "Test Description",
            "finish": "Chrome",
            "size": "Large",
            "category": str(self.category.id),
            "series": str(self.series.id),
            "price": 200.0,
            "lifestyle_images[]": [mock_lifestyle_image_1, mock_lifestyle_image_2],
            "existing_images_id[]": [self.product_lifestyle_image_1.id],
        }

        response = api_client.put(
            f"/api/products/products/{self.product_1.id}/", data=data
        )

        assert response.status_code == 200
        assert response.data["id"] is not None

    @patch("products.views.R2")
    def test_update_product_with_non_existing_category_by_shop_manager_or_web_admin_return_404(
        self, mock_r2, authenticate_user
    ):
        api_client = authenticate_user(user=self.shop_manager)

        mock_r2_instance = mock_r2.return_value
        mock_r2_instance.upload_fileobj.return_value = "/product_images/image.jpg"
        mock_image = SimpleUploadedFile(
            "image.jpg", b"mock-image-content", content_type="image/jpeg"
        )
        mock_lifestyle_image_1 = SimpleUploadedFile(
            "l_image_1.jpg", b"mock-image-content", content_type="image/jpeg"
        )
        mock_lifestyle_image_2 = SimpleUploadedFile(
            "l_image_2.jpg", b"mock-image-content", content_type="image/jpeg"
        )

        random_uuid = uuid.uuid4()

        data = {
            "name": "Test Product",
            "image_path": mock_image,
            "edp_number": "ABC-123",
            "article_number": "ART-123",
            "description": "Test Description",
            "finish": "Chrome",
            "size": "Large",
            "category": str(random_uuid),
            "series": str(self.series.id),
            "price": 200.0,
            "lifestyle_images[]": [mock_lifestyle_image_1, mock_lifestyle_image_2],
            "existing_images_id[]": [self.product_lifestyle_image_1.id],
        }

        response = api_client.put(
            f"/api/products/products/{self.product_1.id}/", data=data
        )

        assert response.status_code == 404
        assert response.data["message"] == "Selected category does not exists."

    @patch("products.views.R2")
    def test_update_product_with_non_existing_series_by_shop_manager_or_web_admin_return_404(
        self, mock_r2, authenticate_user
    ):
        api_client = authenticate_user(user=self.shop_manager)

        mock_r2_instance = mock_r2.return_value
        mock_r2_instance.upload_fileobj.return_value = "/product_images/image.jpg"
        mock_image = SimpleUploadedFile(
            "image.jpg", b"mock-image-content", content_type="image/jpeg"
        )
        mock_lifestyle_image_1 = SimpleUploadedFile(
            "l_image_1.jpg", b"mock-image-content", content_type="image/jpeg"
        )
        mock_lifestyle_image_2 = SimpleUploadedFile(
            "l_image_2.jpg", b"mock-image-content", content_type="image/jpeg"
        )

        random_uuid = uuid.uuid4()

        data = {
            "name": "Test Product",
            "image_path": mock_image,
            "edp_number": "ABC-123",
            "article_number": "ART-123",
            "description": "Test Description",
            "finish": "Chrome",
            "size": "Large",
            "category": str(self.category.id),
            "series": str(random_uuid),
            "price": 200.0,
            "lifestyle_images[]": [mock_lifestyle_image_1, mock_lifestyle_image_2],
            "existing_images_id[]": [self.product_lifestyle_image_1.id],
        }

        response = api_client.put(
            f"/api/products/products/{self.product_1.id}/", data=data
        )

        assert response.status_code == 404
        assert response.data["message"] == "Selected series does not exists."


@pytest.mark.django_db()
class TestProductsUploadFile:
    def setup_method(self):
        self.shop_manager = baker.make(Users, is_staff=True, role="Shop Manager")
        self.copywriter = baker.make(Users, is_staff=True, role="Copywriter")

        self.series = baker.make(Series)
        self.category = baker.make(Categories)
        self.modified_description = json.dumps({"delta": "", "html": "Hello World"})

        self.product_1 = baker.make(
            Products,
            name="Product 1",
            edp_number="EDP-000",
            article_number="ART-000",
            price=100.0,
            description=self.modified_description,
            category=self.category,
        )

    def test_upload_file_by_non_admin_return_403(self, authenticate_user):
        api_client = authenticate_user()

        mock_file = SimpleUploadedFile(
            "file.xlsx",
            b"mock-image-content",
            content_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
        )

        response = api_client.post(
            "/api/products/products/upload-products/", data={"file": mock_file}
        )

        assert response.status_code == 403

    def test_upload_file_by_non_shop_manager_or_web_admin_return_403(
        self, authenticate_user
    ):
        api_client = authenticate_user(user=self.copywriter)

        mock_file = SimpleUploadedFile(
            "file.xlsx",
            b"mock-image-content",
            content_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
        )

        response = api_client.post(
            "/api/products/products/upload-products/", data={"file": mock_file}
        )

        assert response.status_code == 403

    @patch("products.views.upload_products.delay")
    def test_upload_csv_file_by_shop_manager_or_web_admin_return_202(
        self, mock_upload, authenticate_user
    ):
        api_client = authenticate_user(user=self.shop_manager)

        mock_file = SimpleUploadedFile(
            "file.csv",
            b"mock,csv,content",
            content_type="text/csv",
        )

        response = api_client.post(
            "/api/products/products/upload-products/", data={"file": mock_file}
        )

        assert response.status_code == 202
        assert response.data["message"] == f"File {str(mock_file)} is being uploaded."
        mock_upload.assert_called_once()

    @patch("products.views.upload_products.delay")
    @patch("pandas.read_excel")
    def test_upload_excel_file_by_shop_manager_or_web_admin_return_202(
        self, mock_read_excel, mock_upload, authenticate_user
    ):
        api_client = authenticate_user(user=self.shop_manager)

        mock_file = SimpleUploadedFile(
            "file.xlsx",
            b"mock-excel-content",
            content_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
        )

        mock_read_excel.return_value = pd.DataFrame(
            {"name": ["Product1"], "price": [100]}
        )

        response = api_client.post(
            "/api/products/products/upload-products/", data={"file": mock_file}
        )

        assert response.status_code == 202
        assert response.data["message"] == f"File {str(mock_file)} is being uploaded."
        mock_upload.assert_called_once()

    def test_upload_file_with_invalid_format_by_shop_manager_or_web_admin_return_202(
        self, authenticate_user
    ):
        api_client = authenticate_user(user=self.shop_manager)

        mock_file = SimpleUploadedFile(
            "file.pdf",
            b"%PDF-1.4 mock pdf content",
            content_type="application/pdf",
        )

        response = api_client.post(
            "/api/products/products/upload-products/", data={"file": mock_file}
        )

        assert response.status_code == 400
        assert (
            response.data["message"]
            == "Invalid file format. Only CSV and Excel are supported"
        )


@pytest.mark.django_db()
class TestProductsDelete:
    def setup_method(self):
        self.superuser = baker.make(Users, is_staff=True, is_superuser=True)
        self.web_admin = baker.make(Users, is_staff=True, role="Web Admin")
        self.copywriter = baker.make(Users, is_staff=True, role="Copywriter")

        self.series = baker.make(Series)
        self.category = baker.make(Categories)
        self.modified_description = json.dumps({"delta": "", "html": "Hello World"})

        self.product_1 = baker.make(
            Products,
            name="Product 1",
            image_path="/test/image.jpeg",
            edp_number="EDP-000",
            article_number="ART-000",
            price=100.0,
            description=self.modified_description,
            category=self.category,
        )

        self.product_lifestyle_image_1 = baker.make(
            ProductGallery,
            product=self.product_1,
            image_path="/test/lifestyle_image.jpeg",
        )

    def test_delete_product_by_non_admin_return_403(self, authenticate_user):
        api_client = authenticate_user()

        response = api_client.delete(f"/api/products/products/{self.product_1.id}/")

        assert response.status_code == 403

    def test_delete_product_by_non_shop_manager_or_web_admin_or_superuser_admin_return_403(
        self, authenticate_user
    ):
        api_client = authenticate_user(user=self.copywriter)

        response = api_client.delete(f"/api/products/products/{self.product_1.id}/")

        assert response.status_code == 403

    def test_delete_product_by_shop_manager_or_web_admin_or_superuser_return_204(
        self, authenticate_user
    ):
        api_client = authenticate_user(user=self.superuser)

        response = api_client.delete(f"/api/products/products/{self.product_1.id}/")

        assert response.status_code == 204
