# 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 datetime import date

from trytond.pool import PoolMeta, Pool
from trytond.model import fields


class Invoice(metaclass=PoolMeta):
    __name__ = 'account.invoice'

    def auto_reconcile(self):
        reconcile_lines = []
        Reconciliation = Pool().get('account.move.reconciliation')
        account_reconcile_id = self.account.id
        balance = []
        for ml in self.payment_lines:
            if not ml.reconciliation and ml.account.id == account_reconcile_id:
                reconcile_lines.append(ml)
                balance.append(ml.debit - ml.credit)

        for ml in self.move.lines:
            if ml.account.id == account_reconcile_id:
                reconcile_lines.append(ml)
                balance.append(ml.debit - ml.credit)

        if sum(balance) != 0:
            return

        if reconcile_lines:
            Reconciliation.create([{
                'lines': [('add', reconcile_lines)],
                'date': date.today(),
            }])

    @classmethod
    def create_commissions(cls, invoices):
        """
        This set Off set move in commission model from channel commission
        in booking
        """
        commissions = super(Invoice, cls).create_commissions(invoices)
        for commission in commissions:
            if commission.origin.__name__ == 'account.invoice.line':
                inv_line = commission.origin
                if inv_line.offset_move_line:
                    commission.offset_move_line = inv_line.offset_move_line.id
                    commission.save()

    @classmethod
    def _get_folio_origin(cls, line):
        if line.origin and line.origin.__name__ == 'hotel.folio':
            return line.origin

    @classmethod
    def process_offset_move(cls, invoice):
        """
        This method create the offset move in the booking, for to cross
        in the future with account move related to supplier invoice of
        agent in module commissions
        """
        Folio = Pool().get('hotel.folio')

        folios_target = []
        lines_ids = []
        bk = None
        for line in invoice.lines:
            folio = cls._get_folio_origin(line)
            if not folio:
                return
            folios_target.append((folio, line))
            bk = folio.booking

        if bk.channel and bk.collection_mode == 'anticipated':
            lines_ids = Folio.set_offset_commission_move(folios_target, bk)
        return lines_ids

    def _add_commission_payment(self):
        pool = Pool()
        Commission = pool.get('commission')
        MoveLine = pool.get('account.move.line')
        lines_ids = [line.id for line in self.lines]
        commissions = Commission.search([
            ('invoice_line', 'in', lines_ids)
        ])
        payment_lines = []
        to_reconcile = []
        for comm in commissions:
            if not comm.invoice_line or not comm.offset_move_line:
                return
            payment_lines.append(comm.offset_move_line.id)
            invoice = comm.invoice_line.invoice
            self.write([invoice], {'payment_lines': [
                ('add', payment_lines)
            ]})
            to_reconcile.append(comm.offset_move_line)
            for line in self.move.lines:
                if line.account == self.account and not line.reconciliation:
                    to_reconcile.append(line)
            if invoice.amount_to_pay == 0 and to_reconcile:
                MoveLine.reconcile(to_reconcile)

    @classmethod
    def _post(cls, invoices):
        for invoice in invoices:
            lines_ids = None
            if invoice.type == 'in':
                super()._post([invoice])
                continue

            if invoice.type == 'out' and invoice.agent:
                lines_ids = cls.process_offset_move(invoice)

            super()._post([invoice])
            if lines_ids:
                cls.write([invoice], {'payment_lines': [('add', lines_ids)]})
            if invoice.type == 'in':
                invoice._add_commission_payment()

            cls.set_booking_payments(invoice)
            if not invoice.move.origin:
                return
            invoice.auto_reconcile()

    @classmethod
    def _add_payment(cls, inv, record, lines_ids):
        balance = 0
        for as_line in record.payments:
            if as_line.move and as_line.party == inv.party:
                balance += as_line.amount
                if as_line.amount > inv.total_amount or balance > inv.total_amount:
                    break
                for mline in as_line.move.lines:
                    if mline.account.id == inv.account.id and not mline.reconciliation:
                        lines_ids.append(mline.id)

    @classmethod
    def set_booking_payments(cls, invoice):
        lines_ids = []
        booking = None
        for line in invoice.lines:
            if line.origin and line.origin.__name__ == 'hotel.folio':
                folio = line.origin
                booking = folio.booking
                cls._add_payment(invoice, folio, lines_ids)
        if booking:
            cls._add_payment(invoice, booking, lines_ids)
        if lines_ids:
            cls.write([invoice], {'payment_lines': [('add', lines_ids)]})

    @classmethod
    def set_advances_from_origin(cls, invoice):
        vouchers = []
        for line in invoice.lines:
            if line.origin and line.origin.__name__ == 'hotel.booking':
                booking = line.origin
                if booking.vouchers:
                    for voucher in booking.vouchers:
                        if invoice.party.id == voucher.party.id:
                            vouchers.append(voucher)
                            # FIXME must pass lines of move
        if vouchers:
            invoice.create_move_advance(set(vouchers))


class InvoiceLine(metaclass=PoolMeta):
    __name__ = 'account.invoice.line'
    offset_move_line = fields.Many2One('account.move.line', 'Offset Move Line')

    @classmethod
    def _get_origin(cls):
        return super(InvoiceLine, cls)._get_origin() + [
            'hotel.booking', 'hotel.folio'
        ]

    def get_move_lines(self):
        Config = Pool().get('hotel.configuration')
        config = Config.get_configuration()
        lines = super().get_move_lines()
        if config.accounting_revenue == 'recognise_revenue':
            for line in lines:
                line.account = config.recognise_account.id
        return lines
