# This file is part of Tryton.  The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.

import datetime as dt

from sql.aggregate import Sum

from trytond.i18n import gettext
from trytond.model import fields
from trytond.modules.account_invoice.exceptions import (
    InvoiceLineValidationError)
from trytond.pool import Pool, PoolMeta
from trytond.transaction import Transaction


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

    project_invoice_works = fields.One2Many(
        'project.work', 'invoice_line',
        "Project Invoice Works", readonly=True)
    project_invoice_progresses = fields.One2Many(
        'project.work.invoiced_progress', 'invoice_line',
        "Project Invoice Progresses", readonly=True)
    project_invoice_timesheet_duration = fields.Function(
        fields.TimeDelta("Project Invoice Timesheet Duration"),
        'get_project_invoice_timesheet_duration')

    @classmethod
    def check_validate_project_invoice_quantity(cls, lines, field_names):
        pool = Pool()
        Lang = pool.get('ir.lang')
        if field_names and not (field_names & {
                    'quantity', 'project_invoice_works'}):
            return
        for line in lines:
            project_invoice_quantity = line.project_invoice_quantity
            if project_invoice_quantity is None:
                continue
            if line.unit:
                project_invoice_quantity = line.unit.round(
                    project_invoice_quantity)
            if line.quantity != project_invoice_quantity:
                lang = Lang.get()
                if line.unit:
                    quantity = lang.format_number_symbol(
                        project_invoice_quantity, line.unit)
                else:
                    quantity = lang.format_number(project_invoice_quantity)
                raise InvoiceLineValidationError(gettext(
                        'project_invoice.msg_project_invoice_line_quantity',
                        invoice_line=line.rec_name,
                        quantity=quantity,
                        ))

    @property
    def project_invoice_quantity(self):
        quantity = None
        for work in self.project_invoice_works:
            if quantity is None:
                quantity = 0
            if work.price_list_hour:
                quantity += work.effort_hours
            else:
                quantity += 1
        for progress in self.project_invoice_progresses:
            if quantity is None:
                quantity = 0
            work = progress.work
            if work.price_list_hour:
                quantity += progress.progress * work.effort_hours
            else:
                quantity += progress.progress
        if self.project_invoice_timesheet_duration is not None:
            if quantity is None:
                quantity = 0
            quantity += (
                self.project_invoice_timesheet_duration.total_seconds()
                / 60 / 60)
        return quantity

    @classmethod
    def get_project_invoice_timesheet_duration(cls, lines, name):
        pool = Pool()
        TimesheetLine = pool.get('timesheet.line')
        cursor = Transaction().connection.cursor()
        ts_line = TimesheetLine.__table__()

        durations = dict.fromkeys(map(int, lines))
        query = ts_line.select(
            ts_line.invoice_line, Sum(ts_line.duration),
            where=fields.SQL_OPERATORS['in'](
                ts_line.invoice_line, map(int, lines)),
            group_by=ts_line.invoice_line)
        cursor.execute(*query)
        for line_id, duration in cursor:
            # SQLite uses float for SUM
            if (duration is not None
                    and not isinstance(duration, dt.timedelta)):
                duration = dt.timedelta(seconds=duration)
            durations[line_id] = duration
        return durations

    @classmethod
    def validate_fields(cls, lines, field_names):
        super().validate_fields(lines, field_names)
        cls.check_validate_project_invoice_quantity(lines, field_names)

    @classmethod
    def copy(cls, lines, default=None):
        default = default.copy() if default is not None else {}
        default.setdefault('project_invoice_works')
        default.setdefault('project_invoice_progresses')
        return super().copy(lines, default=default)
