from datetime import timedelta

from odoo import _, fields, models
from odoo.exceptions import UserError
from odoo.osv.expression import OR


class StockPicking(models.Model):
    _inherit = "stock.picking"

    subcontracted_unbuild_ids = fields.One2many(
        "mrp.unbuild", "picking_id", readonly=True, string="Subcontracted unbuilds"
    )

    def _prepare_subcontract_unbuild_vals(self, subcontract_move, bom):
        subcontract_move.ensure_one()
        product = subcontract_move.product_id
        mos = subcontract_move.mapped(
            "origin_returned_move_id.move_orig_ids.production_id"
        )
        if len(mos) > 1:
            raise UserError(
                _(
                    "It's not possible to create the subcontracting unbuild order\n"
                    "The subcontract move %(smn)s is linked with more than "
                    "one manufacturing order: %(jmm)s"
                )
                % {"smn": subcontract_move.name, "jmm": ",".join(mos.mapped("name"))}
            )
        vals = {
            "company_id": subcontract_move.company_id.id,
            "product_id": product.id,
            "product_uom_id": subcontract_move.product_uom.id,
            "bom_id": bom.id,
            "location_id": subcontract_move.picking_id.partner_id.with_company(
                subcontract_move.company_id
            ).property_stock_subcontractor.id,
            "location_dest_id": subcontract_move.picking_id.partner_id.with_company(
                subcontract_move.company_id
            ).property_stock_subcontractor.id,
            "product_qty": subcontract_move.product_uom_qty,
            "picking_id": self.id,
            "is_subcontracted": True,
            "mo_id": mos.id,
            "lot_id": subcontract_move.move_orig_ids.lot_ids.id,
        }
        return vals

    def _subcontracted_produce_unbuild(self, subcontract_details):
        self.ensure_one()
        for move, bom in subcontract_details:
            unbuild = (
                self.env["mrp.unbuild"]
                .with_company(move.company_id)
                .create(self._prepare_subcontract_unbuild_vals(move, bom))
            )
            self.subcontracted_unbuild_ids |= unbuild

    def _action_done(self):
        res = super(StockPicking, self)._action_done()
        for picking in self:
            unbuilds_to_done = picking.subcontracted_unbuild_ids.filtered(
                lambda x: x.state == "draft"
            )
            if not unbuilds_to_done:
                continue
            unbuild_ids_backorder = []
            if not self.env.context.get("cancel_backorder"):
                unbuild_ids_backorder = unbuilds_to_done.filtered(
                    lambda u: u.state == "draft"
                ).ids
            for unbuild in unbuilds_to_done:
                unbuild.with_context(
                    subcontract_move_id=True, mo_ids_to_backorder=unbuild_ids_backorder
                ).action_validate()
            moves = picking.move_ids.filtered(lambda move: move.is_subcontract)
            finished_move = unbuilds_to_done.produce_line_ids.filtered(
                lambda m: m.product_id.id in moves.mapped("product_id").ids
            )
            for move in moves:
                finished_move.write({"move_dest_ids": [(4, move.id, False)]})
            # For concistency, set the date on production move before the date
            # on picking. (Traceability report + Product Moves menu item)
            minimum_date = min(picking.move_line_ids.mapped("date"))
            unbuild_moves = (
                unbuilds_to_done.produce_line_ids | unbuilds_to_done.consume_line_ids
            )
            unbuild_moves.write({"date": minimum_date - timedelta(seconds=1)})
            unbuild_moves.move_line_ids.write(
                {"date": minimum_date - timedelta(seconds=1)}
            )
        return res

    def action_view_stock_valuation_layers(self):
        action = super(StockPicking, self).action_view_stock_valuation_layers()
        subcontracted_unbuilds = self.subcontracted_unbuild_ids
        if not subcontracted_unbuilds:
            return action
        domain = action["domain"]
        domain_subcontracting = [
            (
                "id",
                "in",
                (
                    subcontracted_unbuilds.produce_line_ids
                    | subcontracted_unbuilds.consume_line_ids
                ).stock_valuation_layer_ids.ids,
            )
        ]
        domain = OR([domain, domain_subcontracting])
        return dict(action, domain=domain)
