from unittest import mock

from django.test import TestCase

from oscar.core.loading import get_class, get_model

import ocyan.core.fender
from ocyan.plugin.oscar.fender import InvalidTaxRateException

Product = get_model("catalogue", "Product")
Selector = get_class("partner.strategy", "Selector")
tax_rate_as_fraction = get_class("taxes.taxrate", "tax_rate_as_fraction")

EXCL_TAX_SETTINGS = {"oscar": {"use_price_incl_tax": False}}


class TaxPriceSelectorTest(TestCase):
    fixtures = ["partner/auth.json", "partner/catalogue.json"]

    def test_tax_rate_as_fraction(self):
        with self.assertRaises(InvalidTaxRateException):
            tax_rate_as_fraction(None)

    def test_tax_price_selector_incl_tax(self):
        strategy = Selector().strategy()
        p = Product.objects.get()
        price_info = strategy.fetch_for_product(p)

        self.assertTrue(
            price_info.price.is_tax_known,
            "A valid product should have a known tax value",
        )
        self.assertTrue(price_info.price.exists, "A valid product should have a price")
        self.assertEqual(
            price_info.price.tax_code,
            p.vat_rate,
            "The tax code of the price should mirror the vat_rate on the product",
        )

        Product.objects.update(vat_rate=None)
        p.refresh_from_db()

        price_info = strategy.fetch_for_product(p)
        self.assertFalse(
            price_info.price.exists,
            "A product without a vat_rate should now have a price",
        )
        self.assertFalse(
            price_info.price.is_tax_known,
            "A product without vat_rate should not have a know tax value",
        )

    @mock.patch.object(ocyan.core.fender.config, "settings", EXCL_TAX_SETTINGS)
    def test_tax_price_selector_excl_tax(self):
        strategy = Selector().strategy()
        p = Product.objects.get()
        price_info = strategy.fetch_for_product(p)

        self.assertTrue(
            price_info.price.is_tax_known,
            "A valid product should have a known tax value",
        )
        self.assertTrue(price_info.price.exists, "A valid product should have a price")
        self.assertEqual(
            price_info.price.tax_code,
            p.vat_rate,
            "The tax code of the price should mirror the vat_rate on the product",
        )

        Product.objects.update(vat_rate=None)
        p.refresh_from_db()

        price_info = strategy.fetch_for_product(p)
        self.assertFalse(
            price_info.price.exists,
            "A product without a vat_rate should now have a price",
        )
        self.assertFalse(
            price_info.price.is_tax_known,
            "A product without vat_rate should not have a know tax value",
        )
