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

"""
Test suite for price calculations WITH taxes included.

This test verifies that the _compute_price_with_taxes method correctly
calculates prices including taxes for display in the online shop.
"""

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


@tagged("post_install", "-at_install")
class TestPriceWithTaxesIncluded(TransactionCase):
    """Test that prices displayed include taxes."""

    def setUp(self):
        super().setUp()

        # Create test company
        self.company = self.env["res.company"].create(
            {
                "name": "Test Company Tax Included",
            }
        )

        # Get or create default tax group
        tax_group = self.env["account.tax.group"].search(
            [("company_id", "=", self.company.id)], limit=1
        )
        if not tax_group:
            tax_group = self.env["account.tax.group"].create(
                {
                    "name": "IVA",
                    "company_id": self.company.id,
                }
            )

        # Get default country (Spain)
        country_es = self.env.ref("base.es")

        # Create tax (21% IVA) - price_include=False (default)
        self.tax_21 = self.env["account.tax"].create(
            {
                "name": "IVA 21%",
                "amount": 21.0,
                "amount_type": "percent",
                "type_tax_use": "sale",
                "price_include": False,  # Explicit: tax NOT included in price
                "company_id": self.company.id,
                "country_id": country_es.id,
                "tax_group_id": tax_group.id,
            }
        )

        # Create tax (10% IVA reducido)
        self.tax_10 = self.env["account.tax"].create(
            {
                "name": "IVA 10%",
                "amount": 10.0,
                "amount_type": "percent",
                "type_tax_use": "sale",
                "price_include": False,
                "company_id": self.company.id,
                "country_id": country_es.id,
                "tax_group_id": tax_group.id,
            }
        )

        # Create tax with price_include=True for comparison
        self.tax_21_included = self.env["account.tax"].create(
            {
                "name": "IVA 21% Incluido",
                "amount": 21.0,
                "amount_type": "percent",
                "type_tax_use": "sale",
                "price_include": True,  # Tax IS included in price
                "company_id": self.company.id,
                "country_id": country_es.id,
                "tax_group_id": tax_group.id,
            }
        )

        # Create product category
        self.category = self.env["product.category"].create(
            {
                "name": "Test Category Tax Included",
            }
        )

        # Create test products with different tax configurations
        self.product_21 = self.env["product.product"].create(
            {
                "name": "Product With 21% Tax",
                "list_price": 100.0,
                "categ_id": self.category.id,
                "taxes_id": [(6, 0, [self.tax_21.id])],
                "company_id": self.company.id,
            }
        )

        self.product_10 = self.env["product.product"].create(
            {
                "name": "Product With 10% Tax",
                "list_price": 100.0,
                "categ_id": self.category.id,
                "taxes_id": [(6, 0, [self.tax_10.id])],
                "company_id": self.company.id,
            }
        )

        self.product_no_tax = self.env["product.product"].create(
            {
                "name": "Product Without Tax",
                "list_price": 100.0,
                "categ_id": self.category.id,
                "taxes_id": False,
                "company_id": self.company.id,
            }
        )

        self.product_tax_included = self.env["product.product"].create(
            {
                "name": "Product With Tax Included",
                "list_price": 121.0,  # 100 + 21% = 121
                "categ_id": self.category.id,
                "taxes_id": [(6, 0, [self.tax_21_included.id])],
                "company_id": self.company.id,
            }
        )

        # Create pricelist
        self.pricelist = self.env["product.pricelist"].create(
            {
                "name": "Test Pricelist",
                "company_id": self.company.id,
            }
        )

    def test_price_with_21_percent_tax(self):
        """Test that 21% tax is correctly added to base price."""
        # Base price: 100.0
        # Expected with 21% tax: 121.0

        taxes = self.product_21.taxes_id.filtered(
            lambda t: t.company_id == self.company
        )

        base_price = 100.0
        tax_result = taxes.compute_all(
            base_price,
            currency=self.env.company.currency_id,
            quantity=1.0,
            product=self.product_21,
        )

        price_with_tax = tax_result["total_included"]

        self.assertAlmostEqual(
            price_with_tax, 121.0, places=2, msg="100 + 21% should equal 121.0"
        )

    def test_price_with_10_percent_tax(self):
        """Test that 10% tax is correctly added to base price."""
        # Base price: 100.0
        # Expected with 10% tax: 110.0

        taxes = self.product_10.taxes_id.filtered(
            lambda t: t.company_id == self.company
        )

        base_price = 100.0
        tax_result = taxes.compute_all(
            base_price,
            currency=self.env.company.currency_id,
            quantity=1.0,
            product=self.product_10,
        )

        price_with_tax = tax_result["total_included"]

        self.assertAlmostEqual(
            price_with_tax, 110.0, places=2, msg="100 + 10% should equal 110.0"
        )

    def test_price_without_tax(self):
        """Test that product without tax returns base price unchanged."""
        # Base price: 100.0
        # Expected with no tax: 100.0

        taxes = self.product_no_tax.taxes_id.filtered(
            lambda t: t.company_id == self.company
        )

        # No taxes, so tax_result would be empty
        self.assertFalse(taxes, "Product should have no taxes")

        # Without taxes, price should remain base price
        base_price = 100.0
        expected_price = 100.0

        self.assertEqual(
            base_price,
            expected_price,
            msg="Product without tax should have unchanged price",
        )

    def test_oca_get_price_returns_base_without_tax(self):
        """Test that OCA _get_price returns base price WITHOUT taxes by default."""
        # This verifies our understanding of OCA behavior

        price_info = self.product_21._get_price(
            qty=1.0,
            pricelist=self.pricelist,
            fposition=False,
        )

        # OCA should return base price (100.0) WITHOUT tax
        self.assertAlmostEqual(
            price_info["value"],
            100.0,
            places=2,
            msg="OCA _get_price should return base price without tax",
        )

        # tax_included should be False for price_include=False taxes
        self.assertFalse(
            price_info.get("tax_included", False),
            msg="tax_included should be False when price_include=False",
        )

    def test_oca_get_price_with_included_tax(self):
        """Test OCA behavior with price_include=True tax."""

        price_info = self.product_tax_included._get_price(
            qty=1.0,
            pricelist=self.pricelist,
            fposition=False,
        )

        # With price_include=True, the price should already include tax
        # list_price is 121.0 (100 + 21%)
        self.assertAlmostEqual(
            price_info["value"],
            121.0,
            places=2,
            msg="Price with included tax should be 121.0",
        )

        # tax_included should be True
        self.assertTrue(
            price_info.get("tax_included", False),
            msg="tax_included should be True when price_include=True",
        )

    def test_compute_all_with_multiple_taxes(self):
        """Test tax calculation with multiple taxes."""
        # Create product with both 21% and 10% taxes
        product_multi = self.env["product.product"].create(
            {
                "name": "Product With Multiple Taxes",
                "list_price": 100.0,
                "categ_id": self.category.id,
                "taxes_id": [(6, 0, [self.tax_21.id, self.tax_10.id])],
                "company_id": self.company.id,
            }
        )

        taxes = product_multi.taxes_id.filtered(lambda t: t.company_id == self.company)

        base_price = 100.0
        tax_result = taxes.compute_all(
            base_price,
            currency=self.env.company.currency_id,
            quantity=1.0,
            product=product_multi,
        )

        price_with_taxes = tax_result["total_included"]

        # 100 + 21% + 10% = 100 + 21 + 10 = 131.0
        self.assertAlmostEqual(
            price_with_taxes, 131.0, places=2, msg="100 + 21% + 10% should equal 131.0"
        )

    def test_compute_all_with_fiscal_position(self):
        """Test tax calculation with fiscal position mapping."""
        # Create fiscal position that maps 21% to 10%
        fiscal_position = self.env["account.fiscal.position"].create(
            {
                "name": "Test Fiscal Position",
                "company_id": self.company.id,
            }
        )
        self.env["account.fiscal.position.tax"].create(
            {
                "position_id": fiscal_position.id,
                "tax_src_id": self.tax_21.id,
                "tax_dest_id": self.tax_10.id,
            }
        )

        # Get taxes and apply fiscal position
        taxes = self.product_21.taxes_id.filtered(
            lambda t: t.company_id == self.company
        )
        mapped_taxes = fiscal_position.map_tax(taxes)

        # Should be mapped to 10% tax
        self.assertEqual(len(mapped_taxes), 1)
        self.assertEqual(mapped_taxes[0].id, self.tax_10.id)

        base_price = 100.0
        tax_result = mapped_taxes.compute_all(
            base_price,
            currency=self.env.company.currency_id,
            quantity=1.0,
            product=self.product_21,
        )

        price_with_tax = tax_result["total_included"]

        # Should be 110.0 (10% instead of 21%)
        self.assertAlmostEqual(
            price_with_tax, 110.0, places=2, msg="Fiscal position should map to 10% tax"
        )

    def test_tax_amount_details(self):
        """Test that compute_all provides detailed tax breakdown."""
        taxes = self.product_21.taxes_id.filtered(
            lambda t: t.company_id == self.company
        )

        base_price = 100.0
        tax_result = taxes.compute_all(
            base_price,
            currency=self.env.company.currency_id,
            quantity=1.0,
            product=self.product_21,
        )

        # Verify structure of tax_result
        self.assertIn("total_included", tax_result)
        self.assertIn("total_excluded", tax_result)
        self.assertIn("taxes", tax_result)

        # total_excluded should be base price
        self.assertAlmostEqual(tax_result["total_excluded"], 100.0, places=2)

        # total_included should be base + tax
        self.assertAlmostEqual(tax_result["total_included"], 121.0, places=2)

        # taxes should contain tax details
        self.assertEqual(len(tax_result["taxes"]), 1)
        tax_detail = tax_result["taxes"][0]
        self.assertAlmostEqual(tax_detail["amount"], 21.0, places=2)

    def test_zero_price_with_tax(self):
        """Test tax calculation on free product."""
        free_product = self.env["product.product"].create(
            {
                "name": "Free Product With Tax",
                "list_price": 0.0,
                "categ_id": self.category.id,
                "taxes_id": [(6, 0, [self.tax_21.id])],
                "company_id": self.company.id,
            }
        )

        taxes = free_product.taxes_id.filtered(lambda t: t.company_id == self.company)

        base_price = 0.0
        tax_result = taxes.compute_all(
            base_price,
            currency=self.env.company.currency_id,
            quantity=1.0,
            product=free_product,
        )

        price_with_tax = tax_result["total_included"]

        # 0 + 21% = 0
        self.assertAlmostEqual(
            price_with_tax,
            0.0,
            places=2,
            msg="Free product with tax should still be free",
        )

    def test_high_precision_price_with_tax(self):
        """Test tax calculation with high precision prices."""
        precise_product = self.env["product.product"].create(
            {
                "name": "Precise Price Product",
                "list_price": 99.99,
                "categ_id": self.category.id,
                "taxes_id": [(6, 0, [self.tax_21.id])],
                "company_id": self.company.id,
            }
        )

        taxes = precise_product.taxes_id.filtered(
            lambda t: t.company_id == self.company
        )

        base_price = 99.99
        tax_result = taxes.compute_all(
            base_price,
            currency=self.env.company.currency_id,
            quantity=1.0,
            product=precise_product,
        )

        price_with_tax = tax_result["total_included"]

        # 99.99 + 21% = 120.9879 ≈ 120.99
        expected = 99.99 * 1.21
        self.assertAlmostEqual(
            price_with_tax,
            expected,
            places=2,
            msg=f"Expected {expected}, got {price_with_tax}",
        )
