# Copyright 2018-2019 ForgeFlow, S.L.
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl-3.0)

from odoo import _, api, fields, models
from odoo.exceptions import ValidationError
from odoo.tools import float_compare


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

    created_purchase_request_line_id = fields.Many2one(
        comodel_name="purchase.request.line",
        string="Created Purchase Request Line",
        ondelete="set null",
        readonly=True,
        copy=False,
        index=True,
    )

    purchase_request_allocation_ids = fields.One2many(
        comodel_name="purchase.request.allocation",
        inverse_name="stock_move_id",
        copy=False,
        string="Purchase Request Allocation",
    )

    purchase_request_ids = fields.One2many(
        comodel_name="purchase.request",
        string="Purchase Requests",
        compute="_compute_purchase_request_ids",
    )

    @api.model
    def _prepare_merge_moves_distinct_fields(self):
        distinct_fields = super(StockMove, self)._prepare_merge_moves_distinct_fields()
        distinct_fields += ["created_purchase_request_line_id"]
        return distinct_fields

    def _action_cancel_create_mail_activity(self):
        """Create an activity on the request for the cancelled procurement move"""
        for move in self:
            if move.created_purchase_request_line_id:
                try:
                    activity_type_id = self.env.ref("mail.mail_activity_data_todo").id
                except ValueError:
                    activity_type_id = False
                pr_line = move.created_purchase_request_line_id
                if pr_line.product_id.responsible_id:
                    activity_user = pr_line.product_id.responsible_id
                elif pr_line.request_id.assigned_to:
                    activity_user = pr_line.request_id.assigned_to
                elif move.picking_id.user_id:
                    activity_user = move.picking_id.user_id
                else:
                    activity_user = self.env.user
                self.env["mail.activity"].sudo().create(
                    {
                        "activity_type_id": activity_type_id,
                        "note": _(
                            "A sale/manufacturing order that generated this "
                            "purchase request has been cancelled/deleted. "
                            "Check if an action is needed."
                        ),
                        "user_id": activity_user.id,
                        "res_id": pr_line.request_id.id,
                        "res_model_id": self.env.ref(
                            "purchase_request.model_purchase_request"
                        ).id,
                    }
                )

    def _action_cancel(self):
        self._action_cancel_create_mail_activity()
        return super(StockMove, self)._action_cancel()

    @api.depends("purchase_request_allocation_ids")
    def _compute_purchase_request_ids(self):
        for rec in self:
            rec.purchase_request_ids = (
                rec.purchase_request_allocation_ids.purchase_request_line_id.request_id
            )

    def _merge_moves_fields(self):
        res = super(StockMove, self)._merge_moves_fields()
        res["purchase_request_allocation_ids"] = [
            (4, m.id) for m in self.mapped("purchase_request_allocation_ids")
        ]
        return res

    @api.constrains("company_id")
    def _check_company_purchase_request(self):
        if not self.ids:
            return
        self.env.cr.execute(
            """
            SELECT 1
            FROM purchase_request_allocation pra
            INNER JOIN stock_move sm
               ON sm.id=pra.stock_move_id
            WHERE pra.company_id != sm.company_id
                AND sm.id IN %s
            LIMIT 1
        """,
            (tuple(self.ids),),
        )
        if self.env.cr.fetchone():
            raise ValidationError(
                _(
                    "The company of the purchase request must match with "
                    "that of the location."
                )
            )

    def copy_data(self, default=None):
        """Propagate request allocation on copy.

        If this move is being split, or if this move is processed and there is
        a remaining allocation, move the appropriate quantity over to the new move.
        """
        if default is None:
            default = {}
        if not default.get("purchase_request_allocation_ids") and (
            default.get("product_uom_qty") or self.state in ("done", "cancel")
        ):
            default["purchase_request_allocation_ids"] = []
            new_move_qty = default.get("product_uom_qty") or self.product_uom_qty
            rounding = self.product_id.uom_id.rounding
            for alloc in self.purchase_request_allocation_ids.filtered(
                "open_product_qty"
            ):
                if (
                    float_compare(
                        new_move_qty,
                        0,
                        precision_rounding=self.product_id.uom_id.rounding,
                    )
                    <= 0
                    or float_compare(
                        alloc.open_product_qty, 0, precision_rounding=rounding
                    )
                    <= 0
                ):
                    break
                open_qty = min(new_move_qty, alloc.open_product_qty)
                new_move_qty -= open_qty
                default["purchase_request_allocation_ids"].append(
                    (
                        0,
                        0,
                        {
                            "purchase_request_line_id": alloc.purchase_request_line_id.id,
                            "requested_product_uom_qty": open_qty,
                        },
                    )
                )
                alloc.requested_product_uom_qty -= open_qty
        return super(StockMove, self).copy_data(default)
