# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.

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

from collections import defaultdict


class AccountJournal(models.Model):
    _inherit = 'account.journal'

    edi_format_ids = fields.Many2many(comodel_name='account.edi.format',
                                      string='Electronic invoicing',
                                      help='Send XML/EDI invoices',
                                      domain="[('id', 'in', compatible_edi_ids)]",
                                      compute='_compute_edi_format_ids',
                                      readonly=False, store=True)

    compatible_edi_ids = fields.Many2many(comodel_name='account.edi.format',
                                          compute='_compute_compatible_edi_ids',
                                          help='EDI format that support moves in this journal')

    def write(self, vals):
        # OVERRIDE
        # Don't allow the user to deactivate an edi format having at least one document to be processed.
        if vals.get('edi_format_ids'):
            old_edi_format_ids = self.edi_format_ids
            res = super().write(vals)
            diff_edi_format_ids = old_edi_format_ids - self.edi_format_ids
            documents = self.env['account.edi.document'].search([
                ('move_id.journal_id', 'in', self.ids),
                ('edi_format_id', 'in', diff_edi_format_ids.ids),
                ('state', 'in', ('to_cancel', 'to_send')),
            ])
            # If the formats we are unchecking do not need a webservice, we don't need them to be correctly sent
            if documents.filtered(lambda d: d.edi_format_id._needs_web_services()):
                raise UserError(_('Cannot deactivate (%s) on this journal because not all documents are synchronized', ', '.join(documents.edi_format_id.mapped('display_name'))))
            # remove these documents which: do not need a web service & are linked to the edi formats we are unchecking
            if documents:
                documents.unlink()
            return res
        else:
            return super().write(vals)

    @api.depends('type', 'company_id', 'company_id.account_fiscal_country_id')
    def _compute_compatible_edi_ids(self):
        edi_formats = self.env['account.edi.format'].search([])

        for journal in self:
            compatible_edis = edi_formats.filtered(lambda e: e._is_compatible_with_journal(journal))
            journal.compatible_edi_ids = compatible_edis

    @api.depends('type', 'company_id', 'company_id.account_fiscal_country_id')
    def _compute_edi_format_ids(self):
        edi_formats = self.env['account.edi.format'].search([])
        journal_ids = self.ids

        if journal_ids:
            self.env.cr.execute('''
                SELECT
                    move.journal_id,
                    ARRAY_AGG(doc.edi_format_id) AS edi_format_ids
                FROM account_edi_document doc
                JOIN account_move move ON move.id = doc.move_id
                WHERE doc.state IN ('to_cancel', 'to_send')
                AND move.journal_id IN %s
                GROUP BY move.journal_id
            ''', [tuple(journal_ids)])
            protected_edi_formats_per_journal = {r[0]: set(r[1]) for r in self.env.cr.fetchall()}
        else:
            protected_edi_formats_per_journal = defaultdict(set)

        for journal in self:
            enabled_edi_formats = edi_formats.filtered(lambda e: e._is_compatible_with_journal(journal) and
                                                                 (e._is_enabled_by_default_on_journal(journal)
                                                                  or (e in journal.edi_format_ids)))

            # The existing edi formats that are already in use so we can't remove it.
            protected_edi_format_ids = protected_edi_formats_per_journal.get(journal.id, set())
            protected_edi_formats = journal.edi_format_ids.filtered(lambda e: e.id in protected_edi_format_ids)

            journal.edi_format_ids = enabled_edi_formats + protected_edi_formats
