# Copyright 2020 Camptocamp (https://www.camptocamp.com)
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).

from .common import TestDdmrpCommon


class TestDdmrpDistributedSourceLocation(TestDdmrpCommon):
    @classmethod
    def setUpClass(cls):
        super().setUpClass()
        # we store goods in "Replenish" and make pull rules to
        # go through "Replenish Step" when we replenish Stock
        cls.replenish_location = cls.env["stock.location"].create(
            {
                "name": "Replenish",
                "location_id": cls.warehouse.view_location_id.id,
                "usage": "internal",
                "company_id": cls.main_company.id,
            }
        )
        replenish_step_location = cls.env["stock.location"].create(
            {
                "name": "Replenish Step",
                "location_id": cls.warehouse.view_location_id.id,
                "usage": "internal",
                "company_id": cls.main_company.id,
            }
        )

        replenish_route = cls.env["stock.route"].create(
            {"name": "Replenish", "sequence": 1}
        )
        cls.env["stock.rule"].create(
            {
                "name": "Replenish",
                "route_id": replenish_route.id,
                "location_src_id": cls.replenish_location.id,
                "location_dest_id": replenish_step_location.id,
                "action": "pull",
                "picking_type_id": cls.warehouse.int_type_id.id,
                "procure_method": "make_to_stock",
                "warehouse_id": cls.warehouse.id,
                "company_id": cls.main_company.id,
            }
        )
        cls.env["stock.rule"].create(
            {
                "name": "Replenish Step",
                "route_id": replenish_route.id,
                "location_src_id": replenish_step_location.id,
                "location_dest_id": cls.warehouse.lot_stock_id.id,
                "action": "pull",
                "picking_type_id": cls.warehouse.int_type_id.id,
                "procure_method": "make_to_order",
                "warehouse_id": cls.warehouse.id,
                "company_id": cls.main_company.id,
            }
        )

        # our product uses the replenishment route
        cls.product_c_green.route_ids = replenish_route

        cls.buffer_dist = cls.bufferModel.create(
            {
                "buffer_profile_id": cls.buffer_profile_distr.id,
                "product_id": cls.product_c_green.id,
                "location_id": cls.stock_location.id,
                "warehouse_id": cls.warehouse.id,
                "qty_multiple": 1.0,
                "adu_calculation_method": cls.adu_fixed.id,
                "adu_fixed": 5.0,
            }
        )

        cls.buffer_profile_distr.replenish_distributed_limit_to_free_qty = True

    def test_distributed_source_location_id(self):
        # as we have a route to replenish from this location, we expect the
        # buffer to have this location set as source
        self.assertEqual(
            self.buffer_dist.distributed_source_location_id, self.replenish_location
        )
        self.assertEqual(self.buffer_dist.distributed_source_location_qty, 0)

    def test_distributed_source_location_qty(self):
        self.env["stock.quant"]._update_available_quantity(
            self.product_c_green, self.replenish_location, 4000
        )

        # Invalidate the computed quantities
        self.env["product.product"].invalidate_model()
        self.assertEqual(self.buffer_dist.distributed_source_location_qty, 4000)

        self.env["stock.quant"]._update_reserved_quantity(
            self.product_c_green, self.replenish_location, 500
        )

        # Invalidate the computed quantities to recompute free_qty
        self.env["product.product"].invalidate_model()
        self.assertEqual(self.buffer_dist.distributed_source_location_qty, 3500)

        self.assertEqual(
            self.env["stock.buffer"].search(
                [("distributed_source_location_qty", "=", 3500)]
            ),
            self.buffer_dist,
        )

    def _set_qty_and_create_replenish_wizard(
        self, qty_in_replenish=4000, recommended_qty=10000
    ):
        self.env["stock.quant"]._update_available_quantity(
            self.product_c_green, self.replenish_location, 4000
        )
        # lie about the recommended qty (we only want to test if the limit is
        # applied)
        self.buffer_dist.procure_recommended_qty = 10000

        return self.create_orderpoint_procurement(
            self.buffer_dist, make_procurement=False
        )

    def test_distributed_source_limit_replenish(self):
        wizard = self._set_qty_and_create_replenish_wizard()
        self.assertRecordValues(
            wizard.item_ids,
            [
                {
                    "recommended_qty": 10000,
                    # limited to the free qty
                    "qty": 4000,
                }
            ],
        )

    def test_distributed_source_limit_replenish_with_batch_limit_max(self):
        self.buffer_dist.procure_max_qty = 1200
        wizard = self._set_qty_and_create_replenish_wizard()
        self.assertRecordValues(
            wizard.item_ids,
            # we expect lines to be per batch of 1200 but maxed to the free qty
            [
                {"recommended_qty": 10000, "qty": 1200},
                {"recommended_qty": 10000, "qty": 1200},
                {"recommended_qty": 10000, "qty": 1200},
                {"recommended_qty": 10000, "qty": 400},
            ],
        )

    def test_distributed_source_limit_replenish_with_batch_limit_min(self):
        self.buffer_dist.procure_min_qty = 5000
        wizard = self._set_qty_and_create_replenish_wizard()
        self.assertRecordValues(
            wizard.item_ids,
            # the 4000 in stock is below the min of 5000, nothing moved
            [{"recommended_qty": 10000, "qty": 0}],
        )

    def test_distributed_source_limit_replenish_with_batch_limit_min_and_max(self):
        self.buffer_dist.procure_min_qty = 1000
        self.buffer_dist.procure_max_qty = 1200
        wizard = self._set_qty_and_create_replenish_wizard()
        self.assertRecordValues(
            wizard.item_ids,
            # the last batch would be 400 which is below the min limit,
            # ignore the remaining
            [
                {"recommended_qty": 10000, "qty": 1200},
                {"recommended_qty": 10000, "qty": 1200},
                {"recommended_qty": 10000, "qty": 1200},
            ],
        )

    def test_distributed_source_limit_disabled(self):
        self.buffer_profile_distr.replenish_distributed_limit_to_free_qty = False
        wizard = self._set_qty_and_create_replenish_wizard()
        self.assertRecordValues(
            wizard.item_ids,
            # normal behavior, apply the recommended qty when the option is set
            # to False on the profile
            [{"recommended_qty": 10000, "qty": 10000}],
        )
