# Copyright (C) 2011 Julius Network Solutions SARL <contact@julius.fr>
# Copyright 2018 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)

from odoo import _, api, fields, models
from odoo.addons import decimal_precision as dp
from odoo.exceptions import ValidationError
from odoo.tools import float_compare


class StockMoveLocationWizardLine(models.TransientModel):
    _name = "wiz.stock.move.location.line"
    _description = 'Wizard move location line'

    move_location_wizard_id = fields.Many2many(
        string="Move location Wizard",
        comodel_name="wiz.stock.move.location",
        column1='move_location_line_wiz_id',
        column2='move_location_wiz_id',
        readonly=True,
    )
    product_id = fields.Many2one(
        string="Product",
        comodel_name="product.product",
        required=True,
    )
    origin_location_id = fields.Many2one(
        string='Origin Location',
        comodel_name='stock.location',
    )
    destination_location_id = fields.Many2one(
        string='Destination Location',
        comodel_name='stock.location',
    )
    product_uom_id = fields.Many2one(
        string='Product Unit of Measure',
        comodel_name='uom.uom',
    )
    lot_id = fields.Many2one(
        string='Lot/Serial Number',
        comodel_name='stock.production.lot',
        domain="[('product_id','=',product_id)]"
    )
    move_quantity = fields.Float(
        string="Quantity to move",
        digits=dp.get_precision('Product Unit of Measure'),
    )
    max_quantity = fields.Float(
        string="Maximum available quantity",
        digits=dp.get_precision('Product Unit of Measure'),
    )
    custom = fields.Boolean(
        string="Custom line",
        default=True,
    )

    @staticmethod
    def _compare(qty1, qty2, precision_rounding):
        return float_compare(
            qty1, qty2,
            precision_rounding=precision_rounding)

    @api.constrains("max_quantity", "move_quantity")
    def _constraint_max_move_quantity(self):
        for record in self:
            rounding = record.product_uom_id.rounding
            move_qty_gt_max_qty = self._compare(
                record.move_quantity, record.max_quantity, rounding) == 1
            move_qty_lt_0 = self._compare(
                record.move_quantity, 0.0, rounding) == -1
            if (move_qty_gt_max_qty or move_qty_lt_0):
                raise ValidationError(_(
                    "Move quantity can not exceed max quantity or be negative"
                ))

    def get_max_quantity(self):
        self.product_uom_id = self.product_id.uom_id
        search_args = [
            ('location_id', '=', self.origin_location_id.id),
            ('product_id', '=', self.product_id.id),
        ]
        if self.lot_id:
            search_args.append(('lot_id', '=', self.lot_id.id))
        else:
            search_args.append(('lot_id', '=', False))
        res = self.env['stock.quant'].read_group(search_args, ['quantity'], [])
        max_quantity = res[0]['quantity']
        return max_quantity

    def create_move_lines(self, picking, move):
        for line in self:
            values = line._get_move_line_values(picking, move)
            if not self.env.context.get("planned") and \
                    values.get("qty_done") <= 0:
                continue
            self.env["stock.move.line"].create(
                values
            )
        return True

    @api.multi
    def _get_move_line_values(self, picking, move):
        self.ensure_one()
        location_dest_id = (
            self.move_location_wizard_id.apply_putaway_strategy and
            self.destination_location_id.get_putaway_strategy(
                self.product_id).id or self.destination_location_id.id)
        qty_todo, qty_done = self._get_available_quantity()
        return {
            "product_id": self.product_id.id,
            "lot_id": self.lot_id.id,
            "location_id": self.origin_location_id.id,
            "location_dest_id": location_dest_id,
            "product_uom_qty": qty_todo,
            "qty_done": qty_done,
            "product_uom_id": self.product_uom_id.id,
            "picking_id": picking.id,
            "move_id": move.id,
        }

    def _get_available_quantity(self):
        """We check here if the actual amount changed in the stock.

        We don't care about the reservations but we do care about not moving
        more than exists."""
        self.ensure_one()
        if not self.product_id:
            return 0
        if self.env.context.get("planned"):
            # for planned transfer we don't care about the amounts at all
            return self.move_quantity, 0
        search_args = [
            ('location_id', '=', self.origin_location_id.id),
            ('product_id', '=', self.product_id.id),
        ]
        if self.lot_id:
            search_args.append(('lot_id', '=', self.lot_id.id))
        else:
            search_args.append(('lot_id', '=', False))
        res = self.env['stock.quant'].read_group(search_args, ['quantity'], [])
        available_qty = res[0]['quantity']
        if not available_qty:
            # if it is immediate transfer and product doesn't exist in that
            # location -> make the transfer of 0.
            return 0
        rounding = self.product_uom_id.rounding
        available_qty_lt_move_qty = self._compare(
            available_qty, self.move_quantity, rounding) == -1
        if available_qty_lt_move_qty:
            return available_qty
        return 0, self.move_quantity
