# Part of Odoo. See LICENSE file for full copyright and licensing details.

from collections import defaultdict

from odoo import _, api, fields, models
from odoo.exceptions import UserError


# Invoice template that needs to be passed to Sinvoice and will determine the format of the resulting
# invoice pdf on their system
class SInvoiceTemplate(models.Model):
    _name = 'l10n_vn_edi_viettel.sinvoice.template'
    _description = 'SInvoice template'

    name = fields.Char(
        string='Template Code',
        required=True,
    )
    template_invoice_type = fields.Selection(
        selection=[
            # Circular 32 being deprecated, only display types according to the Circular 78
            ('1', '1 - Value-added invoice'),
            ('2', '2 - Sales invoice'),
            ('3', '3 - Public assets sales'),
            ('4', '4 - National reserve sales'),
            ('5', '5 - Invoice for national reserve sales'),
            ('6', '6 - Warehouse release note'),
        ],
        required=True,
    )
    invoice_symbols_ids = fields.One2many(
        comodel_name='l10n_vn_edi_viettel.sinvoice.symbol',
        inverse_name='invoice_template_id',
    )

    _sql_constraints = [
        ('name_uniq', 'unique (name)', 'The template code must be unique!')
    ]

    @api.constrains('name', 'template_invoice_type')
    def _constrains_changes(self):
        """
        Multiple API endpoints will use these data, we should thus not allow changing them if they have been used
        for any invoices sent to sinvoice.
        """
        # The conditions are the same. If any symbols of the template are being used, we shouldn't allow editing it.
        self.invoice_symbols_ids._constrains_changes()


# Invoice symbol that needs to be passed to Sinvoice and will determine the prefix of the
# invoice number on their system
class SInvoiceSymbol(models.Model):
    _name = 'l10n_vn_edi_viettel.sinvoice.symbol'
    _description = 'SInvoice symbol'
    """
    The invoice symbols are made of multiple parts.
    The symbols characters have meanings that will influence the resulting invoices:

    The first character is either C (invoice with code from tax department) or K (without)
    It is then followed by two number which represent the current year (24 in 2024)
    Next, a single character representing additional invoice information:

        T: E-invoices registered with tax authorities by enterprises, organizations or household businesses;
        D: E-invoices used for sale of public property or national reserve goods or special e-invoices that do not have some mandatory contents of the “T” invoices;
        L: E-invoices issued separately by tax authorities;
        M: E-invoices generated by cash registers;
        N: Electronic delivery and internal consignment notes;
        B: Electronic delivery notes for goods sent to sales agents;
        G: VAT invoices in the form of electronic stamps, tickets or cards;
        H: Sales invoices in the form of electronic stamps, tickets or cards.

    Finally, it ends with two characters that shall be decided by the seller for their management requirements.
    """

    name = fields.Char(
        string='Symbol',
        required=True,
    )
    invoice_template_id = fields.Many2one(
        comodel_name='l10n_vn_edi_viettel.sinvoice.template',
        required=True,
    )

    _sql_constraints = [
        ('name_template_uniq', 'unique (name, invoice_template_id)', 'The combination symbol/template must be unique!')
    ]

    @api.constrains('name', 'invoice_template_id')
    def _constrains_changes(self):
        """
        Multiple API endpoints will use these data, we should thus not allow changing them if they have been used
        for any invoices sent to sinvoice.
        """
        invoice_counts = self.env['account.move']._read_group(
            domain=[
                ('l10n_vn_edi_invoice_symbol', 'in', self.ids),
                ('l10n_vn_edi_invoice_state', 'not in', ('ready_to_send', False)),  # Only matches sent invoices.
            ],
            groupby=['l10n_vn_edi_invoice_symbol'],
            aggregates=['__count'],
        )
        invoices_per_symbol = defaultdict(int)
        for symbol, count in invoice_counts:
            invoices_per_symbol[symbol.id] = count

        for record in self:
            if invoices_per_symbol[record.id] > 0:
                raise UserError(_('You cannot change the symbol value or template of the symbol %s because it has '
                                  'already been used to send invoices.', record.name))

    @api.depends('name', 'invoice_template_id')
    def _compute_display_name(self):
        """ As we allow multiple of the same symbol name, we need to also display the template to differentiate. """
        for symbol in self:
            symbol.display_name = f'{symbol.name} ({symbol.invoice_template_id.name})'
