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

from unittest.mock import patch

from freezegun import freeze_time

from odoo.addons.point_of_sale.tests.test_frontend import TestPointOfSaleHttpCommon
from odoo.addons.l10n_vn_edi_viettel.tests.test_edi import TestVNEDI
from odoo.exceptions import UserError
from odoo.tests import tagged
from odoo import Command


@tagged("post_install_l10n", "post_install", "-at_install")
class TestVNEDIPOS(TestVNEDI, TestPointOfSaleHttpCommon):
    @classmethod
    def setUpClass(cls):
        super().setUpClass()

        cls.template_2 = cls.env['l10n_vn_edi_viettel.sinvoice.template'].create({
            'name': '2/0024',
            'template_invoice_type': '2',
        })
        cls.symbol_2 = cls.env['l10n_vn_edi_viettel.sinvoice.symbol'].create({
            'name': 'C25MNK',
            'invoice_template_id': cls.template_2.id,
        })
        cls.company.write({
            "l10n_vn_pos_default_symbol": cls.symbol.id,
        })
        cls.walk_in_customer = cls.env.ref('l10n_vn_edi_viettel_pos.partner_walk_in_customer')

        cls.main_pos_config.open_ui()
        cls.session = cls.main_pos_config.current_session_id

    def _create_simple_order(self):
        return self.env['pos.order'].create(
            {
                "name": "Order/0001",
                "session_id": self.session.id,
                "lines": [
                    Command.create(
                        {
                            "product_id": self.product.product_variant_id.id,
                            "qty": 3,
                            "price_unit": 1.0,
                            "price_subtotal": 3.0,
                            "price_subtotal_incl": 3.0,
                        }
                    )
                ],
                "partner_id": self.walk_in_customer.id,
                "amount_tax": 0.0,
                "amount_total": 3.0,
                "amount_paid": 0.0,
                "amount_return": 0.0,
            }
        )

    def test_default_symbol(self):
        """Test default symbol on POS order invoice."""
        pos_order = self._create_simple_order()
        invoice_vals = pos_order._prepare_invoice_vals()
        self.assertEqual(
            invoice_vals["l10n_vn_edi_invoice_symbol"],
            self.symbol.id,
            "The invoice symbol on the invoice values should be the default symbol of the company.",
        )

    def test_pos_specific_symbol(self):
        """Test POS specific symbol on POS order invoice."""
        self.main_pos_config.l10n_vn_pos_symbol = self.symbol_2.id
        pos_order = self._create_simple_order()
        invoice_vals = pos_order._prepare_invoice_vals()
        self.assertEqual(
            invoice_vals["l10n_vn_edi_invoice_symbol"],
            self.symbol_2.id,
            "The invoice symbol on the invoice values should be the symbol set in the POS configuration.",
        )

    @freeze_time('2024-01-01')
    def test_invoice_send_and_print(self):
        """ Test the invoice creation, sending and printing from a POS order."""
        order = self._create_simple_order()
        move_vals = order._prepare_invoice_vals()
        invoice = order._create_invoice(move_vals)
        invoice.action_post()

        self.assertEqual(invoice.l10n_vn_edi_invoice_state, 'ready_to_send')
        self._send_invoice(invoice)

        self.assertRecordValues(
            invoice,
            [{
                'l10n_vn_edi_invoice_number': 'K24TUT01',
                'l10n_vn_edi_reservation_code': '123456',
                'l10n_vn_edi_invoice_state': 'sent',
            }]
        )
        self.assertNotEqual(invoice.l10n_vn_edi_sinvoice_xml_file, False)
        self.assertNotEqual(invoice.l10n_vn_edi_sinvoice_pdf_file, False)
        self.assertNotEqual(invoice.l10n_vn_edi_sinvoice_file, False)

    @freeze_time('2024-01-01')
    def test_invoice_refund(self):
        """ Test the refund flow of PoS order"""
        order = self._create_simple_order()
        move_vals = order._prepare_invoice_vals()
        invoice = order._create_invoice(move_vals)
        invoice.action_post()
        self._send_invoice(invoice)

        refund_order = order._refund()
        refund_move_vals = refund_order._prepare_invoice_vals()
        refund_invoice = refund_order._create_invoice(refund_move_vals)
        refund_invoice.action_post()

        self.assertEqual(refund_invoice.l10n_vn_edi_invoice_state, 'ready_to_send')
        self._send_invoice(refund_invoice)
        self.assertRecordValues(
            refund_invoice,
            [{
                'l10n_vn_edi_invoice_number': 'K24TUT01',
                'l10n_vn_edi_reservation_code': '123456',
                'l10n_vn_edi_invoice_state': 'sent',
            }]
        )
        self.assertNotEqual(refund_invoice.l10n_vn_edi_sinvoice_xml_file, False)
        self.assertNotEqual(refund_invoice.l10n_vn_edi_sinvoice_pdf_file, False)
        self.assertNotEqual(refund_invoice.l10n_vn_edi_sinvoice_file, False)

    @freeze_time('2024-01-01')
    def test_fetch_invoice_files(self):
        """Test that l10n_vn_edi_fetch_invoice_files fetches and stores XML and PDF files on a sent POS invoice."""
        order = self._create_simple_order()
        invoice = order._create_invoice(order._prepare_invoice_vals())
        invoice.action_post()
        self._send_invoice(invoice)

        self.assertEqual(invoice.l10n_vn_edi_invoice_state, 'sent')

        # Clear the files so we can verify that fetch_invoice_files re-fetches them
        invoice.l10n_vn_edi_sinvoice_pdf_file_id.unlink()
        invoice.l10n_vn_edi_sinvoice_xml_file_id.unlink()
        self.assertFalse(invoice.l10n_vn_edi_sinvoice_pdf_file)
        self.assertFalse(invoice.l10n_vn_edi_sinvoice_xml_file)

        pdf_response = ({
            'name': 'sinvoice.pdf',
            'mimetype': 'application/pdf',
            'raw': b'pdf file',
            'res_field': 'l10n_vn_edi_sinvoice_pdf_file',
        }, "")
        xml_response = ({
            'name': 'sinvoice.xml',
            'mimetype': 'application/xml',
            'raw': b'xml file',
            'res_field': 'l10n_vn_edi_sinvoice_xml_file',
        }, "")

        with patch('odoo.addons.l10n_vn_edi_viettel.models.account_move.AccountMove._l10n_vn_edi_fetch_invoice_pdf_file_data', return_value=pdf_response), \
             patch('odoo.addons.l10n_vn_edi_viettel.models.account_move.AccountMove._l10n_vn_edi_fetch_invoice_xml_file_data', return_value=xml_response):
            invoice.l10n_vn_edi_fetch_invoice_files()

        self.assertNotEqual(invoice.l10n_vn_edi_sinvoice_pdf_file, False)
        self.assertNotEqual(invoice.l10n_vn_edi_sinvoice_xml_file, False)

    @freeze_time('2024-01-01')
    def test_fetch_invoice_files_not_sent_raises(self):
        """Test that calling l10n_vn_edi_fetch_invoice_files on a non-sent invoice raises a UserError."""
        order = self._create_simple_order()
        invoice = order._create_invoice(order._prepare_invoice_vals())
        invoice.action_post()

        self.assertNotEqual(invoice.l10n_vn_edi_invoice_state, 'sent')
        with self.assertRaises(UserError):
            invoice.l10n_vn_edi_fetch_invoice_files()
