# Copyright 2022 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)

from odoo import api, fields, models


class StockMove(models.Model):
    _inherit = "stock.move"

    customer_ref_sale_line_id = fields.Many2one(
        comodel_name="sale.order.line",
        compute="_compute_customer_ref_sale_line_id",
        string="Sale Line With Customer Ref.",
        store=True,
        index=True,
    )
    customer_ref = fields.Char(compute="_compute_customer_ref", store=True)

    @api.depends("sale_line_id.customer_ref", "move_dest_ids.sale_line_id")
    def _compute_customer_ref_sale_line_id(self):
        for move in self:
            sale_line = move._get_customer_ref_sale_line()
            move.customer_ref_sale_line_id = sale_line

    @api.depends("customer_ref_sale_line_id.customer_ref")
    def _compute_customer_ref(self):
        for move in self:
            move.customer_ref = move.customer_ref_sale_line_id.customer_ref

    def _get_customer_ref_sale_line(self):
        """Return the SO line with a customer ref. from the ship move."""
        self.ensure_one()
        if self.sale_line_id.customer_ref:
            return self.sale_line_id
        if not self.move_dest_ids:
            return self.sale_line_id.browse()
        # Search in the destination moves recursively until we find a SO line
        moves_dest = self.move_dest_ids
        move_seen_ids = set(moves_dest.ids)
        while moves_dest:
            for move_dest in moves_dest:
                # As soon as the SO line has a customer reference, we break.
                # That means for pick+pack moves we return the first SO line found.
                if move_dest.sale_line_id.customer_ref:
                    return move_dest.sale_line_id
            # Guard to avoid infinite loop. This should not happen.
            recursion_move_ids = move_seen_ids & set(moves_dest.move_dest_ids.ids)
            if recursion_move_ids:
                break
            moves_dest = moves_dest.move_dest_ids
            move_seen_ids |= set(moves_dest.ids)
        return self.sale_line_id.browse()

    @api.model
    def _prepare_merge_moves_distinct_fields(self):
        distinct_fields = super()._prepare_merge_moves_distinct_fields()
        # While ship moves can't be merged together as they are coming from
        # different SO lines ('sale_line_id' is part of the merge-key in
        # 'sale_stock'), we allow only the merge of chained moves like
        # pick+pack based on the customer reference.
        distinct_fields.append("customer_ref")
        return distinct_fields
