from django.test import TestCase
from django.urls import reverse

from django.core.exceptions import ValidationError

from apps.products.models import (
    Article,
    ArticleSection,
    MainProduct,
    SubProduct,
    SubProductVersion,
)


class MainProductModelTest(TestCase):
    def setUp(self):
        self.product = MainProduct.objects.create(
            name="Test Product",
            short_description="Short description",
            description="Full description of the test product.",
        )

    def test_str_representation(self):
        self.assertEqual(str(self.product), "Test Product")

    def test_slug_auto_generated_on_create(self):
        self.assertEqual(self.product.slug, "test-product")

    def test_slug_not_overwritten_on_update(self):
        self.product.name = "Changed Name"
        self.product.save()
        self.assertEqual(self.product.slug, "test-product")

    def test_default_order_is_zero(self):
        self.assertEqual(self.product.order, 0)

    def test_default_is_active_is_true(self):
        self.assertTrue(self.product.is_active)

    def test_get_absolute_url(self):
        url = self.product.get_absolute_url()
        self.assertEqual(url, reverse("products:main_product_detail", kwargs={"main_slug": "test-product"}))

    def test_slug_uniqueness(self):
        from django.db import IntegrityError
        with self.assertRaises(IntegrityError):
            MainProduct.objects.create(
                name="Test Product",
                slug="test-product",
                short_description="Another",
                description="Another",
            )

    def test_timestamps_set_on_create(self):
        self.assertIsNotNone(self.product.created_at)
        self.assertIsNotNone(self.product.updated_at)


class SubProductModelTest(TestCase):
    def setUp(self):
        self.main_product = MainProduct.objects.create(
            name="Main Product",
            short_description="Short",
            description="Description",
        )
        self.sub_product = SubProduct.objects.create(
            main_product=self.main_product,
            name="Sub Product",
            short_description="Sub short",
            description="Sub description.",
        )

    def test_str_representation(self):
        self.assertIn("Main Product", str(self.sub_product))
        self.assertIn("Sub Product", str(self.sub_product))

    def test_slug_auto_generated(self):
        self.assertEqual(self.sub_product.slug, "sub-product")

    def test_get_absolute_url(self):
        url = self.sub_product.get_absolute_url()
        expected = reverse(
            "products:sub_product_detail",
            kwargs={"main_slug": "main-product", "sub_slug": "sub-product"},
        )
        self.assertEqual(url, expected)

    def test_cascade_delete_with_main_product(self):
        main_pk = self.main_product.pk
        sub_pk = self.sub_product.pk
        self.main_product.delete()
        self.assertFalse(SubProduct.objects.filter(pk=sub_pk).exists())
        self.assertFalse(MainProduct.objects.filter(pk=main_pk).exists())


class ArticleModelTest(TestCase):
    def setUp(self):
        self.main_product = MainProduct.objects.create(
            name="Main",
            short_description="Short",
            description="Desc",
        )
        self.sub_product = SubProduct.objects.create(
            main_product=self.main_product,
            name="Sub",
            short_description="Short",
            description="Desc",
        )
        self.article = Article.objects.create(
            sub_product=self.sub_product,
            title="Test Article",
            description="Article body.",
        )

    def test_str_representation(self):
        self.assertEqual(str(self.article), "Test Article")

    def test_cascade_delete_with_sub_product(self):
        article_pk = self.article.pk
        self.sub_product.delete()
        self.assertFalse(Article.objects.filter(pk=article_pk).exists())

    def test_main_product_article(self):
        article = Article.objects.create(
            main_product=self.main_product,
            title="Product Article",
            description="Body.",
        )
        self.assertEqual(article.main_product, self.main_product)
        self.assertIsNone(article.sub_product_id)

    def test_cascade_delete_with_main_product(self):
        article = Article.objects.create(
            main_product=self.main_product,
            title="Product Article",
            description="Body.",
        )
        article_pk = article.pk
        self.main_product.delete()
        self.assertFalse(Article.objects.filter(pk=article_pk).exists())

    def test_requires_exactly_one_parent(self):
        article = Article(
            main_product=self.main_product,
            sub_product=self.sub_product,
            title="Invalid",
            description="Body.",
        )
        with self.assertRaises(ValidationError):
            article.full_clean()

    def test_requires_a_parent(self):
        article = Article(title="Orphan", description="Body.")
        with self.assertRaises(ValidationError):
            article.full_clean()


class SubProductVersionModelTest(TestCase):
    def setUp(self):
        self.main_product = MainProduct.objects.create(
            name="Main",
            short_description="Short",
            description="Desc",
        )
        self.sub_product = SubProduct.objects.create(
            main_product=self.main_product,
            name="Sub",
            short_description="Short",
            description="Desc",
        )

    def test_main_product_version(self):
        version = SubProductVersion.objects.create(
            main_product=self.main_product,
            version="1.0.0",
        )
        self.assertEqual(version.main_product, self.main_product)
        self.assertIsNone(version.sub_product_id)

    def test_requires_exactly_one_parent(self):
        version = SubProductVersion(
            main_product=self.main_product,
            sub_product=self.sub_product,
            version="1.0.0",
        )
        with self.assertRaises(ValidationError):
            version.full_clean()


class ArticleSectionModelTest(TestCase):
    def setUp(self):
        main = MainProduct.objects.create(name="M", short_description="s", description="d")
        sub = SubProduct.objects.create(main_product=main, name="S", short_description="s", description="d")
        self.article = Article.objects.create(sub_product=sub, title="Article", description="Desc")
        self.section = ArticleSection.objects.create(
            article=self.article,
            title="Link",
            value="https://example.com",
        )

    def test_str_representation(self):
        self.assertIn("Article", str(self.section))
        self.assertIn("Link", str(self.section))

    def test_cascade_delete_with_article(self):
        section_pk = self.section.pk
        self.article.delete()
        self.assertFalse(ArticleSection.objects.filter(pk=section_pk).exists())
