from datetime import date

from odoo.addons.account.tests.common import AccountTestInvoicingCommon
from odoo import Command


class L10nInTestInvoicingCommon(AccountTestInvoicingCommon):
    @classmethod
    @AccountTestInvoicingCommon.setup_country('in')
    def setUpClass(cls):
        super().setUpClass()

        cls.maxDiff = None
        cls.test_date = date(2023, 5, 20)

        # === Countries === #
        cls.country_in = cls.env.ref('base.in')
        cls.country_us = cls.env.ref('base.us')

        # === States === #
        cls.state_in_gj = cls.env.ref('base.state_in_gj')
        cls.state_in_mh = cls.env.ref('base.state_in_mh')
        cls.state_in_hp = cls.env.ref('base.state_in_hp')

        # === Companies === #
        cls.default_company = cls.company_data['company']
        cls.default_company.write({
            'name': "Default Company",
            'state_id': cls.state_in_gj.id,
            'vat': "24AAGCC7144L6ZE",
            'street': "Khodiyar Chowk",
            'street2': "Sala Number 3",
            'city': "Amreli",
            'zip': "365220",
            'l10n_in_is_gst_registered': True,
            'l10n_in_tds_feature': True,
            'l10n_in_tcs_feature': True,
        })

        cls.outside_in_company = cls.env['res.company'].create({
            'name': 'Outside India Company',
            'country_id': cls.country_us.id,
        })

        cls.user.write({
            'company_ids': [cls.default_company.id, cls.outside_in_company.id],
            'company_id': cls.default_company.id,
        })

        # === Partners === #
        cls.partner_a.write({
            'name': "Partner Intra State",
            'vat': '24ABCPM8965E1ZE',
            'state_id': cls.default_company.state_id.id,
            'country_id': cls.country_in.id,
            'street': "Karansinhji Rd",
            'street2': "Karanpara",
            'city': "Rajkot",
            'zip': "360001",
        })

        cls.partner_b.write({
            'vat': '27DJMPM8965E1ZE',
            'state_id': cls.state_in_mh.id,
            'country_id': cls.country_in.id,
            'street': "Sangeet Samrat Naushad Ali Rd",
            'city': "Mumbai",
            'zip': "400052",
        })

        cls.partner_foreign = cls.env['res.partner'].create({
            'name': "Foreign Partner",
            'country_id': cls.country_us.id,
            'state_id': cls.env.ref("base.state_us_1").id,
            'street': "351 Horner Chapel Rd",
            'city': "Peebles",
            'zip': "45660",
        })

        cls.partner_foreign_no_state = cls.env['res.partner'].create({
            'name': "Foreign Partner Without State",
            'country_id': cls.country_us.id,
            # No state_id defined
        })
        cls.sez_partner = cls.env['res.partner'].create({
            'name': 'SEZ Partner',
            'vat': '36AAAAA1234AAZA',
            'l10n_in_gst_treatment': 'special_economic_zone',
            'street': 'Block no. 402',
            'city': 'Some city',
            'zip': '500002',
            'state_id': cls.env.ref('base.state_in_gj').id,
            'country_id': cls.env.ref('base.in').id,
        })

        # === Taxes === #
        AccountChartTemplate = cls.env['account.chart.template']
        cls.sgst_sale_5 = AccountChartTemplate.ref('sgst_sale_5')
        cls.sgst_purchase_5 = AccountChartTemplate.ref('sgst_purchase_5')
        cls.igst_sale_5 = AccountChartTemplate.ref('igst_sale_5')
        cls.igst_sale_18 = AccountChartTemplate.ref('igst_sale_18')
        cls.sgst_sale_18 = AccountChartTemplate.ref('sgst_sale_18')
        cls.igst_sale_18_rcm = AccountChartTemplate.ref('igst_sale_18_rc')
        cls.igst_sale_18_sez_lut = AccountChartTemplate.ref('igst_sale_18_sez_lut')
        cls.igst_sale_18_sez_exp_lut = AccountChartTemplate.ref('igst_sale_18_sez_exp_lut')
        cls.igst_sale_18_sez_exp = AccountChartTemplate.ref('igst_sale_18_sez_exp')
        cls.igst_sale_18_sez_exp_inc = cls.igst_sale_18_sez_exp.copy({'price_include_override': 'tax_included'})
        cls.gst_with_cess = (
            AccountChartTemplate.ref("sgst_sale_12")
            + AccountChartTemplate.ref("cess_5_plus_1591_sale")
        )
        cls.exempt = AccountChartTemplate.ref('exempt_sale')

        # === Products === #
        cls.product_a.write({
            "l10n_in_hsn_code": "111111",
            'taxes_id': cls.sgst_sale_5,
            'supplier_taxes_id': cls.sgst_purchase_5,
        })

        cls.product_b.write({
            "l10n_in_hsn_code": "111111",
            'uom_id': cls.env.ref('uom.product_uom_unit').id,
            'lst_price': 1000.0,
            'standard_price': 1000.0,
            'taxes_id': cls.sgst_sale_5.ids,
            'supplier_taxes_id': cls.sgst_purchase_5.ids,
        })
        cls.product_with_cess = cls.env["product.product"].create({
            "name": "product_with_cess",
            "uom_id": cls.env.ref("uom.product_uom_unit").id,
            "lst_price": 1000.0,
            "standard_price": 800.0,
            "property_account_income_id": cls.company_data["default_account_revenue"].id,
            "property_account_expense_id": cls.company_data["default_account_expense"].id,
            "taxes_id": [Command.set(cls.gst_with_cess.ids)],
            "supplier_taxes_id": [Command.set(cls.sgst_purchase_5.ids)],
            "l10n_in_hsn_code": "333333",
        })

        # === Fiscal Positions === #
        cls.fp_in_intra_state = cls.env["account.chart.template"].ref('fiscal_position_in_intra_state')
        cls.fp_in_inter_state = cls.env["account.chart.template"].ref('fiscal_position_in_inter_state')
        cls.fp_in_export = cls.env["account.chart.template"].ref('fiscal_position_in_export_sez_in')

        # === Invoices === #
        cls.invoice_a = cls.init_invoice(
            move_type='out_invoice',
            partner=cls.partner_a,
            amounts=[110, 500],
            taxes=cls.igst_sale_18,
        )

        cls.invoice_b = cls.init_invoice(
            move_type='out_invoice',
            partner=cls.partner_b,
            amounts=[250, 600],
            taxes=cls.igst_sale_18,
        )

        cls.invoice_c = cls.init_invoice(
            move_type='out_invoice',
            partner=cls.partner_foreign,
            amounts=[300, 740],
            taxes=cls.igst_sale_18,
        )

        cls.invoice_d = cls.init_invoice(
            move_type='out_invoice',
            partner=cls.partner_foreign_no_state,
            amounts=[100, 200],
            taxes=cls.igst_sale_18,
        )

        cls.invoice_with_rcm = cls.init_invoice(
            "out_invoice",
            partner=cls.partner_b,
            products=cls.product_a,
            taxes=cls.igst_sale_18_rcm,
        )

        cls.invoice_with_sez_lut = cls.init_invoice(
            "out_invoice",
            partner=cls.sez_partner,
            products=cls.product_a,
            taxes=cls.igst_sale_18_sez_lut,
        )

        cls.invoice_with_sez_without_lut = cls.init_invoice(
            "out_invoice",
            partner=cls.sez_partner,
            products=cls.product_a,
            taxes=cls.igst_sale_18,
        )

        cls.invoice_with_export_lut = cls.init_invoice(
            "out_invoice",
            partner=cls.partner_foreign,
            products=cls.product_a,
            taxes=cls.igst_sale_18_sez_exp_lut,
        )

        cls.invoice_with_export_without_lut = cls.init_invoice(
            "out_invoice",
            partner=cls.partner_foreign,
            products=cls.product_a,
            taxes=cls.igst_sale_18_sez_exp,
        )
        cls.invoice_with_export_without_lut_inc = cls.init_invoice(
            "out_invoice",
            partner=cls.partner_foreign,
            products=cls.product_a,
            taxes=cls.igst_sale_18_sez_exp_inc,
        )

    @classmethod
    def _set_vals_and_post(cls, move, ref=None, line_vals=None, post=True, irn=None):
        if ref:
            move.ref = ref
        if irn:
            move.l10n_in_irn_number = irn

        if line_vals:
            move.write({'invoice_line_ids': [Command.update(line.id, line_vals) for line in move.line_ids]})

        if post:
            move.action_post()
        return move

    @classmethod
    def _init_inv(cls, move_type='out_invoice', company=None, ref=None, partner=None, taxes=None, invoice_date=None, products=None, line_vals=None, post=True, irn=None):
        return cls._set_vals_and_post(
            move=cls.init_invoice(
                move_type,
                products=products or cls.product_a,
                invoice_date=invoice_date or cls.test_date,
                taxes=taxes,
                company=company or cls.default_company,
                partner=partner,
            ),
            ref=ref,
            irn=irn,
            line_vals=line_vals,
            post=post
        )

    @classmethod
    def _create_credit_note(cls, inv, ref=None, credit_note_date=None, line_vals=None, post=True):
        move = inv._reverse_moves()
        move.invoice_date = credit_note_date or cls.test_date

        return cls._set_vals_and_post(
            move=move,
            ref=ref,
            line_vals=line_vals,
            post=post
        )

    @classmethod
    def _create_debit_note(cls, inv, ref=None, debit_note_date=None, line_vals=None):
        move_debit_note_wiz = cls.env['account.debit.note'].with_context(
            active_model="account.move",
            active_ids=inv.ids
        ).create({
            'date': debit_note_date or cls.test_date,
            'reason': 'no reason',
            'copy_lines': True,
        })
        move_debit_note_wiz.create_debit()

        return cls._set_vals_and_post(move=inv.debit_note_ids[0], ref=ref, line_vals=line_vals)
