# Copyright (C) 2025: Criptomart (https://criptomart.net)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

from odoo.tests import tagged
from odoo.tests.common import TransactionCase


@tagged("post_install", "-at_install")
class TestTripleDiscountMixin(TransactionCase):
    @classmethod
    def setUpClass(cls):
        super().setUpClass()

        # Create a partner
        cls.partner = cls.env["res.partner"].create(
            {
                "name": "Test Partner",
            }
        )

        # Create a product template first, then get the variant
        cls.product_template = cls.env["product.template"].create(
            {
                "name": "Test Product",
                "type": "consu",
                "list_price": 100.0,
                "standard_price": 50.0,
            }
        )
        # Get the auto-created product variant
        cls.product = cls.product_template.product_variant_ids[0]

        # Create a purchase order
        cls.purchase_order = cls.env["purchase.order"].create(
            {
                "partner_id": cls.partner.id,
            }
        )

        # Create a purchase order line
        cls.po_line = cls.env["purchase.order.line"].create(
            {
                "order_id": cls.purchase_order.id,
                "product_id": cls.product.id,
                "product_qty": 10,
                "price_unit": 100.0,
                "discount1": 10.0,
                "discount2": 5.0,
                "discount3": 2.0,
            }
        )

    def test_discount_field_is_readonly(self):
        """Test that the discount field is readonly"""
        field = self.po_line._fields["discount"]
        self.assertTrue(field.readonly, "Discount field should be readonly")

    def test_write_with_explicit_discounts(self):
        """Test writing with explicit discount1, discount2, discount3"""
        # Write with explicit discounts
        self.po_line.write(
            {
                "discount": 20.0,  # This should be ignored
                "discount1": 15.0,
                "discount2": 10.0,
                "discount3": 5.0,
            }
        )

        # Verify explicit discounts were applied
        self.assertEqual(self.po_line.discount1, 15.0)
        self.assertEqual(self.po_line.discount2, 10.0)
        self.assertEqual(self.po_line.discount3, 5.0)

        # The computed discount field should reflect the combined discounts
        # Formula: 100 - (100 * (1 - 0.15) * (1 - 0.10) * (1 - 0.05))
        expected_discount = 100 - (100 * 0.85 * 0.90 * 0.95)
        self.assertAlmostEqual(self.po_line.discount, expected_discount, places=2)

    def test_write_only_discount1(self):
        """Test writing only discount1 explicitly"""
        self.po_line.write(
            {
                "discount": 25.0,  # This should be ignored
                "discount1": 20.0,
            }
        )

        # Only discount1 should change
        self.assertEqual(self.po_line.discount1, 20.0)
        # Others should remain unchanged
        self.assertEqual(self.po_line.discount2, 5.0)
        self.assertEqual(self.po_line.discount3, 2.0)

    def test_write_only_discount2(self):
        """Test writing only discount2 explicitly"""
        self.po_line.write(
            {
                "discount": 30.0,  # This should be ignored
                "discount2": 12.0,
            }
        )

        # Only discount2 should change
        self.assertEqual(self.po_line.discount2, 12.0)
        # Others should remain unchanged from previous test
        self.assertEqual(self.po_line.discount1, 20.0)
        self.assertEqual(self.po_line.discount3, 2.0)

    def test_write_only_discount3(self):
        """Test writing only discount3 explicitly"""
        self.po_line.write(
            {
                "discount": 35.0,  # This should be ignored
                "discount3": 8.0,
            }
        )

        # Only discount3 should change
        self.assertEqual(self.po_line.discount3, 8.0)
        # Others should remain unchanged from previous tests
        self.assertEqual(self.po_line.discount1, 20.0)
        self.assertEqual(self.po_line.discount2, 12.0)

    def test_write_legacy_discount_only(self):
        """Test legacy behavior: writing only discount field"""
        # Reset to known state first
        self.po_line.write(
            {
                "discount1": 10.0,
                "discount2": 5.0,
                "discount3": 2.0,
            }
        )

        # Write only discount (legacy behavior)
        self.po_line.write(
            {
                "discount": 25.0,
            }
        )

        # Should map to discount1 and reset others
        self.assertEqual(self.po_line.discount1, 25.0)
        self.assertEqual(self.po_line.discount2, 0.0)
        self.assertEqual(self.po_line.discount3, 0.0)

    def test_write_multiple_times(self):
        """Test writing multiple times to ensure consistency"""
        # First write
        self.po_line.write(
            {
                "discount1": 10.0,
                "discount2": 10.0,
            }
        )

        self.assertEqual(self.po_line.discount1, 10.0)
        self.assertEqual(self.po_line.discount2, 10.0)

        # Second write
        self.po_line.write(
            {
                "discount": 5.0,
                "discount3": 5.0,
            }
        )

        # discount3 should change, others remain
        self.assertEqual(self.po_line.discount1, 10.0)
        self.assertEqual(self.po_line.discount2, 10.0)
        self.assertEqual(self.po_line.discount3, 5.0)

    def test_write_zero_discounts(self):
        """Test writing zero discounts"""
        self.po_line.write(
            {
                "discount1": 0.0,
                "discount2": 0.0,
                "discount3": 0.0,
            }
        )

        self.assertEqual(self.po_line.discount1, 0.0)
        self.assertEqual(self.po_line.discount2, 0.0)
        self.assertEqual(self.po_line.discount3, 0.0)
        self.assertEqual(self.po_line.discount, 0.0)

    def test_write_combined_scenario(self):
        """Test a realistic combined scenario"""
        # Initial state
        self.po_line.write(
            {
                "discount1": 15.0,
                "discount2": 5.0,
                "discount3": 0.0,
            }
        )

        # User tries to update discount field (should be ignored if explicit discounts present)
        self.po_line.write(
            {
                "discount": 50.0,
                "discount1": 20.0,
            }
        )

        # discount1 should be updated, others unchanged
        self.assertEqual(self.po_line.discount1, 20.0)
        self.assertEqual(self.po_line.discount2, 5.0)
        self.assertEqual(self.po_line.discount3, 0.0)

    def test_discount_calculation_accuracy(self):
        """Test that discount calculation is accurate"""
        self.po_line.write(
            {
                "discount1": 10.0,
                "discount2": 10.0,
                "discount3": 10.0,
            }
        )

        # Combined discount: 100 - (100 * 0.9 * 0.9 * 0.9) = 27.1
        expected = 100 - (100 * 0.9 * 0.9 * 0.9)
        self.assertAlmostEqual(self.po_line.discount, expected, places=2)

    def test_write_without_discount_field(self):
        """Test writing other fields without touching discount fields"""
        initial_discount1 = self.po_line.discount1

        # Write other fields
        self.po_line.write(
            {
                "product_qty": 20,
                "price_unit": 150.0,
            }
        )

        # Discounts should remain unchanged
        self.assertEqual(self.po_line.discount1, initial_discount1)
        # But other fields should be updated
        self.assertEqual(self.po_line.product_qty, 20)
        self.assertEqual(self.po_line.price_unit, 150.0)
