# Copyright (C) 2017-20 ForgeFlow S.L.
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html)

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


class RmaAddStockMove(models.TransientModel):
    _name = "rma_add_stock_move"
    _description = "Wizard to add rma lines from pickings"

    @api.model
    def default_get(self, fields_list):
        res = super(RmaAddStockMove, self).default_get(fields_list)
        rma_obj = self.env["rma.order"]
        rma_id = self.env.context["active_ids"] or []
        active_model = self.env.context["active_model"]
        if not rma_id:
            return res
        assert active_model == "rma.order", "Bad context propagation"

        rma = rma_obj.browse(rma_id)
        res["rma_id"] = rma.id
        res["partner_id"] = rma.partner_id.id
        res["move_ids"] = False
        return res

    rma_id = fields.Many2one(
        comodel_name="rma.order", string="RMA Order", readonly=True, ondelete="cascade"
    )
    partner_id = fields.Many2one(
        comodel_name="res.partner", string="Partner", readonly=True
    )
    move_ids = fields.Many2many(
        comodel_name="stock.move",
        string="Stock Moves",
        domain="[('state', '=', 'done')]",
    )
    show_lot_filter = fields.Boolean(
        string="Show lot filter?",
        compute="_compute_lot_domain",
    )
    lot_domain_ids = fields.Many2many(
        comodel_name="stock.lot",
        string="Lots Domain",
        compute="_compute_lot_domain",
    )

    @api.depends(
        "move_ids.move_line_ids.lot_id",
    )
    def _compute_lot_domain(self):
        for rec in self:
            rec.lot_domain_ids = rec.mapped("move_ids.move_line_ids.lot_id").ids
            rec.show_lot_filter = bool(rec.lot_domain_ids)

    lot_ids = fields.Many2many(comodel_name="stock.lot", string="Lots/Serials selected")

    def select_all(self):
        self.ensure_one()
        self.write(
            {
                "lot_ids": [(6, 0, self.lot_domain_ids.ids)],
            }
        )
        return {
            "type": "ir.actions.act_window",
            "name": _("Add from Stock Move"),
            "view_mode": "form",
            "res_model": self._name,
            "res_id": self.id,
            "target": "new",
        }

    def _prepare_rma_line_from_stock_move(self, sm, lot=False):
        operation = self.rma_id.operation_default_id
        if not operation:
            if self.env.context.get("customer"):
                operation = (
                    sm.product_id.rma_customer_operation_id
                    or sm.product_id.categ_id.rma_customer_operation_id
                )
            else:
                operation = (
                    sm.product_id.rma_supplier_operation_id
                    or sm.product_id.categ_id.rma_supplier_operation_id
                )
        if not operation:
            operation = self.env["rma.operation"].search(
                [("type", "=", self.rma_id.type)], limit=1
            )
            if not operation:
                raise ValidationError(_("Please define an operation first"))

        if not operation.in_route_id or not operation.out_route_id:
            route = self.env["stock.route"].search(
                [("rma_selectable", "=", True)], limit=1
            )
            if not route:
                raise ValidationError(_("Please define an RMA route"))
        in_warehouse = self.rma_id.in_warehouse_id or operation.in_warehouse_id
        in_route = self.rma_id.in_route_id or operation.in_route_id
        out_warehouse = self.rma_id.out_warehouse_id or operation.out_warehouse_id
        out_route = self.rma_id.out_route_id or operation.out_route_id
        if not in_warehouse or not out_warehouse:
            warehouse = self.env["stock.warehouse"].search(
                [
                    ("company_id", "=", self.rma_id.company_id.id),
                    ("lot_rma_id", "!=", False),
                ],
                limit=1,
            )
            if not warehouse:
                raise ValidationError(
                    _("Please define a warehouse with a default RMA location")
                )
            in_warehouse = in_warehouse or warehouse
            out_warehouse = out_warehouse or warehouse
        location = self.rma_id.location_id
        if not location:
            location = (
                operation.location_id
                or operation.in_warehouse_id.lot_rma_id
                or in_warehouse.lot_rma_id
                or out_warehouse.lot_rma_id
            )
        product_qty = sm.product_uom_qty
        if sm.product_id.tracking == "serial":
            product_qty = 1
        elif sm.product_id.tracking == "lot":
            product_qty = sum(
                sm.move_line_ids.filtered(lambda x: x.lot_id.id == lot.id).mapped(
                    "qty_done"
                )
            )
        data = {
            "partner_id": self.partner_id.id,
            "description": self.rma_id.description,
            "reference_move_id": sm.id,
            "product_id": sm.product_id.id,
            "lot_id": lot and lot.id or False,
            "origin": sm.picking_id.name or sm.name,
            "uom_id": sm.product_uom.id,
            "operation_id": operation.id,
            "product_qty": product_qty,
            "delivery_address_id": sm.picking_id.partner_id.id,
            "rma_id": self.rma_id.id,
            "receipt_policy": operation.receipt_policy,
            "delivery_policy": operation.delivery_policy,
            "in_warehouse_id": in_warehouse.id,
            "out_warehouse_id": out_warehouse.id,
            "in_route_id": in_route.id,
            "out_route_id": out_route.id,
            "location_id": location.id,
        }
        return data

    @api.model
    def _get_existing_stock_moves(self):
        existing_move_lines = []
        for rma_line in self.rma_id.rma_line_ids:
            existing_move_lines.append(rma_line.reference_move_id)
        return existing_move_lines

    def add_lines(self):
        rma_line_obj = self.env["rma.order.line"]
        existing_stock_moves = self._get_existing_stock_moves()
        for sm in self.move_ids:
            tracking_move = sm.product_id.tracking in ("serial", "lot")
            if sm not in existing_stock_moves or tracking_move:
                if sm.product_id.tracking == "none":
                    data = self._prepare_rma_line_from_stock_move(sm, lot=False)
                    rec = rma_line_obj.with_context(
                        default_rma_id=self.rma_id.id
                    ).create(data)
                    # Ensure that configuration on the operation is applied (like
                    #  policies).
                    # TODO MIG: in v16 the usage of such onchange can be removed in
                    #  favor of (pre)computed stored editable fields for all policies
                    #  and configuration in the RMA operation.
                    rec._onchange_operation_id()
                else:
                    for lot in sm.move_line_ids.mapped("lot_id").filtered(
                        lambda x: x.id in self.lot_ids.ids
                    ):
                        if lot.id in self.rma_id.rma_line_ids.mapped("lot_id").ids:
                            continue
                        data = self._prepare_rma_line_from_stock_move(sm, lot)
                        rec = rma_line_obj.with_context(
                            default_rma_id=self.rma_id.id
                        ).create(data)
                        # Ensure that configuration on the operation is applied (like
                        #  policies).
                        # TODO MIG: in v16 the usage of such onchange can be removed in
                        #  favor of (pre)computed stored editable fields for all policies
                        #  and configuration in the RMA operation.
                        rec._onchange_operation_id()
                        rec.price_unit = rec._get_price_unit()
        return {"type": "ir.actions.act_window_close"}
