from decimal import Decimal

from django.contrib.auth import get_user_model
from django.db import IntegrityError
from django.test import TestCase
from rest_framework.test import APIClient

from shop_management.models.data.product import Category, Product, ProductPrice
from shop_management.models.data.shop import Shop
from shop_management.models.data.utils import Currency, Unit


class ProductMasterTests(TestCase):
    def setUp(self):
        self.user = get_user_model().objects.create_user(
            username="product-owner", password="test", is_staff=True
        )
        self.user.allowed_tabs = ["products"]
        self.user.save(update_fields=["allowed_tabs"])
        self.shop = Shop.objects.create(owner=self.user, name="Kabul")
        self.other_shop = Shop.objects.create(
            owner=get_user_model().objects.create_user(username="other-product-owner"),
            name="Takhar",
        )
        self.category = Category.objects.create(shop=self.shop, name="Medicine")
        self.unit = Unit.objects.create(shop=self.shop, title="Box")
        self.currency = Currency.objects.create(shop=self.shop, title="AFN")
        self.other_currency = Currency.objects.create(shop=self.other_shop, title="USD")
        self.product = Product.objects.create(
            shop=self.shop,
            category=self.category,
            name="Test Product",
            code="SKU-1",
            default_unit=self.unit,
            minimum_stock_level=Decimal("5.0000"),
        )

    def test_product_price_is_unique_and_nonnegative(self):
        ProductPrice.objects.create(
            product=self.product,
            currency=self.currency,
            price_type=ProductPrice.PriceType.RETAIL,
            amount=Decimal("120.0000"),
        )
        with self.assertRaises(IntegrityError):
            ProductPrice.objects.create(
                product=self.product,
                currency=self.currency,
                price_type=ProductPrice.PriceType.RETAIL,
                amount=Decimal("130.0000"),
            )

    def test_product_api_enables_batch_when_expiry_is_required(self):
        client = APIClient()
        client.force_authenticate(self.user)
        response = client.patch(
            f"/api/shop/products/{self.product.id}/",
            {"requires_expiry": True, "requires_batch": False},
            format="json",
        )
        self.assertEqual(response.status_code, 200)
        self.product.refresh_from_db()
        self.assertTrue(self.product.requires_expiry)
        self.assertTrue(self.product.requires_batch)

    def test_product_price_rejects_currency_from_another_branch(self):
        client = APIClient()
        client.force_authenticate(self.user)
        response = client.post(
            "/api/shop/product-prices/",
            {
                "product": self.product.id,
                "currency": self.other_currency.id,
                "price_type": "RETAIL",
                "amount": "10.0000",
            },
            format="json",
        )
        self.assertEqual(response.status_code, 400)
        self.assertIn("currency", response.data)

    def test_product_price_defaults_to_single_sale_price(self):
        client = APIClient()
        client.force_authenticate(self.user)

        response = client.post(
            "/api/shop/product-prices/",
            {
                "product": self.product.id,
                "currency": self.currency.id,
                "amount": "125.0000",
            },
            format="json",
        )

        self.assertEqual(response.status_code, 201, response.data)
        self.assertEqual(response.data["price_type"], ProductPrice.PriceType.RETAIL)

    def test_wholesale_product_price_is_rejected(self):
        client = APIClient()
        client.force_authenticate(self.user)

        response = client.post(
            "/api/shop/product-prices/",
            {
                "product": self.product.id,
                "currency": self.currency.id,
                "price_type": "WHOLESALE",
                "amount": "100.0000",
            },
            format="json",
        )

        self.assertEqual(response.status_code, 400)
        self.assertIn("price_type", response.data)
