import time
from datetime import timedelta

from odoo import api, fields, models
from odoo.addons.l10n_hu_edi.models.l10n_hu_edi_connection import L10nHuEdiConnection


class AccountMoveSend(models.TransientModel):
    _inherit = 'account.move.send'

    l10n_hu_edi_actionable_errors = fields.Json(
        compute='_compute_l10n_hu_edi_enable_nav_30'
    )
    l10n_hu_edi_enable_nav_30 = fields.Boolean(
        compute='_compute_l10n_hu_edi_enable_nav_30'
    )
    l10n_hu_edi_checkbox_nav_30 = fields.Boolean(
        string='NAV 3.0',
        compute='_compute_l10n_hu_edi_checkbox_nav_30',
        store=True,
        readonly=False,
    )

    def _get_wizard_values(self):
        # EXTENDS 'account'
        return {
            **super()._get_wizard_values(),
            'l10n_hu_edi_checkbox_nav_30': self.l10n_hu_edi_checkbox_nav_30,
        }

    # -------------------------------------------------------------------------
    # COMPUTE METHODS
    # -------------------------------------------------------------------------

    @api.depends('move_ids')
    def _compute_l10n_hu_edi_enable_nav_30(self):
        for wizard in self:
            enabled_moves = wizard.move_ids.filtered(lambda m: 'upload' in m._l10n_hu_edi_get_valid_actions())._origin
            if wizard.mode in ('invoice_single', 'invoice_multi') and enabled_moves:
                wizard.l10n_hu_edi_enable_nav_30 = True
                wizard.l10n_hu_edi_actionable_errors = enabled_moves._l10n_hu_edi_check_invoices()

            else:
                wizard.l10n_hu_edi_enable_nav_30 = False
                wizard.l10n_hu_edi_actionable_errors = False

    @api.depends('l10n_hu_edi_enable_nav_30', 'l10n_hu_edi_actionable_errors')
    def _compute_l10n_hu_edi_checkbox_nav_30(self):
        for wizard in self:
            wizard.l10n_hu_edi_checkbox_nav_30 = wizard.l10n_hu_edi_enable_nav_30

    # -------------------------------------------------------------------------
    # BUSINESS ACTIONS
    # -------------------------------------------------------------------------

    @api.model
    def _need_invoice_document(self, invoice):
        # EXTENDS 'account'
        # If the send & print triggers the NAV 3.0 flow, we want to re-generate the PDF.
        if invoice.country_code != 'HU':
            return super()._need_invoice_document(invoice)
        else:
            return invoice._l10n_hu_edi_get_valid_actions()

    @api.model
    def _call_web_service_before_invoice_pdf_render(self, invoices_data):
        # EXTENDS 'account'
        super()._call_web_service_before_invoice_pdf_render(invoices_data)

        invoices_hu = self.env['account.move'].browse([
            invoice.id
            for invoice, invoice_data in invoices_data.items()
            if invoice_data.get('l10n_hu_edi_checkbox_nav_30')
               and 'upload' in invoice._l10n_hu_edi_get_valid_actions()
        ])

        if not invoices_hu:
            return

        # Pre-emptively acquire write lock on all invoices to be processed
        # Otherwise, we will get a serialization error later
        # (bad, because Odoo will try to retry the entire request, leading to duplicate sending to NAV)
        invoices_hu._l10n_hu_edi_acquire_lock()

        # STEP 1: Generate and send the invoice XMLs.
        invoices_to_upload = invoices_hu.filtered(lambda m: 'upload' in m._l10n_hu_edi_get_valid_actions())

        # If we need to re-generate the PDF, break the link between the existing attachment and the 'invoice_pdf_report_file' field.
        # The existing PDF will remain linked to the invoice, but no longer as primary attachment.
        invoices_to_upload.invoice_pdf_report_id.write({'res_field': False})
        invoices_to_upload.invalidate_recordset(fnames=['invoice_pdf_report_id', 'invoice_pdf_report_file'])

        with L10nHuEdiConnection(self.env) as connection:
            invoices_to_upload._l10n_hu_edi_upload(connection)
            if self._can_commit():
                self.env.cr.commit()

            if any(m.l10n_hu_edi_state == 'sent' for m in invoices_hu):
                # If any invoices were just sent, wait so that NAV has enough time to process them
                time.sleep(2)

            # STEP 2: Query status
            invoices_hu.filtered(lambda m: 'query_status' in m._l10n_hu_edi_get_valid_actions())._l10n_hu_edi_query_status(connection)

        # STEP 3: Schedule update status of pending invoices in 10 minutes.
        if any(m.l10n_hu_edi_state not in [False, 'confirmed', 'confirmed_warning', 'rejected'] for m in invoices_hu):
            self.env.ref('l10n_hu_edi.ir_cron_update_status')._trigger(at=fields.Datetime.now() + timedelta(minutes=10))

        # STEP 4: Error / success handling.
        for invoice in invoices_hu:
            # Log outcome in chatter
            formatted_message = self._format_error_html(invoice.l10n_hu_edi_messages)
            invoice.with_context(no_new_invoice=True).message_post(body=formatted_message)

            # Update invoice_data with errors
            blocking_level = invoice.l10n_hu_edi_messages.get('blocking_level')
            if blocking_level == 'error':
                invoices_data[invoice]['error'] = invoice.l10n_hu_edi_messages

        if self._can_commit():
            self.env.cr.commit()

    @api.model
    def _l10n_hu_edi_cron_update_status(self):
        final_states = [False, 'confirmed', 'confirmed_warning', 'rejected', 'cancel_pending', 'cancelled']
        invoices_pending = self.env['account.move'].search([('l10n_hu_edi_state', 'not in', final_states)])
        invoices_pending.l10n_hu_edi_button_update_status(from_cron=True)

        if any(m.state not in final_states for m in invoices_pending):
            # Trigger cron again in 10 minutes.
            self.env.ref('l10n_hu_edi.ir_cron_update_status')._trigger(at=fields.Datetime.now() + timedelta(minutes=10))
