import pytest
from django.contrib.auth import get_user_model
from model_bakery import baker
from products.models import Catalogs
from unittest.mock import patch
from django.core.files.uploadedfile import SimpleUploadedFile

Users = get_user_model()


@pytest.mark.django_db()
class TestCatalogsModel:
    def test_return_str_model(self):
        catalog = baker.make(Catalogs)
        assert str(catalog) == catalog.title


# Create your tests here.
@pytest.mark.django_db()
class TestCatalogsFetch:
    def setup_method(self):
        self.catalog_1 = baker.make(Catalogs, title="Catalog 1")
        self.catalog_2 = baker.make(Catalogs, title="Catalog 2")

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

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

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

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

        response = api_client.get(f"/api/products/catalogs/{self.catalog_1.id}/")

        assert response.status_code == 200
        assert response.data["id"] == str(self.catalog_1.id)


@pytest.mark.django_db()
class TestCatalogsCreate:
    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.user = baker.make(Users, is_staff=False)

        self.catalog_1 = baker.make(Catalogs, title="Catalog 1")
        self.catalog_2 = baker.make(Catalogs, title="Catalog 2")

    def test_create_catalog_by_non_admin_returns_403(self, authenticate_user):
        api_client = authenticate_user(user=self.user)

        data = {
            "title": "Created Catalog",
            "image_path": "/test/image.jpeg",
            "links": "www.example.com",
        }

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

        assert response.status_code == 403

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

        data = {
            "title": "Created Catalog",
            "image_path": "/test/image.jpeg",
            "links": "www.example.com",
        }

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

        assert response.status_code == 403

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

        data = {
            "title": "Created Catalog",
            "link": "www.example.com",
        }

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

        assert response.status_code == 400
        assert response.data["message"] == "No image provided. Please upload an image."

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

        data = {
            "title": "Catalog 1",
            "image_path": "test/image.jpeg",
            "link": "www.example.com",
        }

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

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

    @patch("products.views.R2")
    def test_create_catalog_by_shop_manager_or_web_admin_returns_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 = "/catalogs_images/image.jpg"
        mock_image = SimpleUploadedFile(
            "image.jpg", b"mock-image-content", content_type="image/jpeg"
        )

        data = {
            "title": "Created Catalog",
            "image_path": mock_image,
            "link": "www.example.com",
        }

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

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


@pytest.mark.django_db()
class TestCatalogsUpdate:
    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.user = baker.make(Users, is_staff=False)

        self.catalog_1 = baker.make(Catalogs, title="Catalog 1")
        self.catalog_2 = baker.make(Catalogs, title="Catalog 2")

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

        data = {
            "title": "Catalog 2",
            "image_path": "test/image.jpeg",
            "link": "www.example.com",
        }

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

        assert response.status_code == 403

    def test_update_catalog_by_non_admin_returns_403(self, authenticate_user):
        api_client = authenticate_user(user=self.user)

        data = {
            "title": "Catalog 2",
            "image_path": "test/image.jpeg",
            "link": "www.example.com",
        }

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

        assert response.status_code == 403

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

        data = {
            "title": "Catalog 2",
            "image_path": "test/image.jpeg",
            "link": "www.example.com",
        }

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

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

    @patch("products.views.R2")
    def test_update_catalog_with_new_image_by_shop_manager_or_web_admin_returns_200(
        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 = "/catalogs_images/image.jpg"
        mock_image = SimpleUploadedFile(
            "image.jpg", b"mock-image-content", content_type="image/jpeg"
        )

        data = {
            "title": "Updated Catalog",
            "image_path": mock_image,
            "link": "www.example.com",
        }

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

        assert response.status_code == 200
        assert response.data["id"] == str(self.catalog_1.id)

    @patch("products.views.R2")
    def test_update_catalog_with_no_new_image_by_shop_manager_or_web_admin_returns_200(
        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 = "/catalogs_images/image.jpg"

        data = {
            "title": "Updated Catalog",
            "link": "www.example.com",
        }

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

        assert response.status_code == 200
        assert response.data["id"] == str(self.catalog_1.id)


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

        self.user = baker.make(Users, is_staff=False)

        self.catalog_1 = baker.make(Catalogs, title="Catalog 1")

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

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

        assert response.status_code == 403

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

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

        assert response.status_code == 403

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

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

        assert response.status_code == 204
