# Copyright 2013-2014 Camptocamp SA - Guewen Baconnier
# © 2016-20 ForgeFlow S.L. (https://www.forgeflow.com)
# © 2016 Serpent Consulting Services Pvt. Ltd.
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from odoo import fields, models
from odoo.tools.float_utils import float_compare


class SaleOrderLine(models.Model):
    _inherit = "sale.order.line"

    procurement_group_id = fields.Many2one(
        "procurement.group", "Procurement group", copy=False
    )

    def _get_procurement_group(self):
        super()._get_procurement_group()
        return self.procurement_group_id or False

    def _get_procurement_group_key(self):
        """Return a key with priority to be used to regroup lines in multiple
        procurement groups

        """
        return 8, self.order_id.id

    def _action_launch_stock_rule(self, previous_product_uom_qty=False):
        """
        Launch procurement group run method.
        """
        if self._context.get("skip_procurement"):
            return True
        precision = self.env["decimal.precision"].precision_get(
            "Product Unit of Measure"
        )
        procurements = []
        groups = {}
        if not previous_product_uom_qty:
            previous_product_uom_qty = {}
        for line in self:
            line = line.with_company(line.company_id)
            if (
                line.state != "sale"
                or line.order_id.locked
                or line.product_id.type != "consu"
            ):
                continue
            qty = line._get_qty_procurement(previous_product_uom_qty) or 0.0
            if (
                float_compare(qty, line.product_uom_qty, precision_digits=precision)
                == 0
            ):
                continue

            group_id = line._get_procurement_group()

            # Group the sales order lines with same procurement group
            # according to the group key
            for order_line in line.order_id.order_line:
                g_id = order_line.procurement_group_id or False
                if g_id:
                    groups[order_line._get_procurement_group_key()] = g_id
            if not group_id:
                group_id = groups.get(line._get_procurement_group_key())

            if not group_id:
                vals = line._prepare_procurement_group_vals()
                group_id = self.env["procurement.group"].create(vals)
            else:
                # In case the procurement group is already created and the
                # order was cancelled, we need to update certain values
                # of the group.
                updated_vals = {}
                if group_id.partner_id != line.order_id.partner_shipping_id:
                    updated_vals.update(
                        {"partner_id": line.order_id.partner_shipping_id.id}
                    )
                if group_id.move_type != line.order_id.picking_policy:
                    updated_vals.update({"move_type": line.order_id.picking_policy})
                if updated_vals:
                    group_id.write(updated_vals)
            line.procurement_group_id = group_id

            values = line._prepare_procurement_values(group_id=group_id)
            product_qty = line.product_uom_qty - qty

            line_uom = line.product_uom
            quant_uom = line.product_id.uom_id
            origin = (
                f"{line.order_id.name} - {line.order_id.client_order_ref}"
                if line.order_id.client_order_ref
                else line.order_id.name
            )
            product_qty, procurement_uom = line_uom._adjust_uom_quantities(
                product_qty, quant_uom
            )
            procurements += line._create_procurements(
                product_qty, procurement_uom, origin, values
            )
            # We store the procured quantity in the UoM of the line to avoid
            # duplicated procurements, specially for dropshipping and kits.
            previous_product_uom_qty[line.id] = line.product_uom_qty
        if procurements:
            self.env["procurement.group"].run(procurements)
        # This next block is currently needed only because the scheduler trigger is done
        # by picking confirmation rather than stock.move confirmation
        orders = self.mapped("order_id")
        for order in orders:
            pickings_to_confirm = order.picking_ids.filtered(
                lambda p: p.state not in ["cancel", "done"]
            )
            if pickings_to_confirm:
                # Trigger the Scheduler for Pickings
                pickings_to_confirm.action_confirm()
        return super(
            SaleOrderLine, self.with_context(sale_group_by_line=True)
        )._action_launch_stock_rule(previous_product_uom_qty=previous_product_uom_qty)
