# Copyright (C) 2020: 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 TestSyncPurchasePriceAction(TransactionCase):
    """Cover action_sync_purchase_price_from_supplierinfo on product.template.

    The action is used to bulk-correct last_purchase_price_received for products
    whose cost was written without applying supplier discounts.
    """

    @classmethod
    def setUpClass(cls):
        super().setUpClass()

        cls.has_discounts = hasattr(cls.env["product.supplierinfo"], "discount1")

        cls.tax = cls.env["account.tax"].create(
            {
                "name": "Test Tax 21% (Action)",
                "amount": 21.0,
                "amount_type": "percent",
                "type_tax_use": "sale",
            }
        )

        cls.pricelist = cls.env["product.pricelist"].create(
            {
                "name": "Test Pricelist (Action)",
                "currency_id": cls.env.company.currency_id.id,
            }
        )
        cls.env["product.pricelist.item"].create(
            {
                "pricelist_id": cls.pricelist.id,
                "compute_price": "formula",
                "base": "last_purchase_price",
                "price_markup": 50.0,
                "applied_on": "3_global",
            }
        )
        cls.env["ir.config_parameter"].sudo().set_param(
            "product_sale_price_from_pricelist.product_pricelist_automatic",
            str(cls.pricelist.id),
        )

        cls.supplier = cls.env["res.partner"].create(
            {"name": "Test Supplier (Action)", "supplier_rank": 1}
        )
        cls.uom_unit = cls.env.ref("uom.product_uom_unit")

    def setUp(self):
        super().setUp()
        if not self.has_discounts:
            self.skipTest("purchase_triple_discount module not installed")

    def _make_product(self, name, compute_type, cost=0.0):
        product = self.env["product.product"].create(
            {
                "name": name,
                "uom_id": self.uom_unit.id,
                "uom_po_id": self.uom_unit.id,
                "list_price": 10.0,
                "standard_price": cost,
                "taxes_id": [(6, 0, [self.tax.id])],
                "last_purchase_price_received": cost,
                "last_purchase_price_compute_type": compute_type,
            }
        )
        return product

    def _add_supplierinfo(
        self, product, price, discount1=0.0, discount2=0.0, discount3=0.0
    ):
        return (
            self.env["product.supplierinfo"]
            .with_context(skip_last_purchase_price_sync=True)
            .create(
                {
                    "partner_id": self.supplier.id,
                    "product_tmpl_id": product.product_tmpl_id.id,
                    "price": price,
                    "discount1": discount1,
                    "discount2": discount2,
                    "discount3": discount3,
                    "sequence": 1,
                }
            )
        )

    def _run_action(self, template):
        return template.action_sync_purchase_price_from_supplierinfo()

    def test_action_corrects_gross_price_no_discounts(self):
        """without_discounts: action keeps the gross price as-is."""
        product = self._make_product("P-NoDsc", "without_discounts", cost=999.0)
        self._add_supplierinfo(product, price=20.0)
        self._run_action(product.product_tmpl_id)
        self.assertAlmostEqual(product.last_purchase_price_received, 20.0, places=2)

    def test_action_corrects_with_first_discount(self):
        """with_discount: action applies discount1 only."""
        product = self._make_product("P-D1", "with_discount", cost=999.0)
        self._add_supplierinfo(product, price=10.0, discount1=20.0, discount2=10.0)
        self._run_action(product.product_tmpl_id)
        # 10 * 0.80 = 8.0
        self.assertAlmostEqual(product.last_purchase_price_received, 8.0, places=2)

    def test_action_corrects_with_two_discounts(self):
        """with_two_discounts: action applies discount1 and discount2."""
        product = self._make_product("P-D2", "with_two_discounts", cost=999.0)
        self._add_supplierinfo(
            product, price=10.0, discount1=20.0, discount2=10.0, discount3=5.0
        )
        self._run_action(product.product_tmpl_id)
        # 10 * 0.80 * 0.90 = 7.2
        self.assertAlmostEqual(product.last_purchase_price_received, 7.2, places=2)

    def test_action_corrects_with_three_discounts(self):
        """with_three_discounts: action applies all three discounts."""
        product = self._make_product("P-D3", "with_three_discounts", cost=999.0)
        self._add_supplierinfo(
            product, price=10.0, discount1=20.0, discount2=10.0, discount3=5.0
        )
        self._run_action(product.product_tmpl_id)
        # 10 * 0.80 * 0.90 * 0.95 = 6.84
        self.assertAlmostEqual(product.last_purchase_price_received, 6.84, places=2)

    def test_action_skips_manual_update(self):
        """manual_update: action never touches the cost."""
        product = self._make_product("P-Manual", "manual_update", cost=42.0)
        self._add_supplierinfo(product, price=10.0, discount1=50.0)
        self._run_action(product.product_tmpl_id)
        self.assertAlmostEqual(product.last_purchase_price_received, 42.0, places=2)

    def test_action_skips_product_without_seller(self):
        """Products with no supplierinfo are left untouched."""
        product = self._make_product("P-NoSeller", "with_three_discounts", cost=99.0)
        result = self._run_action(product.product_tmpl_id)
        self.assertAlmostEqual(product.last_purchase_price_received, 99.0, places=2)
        self.assertIn("warning", result["params"]["type"])

    def test_action_also_recomputes_theoretical_price(self):
        """After correcting the cost the theoretical sale price is refreshed."""
        product = self._make_product(
            "P-Theoretical", "with_three_discounts", cost=999.0
        )
        self._add_supplierinfo(product, price=1.53, discount1=15.0)
        self._run_action(product.product_tmpl_id)
        # net = 1.53 * 0.85 = 1.30, theoretical = 1.30 * 1.5 = 1.95
        self.assertAlmostEqual(product.last_purchase_price_received, 1.30, places=2)
        self.assertAlmostEqual(product.list_price_theoritical, 1.95, places=2)

    def test_action_returns_success_notification(self):
        """Return value is a display_notification client action with type success."""
        product = self._make_product("P-Notif", "with_three_discounts", cost=999.0)
        self._add_supplierinfo(product, price=10.0, discount1=20.0)
        result = self._run_action(product.product_tmpl_id)
        self.assertEqual(result["type"], "ir.actions.client")
        self.assertEqual(result["tag"], "display_notification")
        self.assertEqual(result["params"]["type"], "success")

    def test_action_idempotent(self):
        """Running the action twice leaves the price unchanged on the second run."""
        product = self._make_product("P-Idem", "with_three_discounts", cost=999.0)
        self._add_supplierinfo(product, price=10.0, discount1=20.0)
        self._run_action(product.product_tmpl_id)
        price_after_first = product.last_purchase_price_received
        result = self._run_action(product.product_tmpl_id)
        self.assertAlmostEqual(
            product.last_purchase_price_received, price_after_first, places=2
        )
        # No products were changed on the second run → warning (nothing updated)
        self.assertEqual(result["params"]["type"], "warning")

    def test_action_bulk_multiple_products(self):
        """Action works correctly when called on multiple templates at once."""
        p1 = self._make_product("P-Bulk1", "with_discount", cost=999.0)
        p2 = self._make_product("P-Bulk2", "with_two_discounts", cost=999.0)
        self._add_supplierinfo(p1, price=10.0, discount1=10.0)
        self._add_supplierinfo(p2, price=10.0, discount1=10.0, discount2=10.0)

        templates = p1.product_tmpl_id | p2.product_tmpl_id
        result = self._run_action(templates)

        # p1: 10 * 0.90 = 9.0
        self.assertAlmostEqual(p1.last_purchase_price_received, 9.0, places=2)
        # p2: 10 * 0.90 * 0.90 = 8.1
        self.assertAlmostEqual(p2.last_purchase_price_received, 8.1, places=2)
        self.assertEqual(result["params"]["type"], "success")
