# 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 decimal import Decimal

from trytond.model import ModelView, Workflow
from trytond.modules.account.exceptions import PeriodNotFoundError
from trytond.pool import Pool, PoolMeta
from trytond.transaction import Transaction
import logging

logger = logging.getLogger(__name__)


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

    def _get_account_stock_move_lines(self, type_, fee=None):
        '''
        Return move lines for stock move
        '''
        pool = Pool()
        Uom = pool.get('product.uom')
        AccountMoveLine = pool.get('account.move.line')
        Currency = pool.get('currency.currency')
        assert type_.startswith('in_') or type_.startswith('out_'), \
            'wrong type'

        move_line = AccountMoveLine()
        move_line.lot = self.lot
        move_line.fee = fee
        move_line.origin = self
        # cost_price_method = self.product.get_multivalue(
        #     'cost_price_method', **self._cost_price_pattern)
        # if ((
        #             type_.endswith('supplier')
        #             or type_ in {'in_production', 'in_warehouse'})
        #         and cost_price_method != 'fixed'):
        #     unit_price = self.unit_price_company
        # else:
        #     unit_price = self.cost_price
        # unit_price = self.unit_price
        # unit_price = Uom.compute_price(
        #     self.product.default_uom, unit_price, self.unit)
        # amount = self.company.currency.round(
        #         Decimal(str(self.quantity)) * unit_price)

        # if self.to_location.type == 'customer':
        amount = self.lot.get_cog()
        if fee:
            amount = fee.amount
        
        if fee and fee.currency != self.company.currency:
            with Transaction().set_context(date=self.effective_date):
                amount_converted = amount
                amount = Currency.compute(fee.currency,
                    amount, self.company.currency)
            move_line.second_currency = self.currency

        if self.currency != self.company.currency and not fee:
            with Transaction().set_context(date=self.effective_date):
                amount_converted = Currency.compute(self.company.currency,
                    amount, self.currency)
            move_line.second_currency = self.currency
        
        if amount < 0:
            if type_.startswith('in_'):
                move_line.debit = -amount
                move_line.credit = Decimal(0)
                move_line.account = fee.product.account_stock_in_used if fee else self.product.account_stock_in_used
                if hasattr(move_line, 'second_currency') and move_line.second_currency:
                    move_line.amount_second_currency = amount_converted
            else:
                move_line.debit = Decimal(0)
                move_line.credit = -amount
                move_line.account = fee.product.account_stock_out_used if fee else self.product.account_stock_out_used
                if hasattr(move_line, 'second_currency') and move_line.second_currency:
                    move_line.amount_second_currency = -amount_converted
        else:
            if type_.startswith('in_'):
                move_line.debit = Decimal(0)
                move_line.credit = amount
                move_line.account = fee.product.account_stock_in_used if fee else self.product.account_stock_in_used
                if hasattr(move_line, 'second_currency') and move_line.second_currency:
                    move_line.amount_second_currency = -amount_converted
            else:
                move_line.debit = amount
                move_line.credit = Decimal(0)
                move_line.account = fee.product.account_stock_out_used if fee else self.product.account_stock_out_used
                if hasattr(move_line, 'second_currency') and move_line.second_currency:
                    move_line.amount_second_currency = amount_converted

        logger.info("MOVELINES_DEB:%s",move_line.debit)
        logger.info("MOVELINES_CRE:%s",move_line.credit)
        return [move_line]

    def _get_account_stock_move_line(self, amount, fee=None):
        '''
        Return counterpart move line value for stock move
        '''
        pool = Pool()
        AccountMoveLine = pool.get('account.move.line')
        Currency = pool.get('currency.currency')
        move_line = AccountMoveLine(
            account=fee.product.account_stock_used if fee else self.product.account_stock_used,
            )
        move_line.lot = self.lot
        move_line.fee = fee
        move_line.origin = self
        if not amount:
            return

        amount_converted = amount
        if (self.currency != self.company.currency and not fee) or (fee and fee.currency != self.company.currency):
            with Transaction().set_context(date=self.effective_date):
                amount_converted = round(Currency.compute(self.company.currency,
                    amount, fee.currency if fee else self.currency),2)
            move_line.second_currency = self.currency
            move_line.amount_second_currency = -amount_converted
        
        if amount >= Decimal(0):
            move_line.debit = Decimal(0)
            move_line.credit = amount
        else:
            move_line.debit = - amount
            move_line.credit = Decimal(0)
            
        if self.to_location.type == 'customer':
            move_line.description = 'Delivery fee' if fee else 'Delivery'
        if self.from_location.type == 'supplier':
            move_line.description = 'Reception fee' if fee else 'Reception'

        logger.info("MOVELINE_DEB:%s",move_line.debit)
        logger.info("MOVELINE_CRE:%s",move_line.credit)
        return move_line

    def _get_account_stock_move_type(self):
        '''
        Get account move type
        '''
        type_ = (self.from_location.type, self.to_location.type)
        if type_ in [('supplier', 'storage'), ('supplier', 'drop')]:
            return 'in_supplier'
        elif type_ in [('storage', 'supplier'), ('drop', 'supplier')]:
            return 'out_supplier'
        elif type_ in [('storage', 'customer'), ('drop', 'customer')]:
            return 'out_customer'
        elif type_ in [('customer', 'storage'), ('customer', 'drop')]:
            return 'in_customer'
        elif type_ == ('storage', 'lost_found'):
            return 'out_lost_found'
        elif type_ == ('lost_found', 'storage'):
            return 'in_lost_found'
        elif type_ == ('supplier', 'customer'):
            return 'supplier_customer'
        elif type_ == ('customer', 'supplier'):
            return 'customer_supplier'
        elif type_ == ('storage', 'production'):
            return 'out_production'
        elif type_ == ('production', 'storage'):
            return 'in_production'

    def _get_account_stock_move(self):
        '''
        Return account move for stock move
        '''
        pool = Pool()
        AccountMove = pool.get('account.move')
        Date = pool.get('ir.date')
        Period = pool.get('account.period')
        AccountConfiguration = pool.get('account.configuration')

        if self.product.type != 'goods':
            return

        with Transaction().set_context(company=self.company.id):
            today = Date.today()
        for date in [self.effective_date, today]:
            try:
                period = Period.find(self.company, date=date, test_state=False)
            except PeriodNotFoundError:
                if date < today:
                    return
                continue
            break
        else:
            return
        logger.info("PERIOD_STOCK_METHOD:%s",period.fiscalyear.account_stock_method)
        if not period.fiscalyear.account_stock_method:
            return
        if period.state != 'open':
            date = today
            period = Period.find(self.company, date=date)

        type_ = self._get_account_stock_move_type()
        logger.info("MOVE_TYPE:%s",type_)
        if not type_:
            return
        with Transaction().set_context(
                company=self.company.id, date=date):
            if type_ == 'supplier_customer':
                account_move_lines = self._get_account_stock_move_lines(
                    'in_supplier')
                account_move_lines.extend(self._get_account_stock_move_lines(
                        'out_customer'))
            elif type_ == 'customer_supplier':
                account_move_lines = self._get_account_stock_move_lines(
                    'in_customer')
                account_move_lines.extend(self._get_account_stock_move_lines(
                        'out_supplier'))
            else:
                account_move_lines = self._get_account_stock_move_lines(type_)

        amount = Decimal(0)
        for line in account_move_lines:
            amount += line.debit - line.credit
        # if not amount:
        #     return
        move_line = self._get_account_stock_move_line(amount)
        if move_line:
            account_move_lines.append(move_line)

        account_configuration = AccountConfiguration(1)
        journal = account_configuration.get_multivalue(
            'stock_journal', company=self.company.id)
        logger.info("GET_ACCOUNT_:%s",account_move_lines)
        description = None
        if self.to_location.type == 'customer':
            description = 'Delivery'
        if self.from_location.type == 'supplier':
            description = 'Reception'
        return AccountMove(
            journal=journal,
            period=period,
            date=date,
            origin=self,
            description=description,
            lines=account_move_lines,
            )

    def _get_account_stock_move_fee(self, fee):
        '''
        Return account move for fee linked to lot of the stock move
        '''
        pool = Pool()
        AccountMove = pool.get('account.move')
        Date = pool.get('ir.date')
        Period = pool.get('account.period')
        AccountConfiguration = pool.get('account.configuration')

        if fee.product.type != 'service':
            return

        with Transaction().set_context(company=self.company.id):
            today = Date.today()
        for date in [self.effective_date, today]:
            try:
                period = Period.find(self.company, date=date, test_state=False)
            except PeriodNotFoundError:
                if date < today:
                    return
                continue
            break
        else:
            return
        if not period.fiscalyear.account_stock_method:
            return
        if period.state != 'open':
            date = today
            period = Period.find(self.company, date=date)

        type_ = self._get_account_stock_move_type()
        if not type_:
            return
        with Transaction().set_context(
                company=self.company.id, date=date):
            if type_ == 'supplier_customer':
                account_move_lines = self._get_account_stock_move_lines(
                    'in_supplier',fee)
                account_move_lines.extend(self._get_account_stock_move_lines(
                        'out_customer',fee))
            elif type_ == 'customer_supplier':
                account_move_lines = self._get_account_stock_move_lines(
                    'in_customer',fee)
                account_move_lines.extend(self._get_account_stock_move_lines(
                        'out_supplier',fee))
            else:
                account_move_lines = self._get_account_stock_move_lines(type_,fee)

        amount = Decimal(0)
        for line in account_move_lines:
            amount += line.debit - line.credit
        # if not amount:
        #     return
        move_line = self._get_account_stock_move_line(amount,fee)
        if move_line:
            account_move_lines.append(move_line)

        account_configuration = AccountConfiguration(1)
        journal = account_configuration.get_multivalue(
            'stock_journal', company=self.company.id)
        logger.info("GET_ACCOUNT_FEE:%s",account_move_lines)
        description = None
        if self.to_location.type == 'customer':
            description = 'Delivery fee'
        if self.from_location.type == 'supplier':
            description = 'Reception fee'
        return AccountMove(
            journal=journal,
            period=period,
            date=date,
            origin=self,
            description=description,
            lines=account_move_lines,
            )
    
    @classmethod
    @ModelView.button
    @Workflow.transition('done')
    def do(cls, moves):
        pool = Pool()
        AccountMove = pool.get('account.move')
        FeeLots = pool.get('fee.lots')
        logger.info("CONTINENTAL_DO_BEFORE:%s",moves)
        super(Move, cls).do(moves)
        logger.info("CONTINENTAL_DO_AFTER:%s",moves)
        account_moves = []
        for move in moves:
            account_move = move._get_account_stock_move()
            if account_move:
                account_moves.append(account_move)
            if move.lot:
                fees = FeeLots.search(['lot','=',move.lot.id])
                for fl in fees:
                    if fl.fee.type == 'ordered' and fl.fee.product.template.landed_cost:
                        account_move = move._get_account_stock_move_fee(fl.fee)
                        if account_move:
                            account_moves.append(account_move)

        AccountMove.save(account_moves)
        #AccountMove.post(account_moves)
