# This file is part of Tryton.  The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
from trytond.model import fields
from trytond.modules.currency.fields import Monetary
from trytond.modules.product import price_digits, round_price
from trytond.pool import Pool, PoolMeta
from trytond.pyson import Eval


class Move(metaclass=PoolMeta):
    __name__ = 'stock.move'

    secondary_quantity = fields.Function(fields.Float(
            "Secondary Quantity", digits='secondary_unit',
            states={
                'invisible': ~Eval('secondary_unit'),
                'readonly': Eval('state').in_(
                    ['cancelled', 'assigned', 'done']),
                }),
        'on_change_with_secondary_quantity', setter='set_secondary')
    secondary_unit = fields.Many2One(
        'product.uom', "Secondary Unit", ondelete='RESTRICT',
        domain=[
            ('category', '=', Eval('product_secondary_uom_category')),
            ],
        states={
            'invisible': ~Eval('product_secondary_uom_category'),
            'readonly': Eval('state').in_(['cancelled', 'assigned', 'done']),
            })
    secondary_unit_price = fields.Function(
        Monetary(
            "Secondary Unit Price", currency='currency', digits=price_digits,
            states={
                'invisible': (~Eval('unit_price_required')
                    | ~Eval('secondary_unit')),
                'readonly': Eval('state') != 'draft',
                }),
        'on_change_with_secondary_unit_price', setter='set_secondary')

    product_secondary_uom_category = fields.Function(
        fields.Many2One(
            'product.uom.category', "Product Secondary UoM Category",
            help="The category of secondary Unit of Measure for the product."),
        'get_product_secondary_uom_category')

    @fields.depends('quantity', 'unit', 'secondary_unit', 'origin')
    def on_change_with_secondary_quantity(self, name=None):
        pool = Pool()
        Uom = pool.get('product.uom')
        if (self.quantity and self.unit and self.secondary_unit
                and (self.secondary_uom_factor or self.secondary_uom_rate)):
            return Uom.compute_qty(
                self.unit, self.quantity,
                self.secondary_unit, round=True,
                factor=self.secondary_uom_factor, rate=self.secondary_uom_rate)
        else:
            return None

    @fields.depends('secondary_quantity', 'secondary_unit', 'unit', 'origin')
    def on_change_secondary_quantity(self):
        pool = Pool()
        Uom = pool.get('product.uom')
        if (self.secondary_quantity and self.secondary_unit and self.unit
                and (self.secondary_uom_factor or self.secondary_uom_rate)):
            self.quantity = Uom.compute_qty(
                self.secondary_unit, self.secondary_quantity,
                self.unit, round=True,
                factor=self.secondary_uom_rate, rate=self.secondary_uom_factor)

    @fields.depends('unit_price', 'unit', 'secondary_unit', 'origin')
    def on_change_with_secondary_unit_price(self, name=None):
        pool = Pool()
        Uom = pool.get('product.uom')
        if (self.unit_price and self.unit and self.secondary_unit
                and (self.secondary_uom_factor or self.secondary_uom_rate)):
            unit_price = Uom.compute_price(
                self.unit, self.unit_price, self.secondary_unit,
                factor=self.secondary_uom_factor, rate=self.secondary_uom_rate
                )
            return round_price(unit_price)
        else:
            return None

    @fields.depends('secondary_unit_price', 'secondary_unit', 'unit', 'origin')
    def on_change_secondary_unit_price(self, name=None):
        pool = Pool()
        Uom = pool.get('product.uom')
        if (self.secondary_unit_price and self.secondary_unit and self.unit
                and (self.secondary_uom_factor or self.secondary_uom_rate)):
            self.unit_price = Uom.compute_price(
                self.secondary_unit, self.secondary_unit_price, self.unit,
                factor=self.secondary_uom_rate, rate=self.secondary_uom_factor)
            self.unit_price = round_price(self.unit_price)

    @fields.depends(methods=[
            'on_change_secondary_quantity', 'on_change_secondary_unit_price'])
    def on_change_secondary_unit(self):
        self.on_change_secondary_quantity()
        self.on_change_secondary_unit_price()

    def get_product_secondary_uom_category(self, name):
        category = None
        if self.secondary_unit:
            # Stay valid even if origin has been deleted
            category = self.secondary_unit.category.id
        if isinstance(self.origin, self.__class__) and self.origin != self:
            if self.origin.product_secondary_uom_category:
                category = self.origin.product_secondary_uom_category.id
        return category

    @classmethod
    def set_secondary(cls, lines, name, value):
        pass

    @property
    def secondary_uom_factor(self):
        if isinstance(self.origin, self.__class__) and self.origin != self:
            return self.origin.secondary_uom_factor

    @property
    def secondary_uom_rate(self):
        if isinstance(self.origin, self.__class__) and self.origin != self:
            return self.origin.secondary_uom_rate


class ShipmentIn(metaclass=PoolMeta):
    __name__ = 'stock.shipment.in'

    def _get_inventory_move(self, incoming_move):
        move = super()._get_inventory_move(incoming_move)
        if move:
            move.secondary_unit = incoming_move.secondary_unit
        return move


class ShipmentOut(metaclass=PoolMeta):
    __name__ = 'stock.shipment.out'

    def _get_inventory_move(self, move):
        inventory_move = super()._get_inventory_move(move)
        if inventory_move:
            inventory_move.secondary_unit = move.secondary_unit
        return inventory_move

    def _sync_outgoing_move(self, template=None):
        move = super()._sync_outgoing_move(template)
        if template:
            move.secondary_unit = template.secondary_unit
        return move


class ShipmentOutReturn(metaclass=PoolMeta):
    __name__ = 'stock.shipment.out.return'

    def _get_inventory_move(self, incoming_move):
        move = super()._get_inventory_move(incoming_move)
        if move:
            move.secondary_unit = incoming_move.secondary_unit
        return move


class ShipmentInternal(metaclass=PoolMeta):
    __name__ = 'stock.shipment.internal'

    def _sync_incoming_move(self, template=None):
        move = super()._sync_incoming_move(template)
        if template:
            move.secondary_unit = template.secondary_unit
        return move
