# barbacompta - invoicing for dummies
# Copyright (C) 2019-2021 Entr'ouvert
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

import io
import xml.etree.ElementTree as ET

import facturx
import pytest
from django.contrib.auth import get_user_model

from eo_gestion.eo_facture.models import Facture


def test_limitations(db):
    facture = Facture.objects.get(
        client__nom='c3f42bb0d75d379', contrat__intitule='1da9dc528d5c7191bc87c7', ordre=137
    )
    User = get_user_model()
    creator = User.objects.get(username='admin')
    facture_avoir = facture.cancel(creator)

    with pytest.raises(AssertionError, match='cannot cancel a canceled invoice'):
        facture_avoir.cancel(creator)


def test_facture_avoir(app):
    response = app.get("/eo_facture/facture/").follow()

    response.form.set("username", "admin")
    response.form.set("password", "admin")

    homepage = response.form.submit().follow()
    factures_page = homepage.click("Factures")

    facture_0137_page = factures_page.click('F20190137')
    assert 'F20190137' in facture_0137_page.html.find('div', {'class': 'breadcrumbs'}).text
    assert facture_0137_page.html.find('input', {'id': 'id_intitule'})['value'] == '95e0eb4429394cd2'
    assert len([x for x in Facture.objects.all() if x.code() == 'F20190137']) == 1
    facture = [x for x in Facture.objects.all() if x.code() == 'F20190137'][0]
    assert facture.factures_avoir.count() == 0
    assert 'Annuler' in [li.a.text for li in facture_0137_page.html.find_all('li')]
    facture_avoir_page = facture_0137_page.click("Annuler")
    facture_avoir_page = facture_avoir_page.follow()
    assert (
        'Facture proforma du 2019-10-09' in facture_avoir_page.html.find('div', {'class': 'breadcrumbs'}).text
    )
    assert (
        facture_avoir_page.html.find('input', {'id': 'id_intitule'})['value']
        == 'AVOIR POUR LA FACTURE 95e0eb4429394cd2'
    )
    # can't cancel a canceled invoice
    assert 'Annuler' not in [li.a.text for li in facture_avoir_page.html.find_all('li')]
    assert facture.factures_avoir.count() == 1
    facture_avoir = facture.factures_avoir.first()
    assert facture_avoir.code() == 'Facture proforma du 2019-10-09'
    assert facture_avoir.annulation == facture
    assert facture_avoir.proforma is True
    assert facture.intitule == '95e0eb4429394cd2'
    assert facture_avoir.intitule == 'AVOIR POUR LA FACTURE 95e0eb4429394cd2'
    assert str(facture.lignes.first()) == '503aa5f7b148f6a106eda9274d5130c1 pour 800.85 €'
    assert str(facture_avoir.lignes.first()) == '503aa5f7b148f6a106eda9274d5130c1 pour -800.85 €'

    facture_avoir_page.form.fields['proforma'][0].checked = False
    facture_avoir_page = facture_avoir_page.form.submit('_continue')
    facture_avoir_page = facture_avoir_page.follow()
    assert 'F20190237' in facture_avoir_page.html.find('div', {'class': 'breadcrumbs'}).text
    assert (
        facture_avoir_page.html.find('input', {'id': 'id_intitule'})['value']
        == 'AVOIR POUR LA FACTURE 95e0eb4429394cd2'
    )
    facture_avoir = Facture.objects.get(id=facture_avoir.id)  # object was updated
    assert facture_avoir.code() == 'F20190237'

    assert 'Imprimer' in [li.a.text for li in facture_avoir_page.html.find_all('li')]
    factur_x_page = app.get("/eo_facture/facture/%s/view_pdf/F20190137.pdf?facturx" % facture_avoir.id)
    factur_x_pdf = factur_x_page.body
    _, factur_x_xml = facturx.get_facturx_xml_from_pdf(io.BytesIO(factur_x_pdf))
    root = ET.fromstring(factur_x_xml)

    def helper(root):
        tag = root.tag.split('}')[-1]
        if len(root) == 0:
            return [tag, root.text or '']
        else:
            return [tag] + [helper(node) for node in root]

    # factur-x facture avoir
    assert helper(root) == [
        'CrossIndustryInvoice',
        [
            'ExchangedDocumentContext',
            ['BusinessProcessSpecifiedDocumentContextParameter', ['ID', 'A1']],
            ['GuidelineSpecifiedDocumentContextParameter', ['ID', 'urn:factur-x.eu:1p0:basicwl']],
        ],
        [
            'ExchangedDocument',
            ['ID', 'F20190237'],
            ['TypeCode', '381'],
            ['IssueDateTime', ['DateTimeString', '20190101']],
        ],
        [
            'SupplyChainTradeTransaction',
            [
                'ApplicableHeaderTradeAgreement',
                [
                    'SellerTradeParty',
                    ['Name', "Entr'ouvert"],
                    ['SpecifiedLegalOrganization', ['ID', '44317013900036']],
                    ['PostalTradeAddress', ['CountryID', 'FR']],
                    ['SpecifiedTaxRegistration', ['ID', 'FR09491081899']],
                ],
                [
                    'BuyerTradeParty',
                    ['Name', 'c3f42bb0d75d379'],
                    [
                        'SpecifiedLegalOrganization',
                        ['ID', ''],
                    ],
                ],
            ],
            ['ApplicableHeaderTradeDelivery', ''],
            [
                'ApplicableHeaderTradeSettlement',
                ['InvoiceCurrencyCode', 'EUR'],
                ['SpecifiedTradeSettlementPaymentMeans', ['TypeCode', '97']],
                [
                    'ApplicableTradeTax',
                    ['CalculatedAmount', '-160.17'],
                    ['TypeCode', 'VAT'],
                    ['BasisAmount', '-800.85'],
                    ['CategoryCode', 'S'],
                    ['RateApplicablePercent', '20.00'],
                ],
                [
                    'SpecifiedTradeSettlementHeaderMonetarySummation',
                    ['LineTotalAmount', '-800.85'],
                    ['TaxBasisTotalAmount', '-800.85'],
                    ['TaxTotalAmount', '-160.17'],
                    ['GrandTotalAmount', '-961.02'],
                    ['DuePayableAmount', '-961.02'],
                ],
                ['InvoiceReferencedDocument', ['IssuerAssignedID', 'F20190137']],
            ],
        ],
    ]

