/*
 * This file is part of LibEuFin.
 * Copyright (C) 2024, 2025, 2026 Taler Systems S.A.

 * LibEuFin 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, or
 * (at your option) any later version.

 * LibEuFin 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 LibEuFin; see the file COPYING.  If not, see
 * <http://www.gnu.org/licenses/>
 */

import org.junit.Test
import tech.libeufin.common.*
import tech.libeufin.nexus.*
import tech.libeufin.nexus.iso20022.*
import tech.libeufin.ebics.*
import kotlin.io.path.*
import kotlin.test.*
import java.time.Instant

class Iso20022Test {
    @Test
    fun pain001() {
        val creditor = IbanAccountMetadata(
            iban = IBAN.parse("CH4189144589712575493"),
            bic = null,
            name = "Test"
        )
        val msg = Pain001Msg(
            messageId = "MESSAGE_ID",
            timestamp = dateToInstant("2024-09-09"),
            debtor = IbanAccountMetadata(
                iban = IBAN.parse("CH7789144474425692816"),
                bic = "BIC",
                name = "myname"
            ),
            sum = TalerAmount("CHF:47.32"),
            txs = listOf(
                Pain001Tx(
                    creditor = creditor,
                    amount = TalerAmount("CHF:42"),
                    subject = "Test 42",
                    endToEndId = "TX_FIRST"
                ),
                Pain001Tx(
                    creditor = creditor,
                    amount = TalerAmount("CHF:5.11"),
                    subject = "Test 5.11",
                    endToEndId = "TX_SECOND"
                ),
                Pain001Tx(
                    creditor = creditor,
                    amount = TalerAmount("CHF:0.21"),
                    subject = "Test 0.21",
                    endToEndId = "TX_THIRD"
                )
            )
        )
        for (dialect in Dialect.entries) {
            assertEquals(
                Path("sample/platform/${dialect}_pain001.xml").readText().replace("VERSION", VERSION),
                createPain001(msg, dialect, false).asUtf8()
            )
        }
    }

    @Test
    fun hac() {
        assertContentEquals(
            parseCustomerAck(Path("sample/platform/hac.xml").inputStream()),
            listOf(
                CustomerAck(
                    actionType = HacAction.FILE_DOWNLOAD,
                    orderId = null,
                    code = ExternalStatusReasonCode.TS01,
                    info = "",
                    timestamp = dateTimeToInstant("2024-09-02T15:47:30.350Z")
                ),
                CustomerAck(
                    actionType = HacAction.FILE_UPLOAD,
                    orderId = "ORDER_SUCCESS",
                    code = ExternalStatusReasonCode.TS01,
                    info = "",
                    timestamp = dateTimeToInstant("2024-09-02T20:48:43.153Z")
                ),
                CustomerAck(
                    actionType = HacAction.ES_VERIFICATION,
                    orderId = "ORDER_SUCCESS",
                    code = ExternalStatusReasonCode.DS01,
                    info = "",
                    timestamp = dateTimeToInstant("2024-09-02T20:48:43.153Z")
                ),
                CustomerAck(
                    actionType = HacAction.ORDER_HAC_FINAL_POS,
                    orderId = "ORDER_SUCCESS",
                    code = null,
                    info = "Some multiline info",
                    timestamp = dateTimeToInstant("2024-09-02T20:48:43.153Z")
                ),
                CustomerAck(
                    actionType = HacAction.FILE_DOWNLOAD,
                    orderId = null,
                    code = ExternalStatusReasonCode.TD01,
                    info = "",
                    timestamp = dateTimeToInstant("2024-09-02T15:47:31.754Z")
                ),
                CustomerAck(
                    actionType = HacAction.FILE_UPLOAD,
                    orderId = "ORDER_FAILURE",
                    code = ExternalStatusReasonCode.TS01,
                    info = "",
                    timestamp = dateTimeToInstant("2024-08-23T15:34:11.987")
                ),
                CustomerAck(
                    actionType = HacAction.ES_VERIFICATION,
                    orderId = "ORDER_FAILURE",
                    code = ExternalStatusReasonCode.TD03,
                    info = "",
                    timestamp = dateTimeToInstant("2024-08-23T15:34:13.307")
                ),
                CustomerAck(
                    actionType = HacAction.ORDER_HAC_FINAL_NEG,
                    orderId = "ORDER_FAILURE",
                    code = null,
                    info = "",
                    timestamp = dateTimeToInstant("2024-08-23T15:34:13.307")
                ),
            )
        )
    }

    @Test
    fun postfinance_camt054() {
        assertContentEquals(
            parseTx(Path("sample/platform/postfinance_camt054.xml").inputStream()),
            listOf(AccountTransactions(
                iban = "CH9289144596463965762",
                currency = "CHF",
                txs = listOf(
                    OutgoingPayment(
                        id = OutgoingId("ZS1PGNTSV0ZNDFAJBBWWB8015G", "ZS1PGNTSV0ZNDFAJBBWWB8015G", null),
                        amount = TalerAmount("CHF:3.00"),
                        subject = null,
                        executionTime = dateToInstant("2024-01-15"),
                        creditor = null
                    ),
                    IncomingPayment(
                        id = IncomingId("62e2b511-7313-4ccd-8d40-c9d8e612cd71", null, "231121CH0AZWCR9T"),
                        amount = TalerAmount("CHF:10"),
                        subject = "G1XTY6HGWGMVRM7E6XQ4JHJK561ETFDFTJZ7JVGV543XZCB27YBG",
                        executionTime = dateToInstant("2023-12-19"),
                        debtor = ibanPayto("CH7389144832588726658", "Mr Test")
                    ),
                    IncomingPayment(
                        id = IncomingId("62e2b511-7313-4ccd-8d40-c9d8e612cd71", null, "231121CH0AZWCVR1"),
                        amount = TalerAmount("CHF:2.53"),
                        subject = "G1XTY6HGWGMVRM7E6XQ4JHJK561ETFDFTJZ7JVGV543XZCB27YB",
                        executionTime = dateToInstant("2023-12-19"),
                        debtor = ibanPayto("CH7389144832588726658", "Mr Test")
                    ),
                    OutgoingReversal(
                        endToEndId = "50820f78-9024-44ff-978d-63a18c",
                        msgId = "50820f78-9024-44ff-978d-63a18c",
                        reason = "",
                        executionTime = dateToInstant("2024-01-15")
                    ),
                    OutgoingBatch(
                        msgId = "ZS1PGNTSV0ZNDFAJBBWWB8015G",
                        executionTime = dateToInstant("2024-01-15")
                    )
                )
            ))
        )
    }

    @Test
    fun postfinance_camt053() {
        assertContentEquals(
            parseTx(Path("sample/platform/postfinance_camt053.xml").inputStream()),
            listOf(AccountTransactions(
                iban = "CH9289144596463965762",
                currency = "CHF",
                txs = listOf(
                    OutgoingReversal(
                        endToEndId = "889d1a80-1267-49bd-8fcc-85701a",
                        msgId = "889d1a80-1267-49bd-8fcc-85701a",
                        reason = "InconsistenWithEndCustomer 'Identification of end customer is not consistent with associated account number, organisation ID or private ID.' - 'more info here ...'",
                        executionTime = dateToInstant("2023-11-22")
                    ),
                    OutgoingReversal(
                        endToEndId = "4cc61cc7-6230-49c2-b5e2-b40bbb",
                        msgId = "4cc61cc7-6230-49c2-b5e2-b40bbb",
                        reason = "MissingCreditorNameOrAddress 'Specification of the creditor’s name and/or address needed for regulatory requirements is insufficient or missing.' - 'more info here ...'",
                        executionTime = dateToInstant("2023-11-22")
                    ),
                    OutgoingBatch(
                        msgId = "EB4D22D428214261B2B3012D2A8CEC36",
                        executionTime = dateToInstant("2024-08-26")
                    )
                )
            ))
        )
    }

    @Test
    fun valiant_camt052() {
        assertContentEquals(
            parseTx(Path("sample/platform/valiant_camt052.xml").inputStream()),
            listOf(AccountTransactions(
                iban = "CH7389144832588726658",
                currency = "CHF",
                txs = listOf(
                    OutgoingPayment(
                        id = OutgoingId("MJDJO2BDDBL7YSL2P96SXHG3TQZEZQD26L", "4UWWIDGTEIGDU6Z721QE95PYJSIEA48PYE", "ZV20251030/511372/1"),
                        amount = TalerAmount("CHF:0.1"),
                        creditor = ibanPayto("CH7389144832588726658", "Grothoff Hans"),
                        subject = "single 2025-10-30T09:46:04.55293090 9Z",
                        executionTime = dateToInstant("2025-10-30")
                    ),
                    OutgoingPayment(
                        id = OutgoingId("5HIS3433VVIBAANHW3GX9DR1AXRS43KZ4U", "SKMU2891PAAYBDW22DBWX2W7KTFZ1CDFO8", "ZV20251030/511373/1"),
                        amount = TalerAmount("CHF:0.1"),
                        creditor = ibanPayto("CH7389144832588726658", "Grothoff Hans"),
                        subject = "multi 0 2025-10-30T09:46:10.3877961 30Z",
                        executionTime = dateToInstant("2025-10-30")
                    ),
                    OutgoingPayment(
                        id = OutgoingId("5HIS3433VVIBAANHW3GX9DR1AXRS43KZ4U", "RC9YD301NZ17YKD6WDWLNOROFHIIN29VJN", "ZV20251030/511373/2"),
                        amount = TalerAmount("CHF:0.11"),
                        creditor = ibanPayto("CH7389144832588726658", "Grothoff Hans"),
                        subject = "multi 1 2025-10-30T09:46:10.3877961 30Z",
                        executionTime = dateToInstant("2025-10-30")
                    ),
                    OutgoingPayment(
                        id = OutgoingId("5HIS3433VVIBAANHW3GX9DR1AXRS43KZ4U", "GKDGTHLB82X6XVHBJIJ1CK8MEGU9XJ2EL7", "ZV20251030/511373/3"),
                        amount = TalerAmount("CHF:0.12"),
                        creditor = ibanPayto("CH7389144832588726658", "Grothoff Hans"),
                        subject = "multi 2 2025-10-30T09:46:10.3877961 30Z",
                        executionTime = dateToInstant("2025-10-30")
                    ),
                    OutgoingPayment(
                        id = OutgoingId("5HIS3433VVIBAANHW3GX9DR1AXRS43KZ4U", "PXCH2VVVTXEXBVDWICP23HZ4NV0H2CWW28", "ZV20251030/511373/4"),
                        amount = TalerAmount("CHF:0.13"),
                        creditor = ibanPayto("CH7389144832588726658", "Grothoff Hans"),
                        subject = "multi 3 2025-10-30T09:46:10.3877961 30Z",
                        executionTime = dateToInstant("2025-10-30")
                    ),
                    IncomingPayment(
                        id = IncomingId(null, "51030655601.0001", "ZV20251030/514778/1"),
                        amount = TalerAmount("CHF:0.85"),
                        subject = "fun stuff",
                        executionTime = dateToInstant("2025-10-30"),
                        debtor = ibanPayto("CH7389144832588726658", "Grothoff Hans"),
                    ),
                    IncomingPayment(
                        id = IncomingId(null, "51030655601.0002", "ZV20251030/514779/1"),
                        amount = TalerAmount("CHF:0.95"),
                        subject = "Taler PC2MKG0B7CK32K1T7DP08P6E1B7FHB6HY6R Q0PT3VTPBPRPYM1B0",
                        executionTime = dateToInstant("2025-10-30"),
                        debtor = ibanPayto("CH7389144832588726658", "Grothoff Hans"),
                    ),
                    OutgoingPayment(
                        id = OutgoingId("X166701F6RV59LP71RVWVIW9SV2AFZYLG4", "R48UBIIB7B4LX0DMVOSI0ZTJWMMG8FMNKX", "ZV20251030/524078/1"),
                        amount = TalerAmount("CHF:0.21"),
                        creditor = ibanPayto("CH6208704048981247126", "John Smith"),
                        subject = "bad name 2025-10-30T12:03:24.997478 811Z",
                        executionTime = dateToInstant("2025-10-30")
                    ),
                    OutgoingPayment(
                        id = OutgoingId("6OZN5T9W7MK6BIZYE01E62NHGP5JLMUD4X", "02WDIX4J90Z1M1WNFHLNSXY59SHXQTQCMQ", "ZV20251030/524079/1"),
                        amount = TalerAmount("CHF:0.1"),
                        creditor = ibanPayto("CH7389144832588726658", "Grothoff Hans"),
                        subject = "single 2025-10-30T12:04:00.37042083 6Z",
                        executionTime = dateToInstant("2025-10-30")
                    ),
                    OutgoingPayment(
                        id = OutgoingId("6OZN5T9W7MK6BIZYE01E62NHGP5JLMUD4X", "XAP5L7HVWPLCEMECU4GZK6GKUPBL0TD13Y", "ZV20251030/524079/2"),
                        amount = TalerAmount("CHF:0.21"),
                        creditor = ibanPayto("CH6208704048981247126", "John Smith"),
                        subject = "bad name 2025-10-30T12:03:53.042190 686Z",
                        executionTime = dateToInstant("2025-10-30")
                    ),
                    OutgoingReversal(
                        endToEndId = "XAP5L7HVWPLCEMECU4GZK6GKUPBL0TD13Y",
                        reason = "Error msg in german",
                        executionTime = dateToInstant("2025-10-30")
                    ),
                    OutgoingReversal(
                        endToEndId = "R48UBIIB7B4LX0DMVOSI0ZTJWMMG8FMNKX",
                        reason = "Error msg in german",
                        executionTime = dateToInstant("2025-10-30")
                    ),
                    OutgoingPayment(
                        id = OutgoingId("OLAMDPI6YPMNRZHQ5PQ6JCVUQV2AN5NW6P", "TU2WJ54DR9Z6HT5VE494BNH4EXUSM0DRF7", "ZV20251030/524077/1"),
                        amount = TalerAmount("CHF:0.23"),
                        debitFee = TalerAmount("CHF:5"),
                        creditor = ibanPayto("DE48330605920000686018", "Christian Grothoff"),
                        subject = "foreign iban 2025-10-30T12:03:44.0972 63765Z",
                        executionTime = dateToInstant("2025-10-30")
                    ),
                    OutgoingPayment(
                        id = OutgoingId("6OZN5T9W7MK6BIZYE01E62NHGP5JLMUD4X", "GM8I8GIETR72LP6CFBGRBUDKNO2CEQBGOE", "ZV20251030/524080/1"),
                        amount = TalerAmount("CHF:0.23"),
                        debitFee = TalerAmount("CHF:5"),
                        creditor = ibanPayto("DE48330605920000686018", "Christian Grothoff"),
                        subject = "foreign iban 2025-10-30T12:03:58.0046 73747Z",
                        executionTime = dateToInstant("2025-10-30")
                    ),
                    IncomingPayment(
                        id = IncomingId("7b76d488-05d5-44ab-9d77-31d4165ec158", "00204EQY370", "ZV20251118/685062/1"),
                        amount = TalerAmount("CHF:4.55"),
                        subject = "TEST",
                        executionTime = dateToInstant("2025-11-18"),
                        debtor = null
                    ),
                )
            ))
        )
    }

    @Test
    fun raiffeisen_camt053() {
        assertContentEquals(
            parseTx(Path("sample/platform/raiffeisen_camt053.xml").inputStream()),
            listOf(AccountTransactions(
                iban = "CH7389144832588726658",
                currency = null,
                txs = listOf(
                    IncomingPayment(
                        id = IncomingId(null, null, "A200020494367552"),
                        amount = TalerAmount("CHF:20000"),
                        subject = "1. TZ 2025",
                        executionTime = dateToInstant("2025-12-23"),
                        debtor = ibanPayto("CH7389144832588726658", "KANTON BERN")
                    ),
                    OutgoingPayment(
                        id = OutgoingId(null, null, "19868398389"),
                        amount = TalerAmount("CHF:15"),
                        executionTime = dateToInstant("2025-12-31"),
                        subject = null,
                        creditor = null
                    ),
                    OutgoingPayment(
                        id = OutgoingId(null, null, "19890406743"),
                        amount = TalerAmount("CHF:2"),
                        executionTime = dateToInstant("2025-12-31"),
                        subject = null,
                        creditor = null
                    ),
                      OutgoingPayment(
                        id = OutgoingId(null, null, "19885172770"),
                        amount = TalerAmount("CHF:3"),
                        executionTime = dateToInstant("2025-12-31"),
                        subject = null,
                        creditor = null
                    ),
                )
            ))
        )
    }

    @Test
    fun gls_camt052() {
        assertContentEquals(
            parseTx(Path("sample/platform/gls_camt052.xml").inputStream()),
            listOf(AccountTransactions(
                iban = "DE84500105177118117964",
                currency = "EUR",
                txs = listOf(
                    OutgoingPayment(
                        id = OutgoingId("COMPAT_SUCCESS", "COMPAT_SUCCESS", "2024041801514102000"),
                        amount = TalerAmount("EUR:2"),
                        subject = "TestABC123",
                        executionTime = dateToInstant("2024-04-18"),
                        creditor = ibanPayto("DE20500105172419259181", "John Smith")
                    ),
                    OutgoingReversal(
                        endToEndId = "8XK8Z7RAX224FGWK832FD40GYC",
                        reason = "IncorrectAccountNumber 'Format of the account number specified is not correct' - 'IBAN fehlerhaft und ungültig'",
                        executionTime = dateToInstant("2024-09-05")
                    ),
                    IncomingPayment(
                        id = IncomingId(null, "BYLADEM1WOR-G2910276709458A2", "2024041210041357000"),
                        amount = TalerAmount("EUR:3"),
                        subject = "Taler FJDQ7W6G7NWX4H9M1MKA12090FRC9K7DA6N0FANDZZFXTR6QHX5G Test.,-",
                        executionTime = dateToInstant("2024-04-12"),
                        debtor = ibanPayto("DE84500105177118117964", "John Smith")
                    ),
                    OutgoingReversal(
                        endToEndId = "COMPAT_FAILURE",
                        reason = "IncorrectAccountNumber 'Format of the account number specified is not correct' - 'IBAN ...'",
                        executionTime = dateToInstant("2024-04-12")
                    ),
                    OutgoingPayment(
                        id = OutgoingId("BATCH_SINGLE_SUCCESS", "FD622SMXKT5QWSAHDY0H8NYG3G", "2024090216552232000"),
                        amount = TalerAmount("EUR:1.1"),
                        subject = "single 2024-09-02T14:29:52.875253314Z",
                        executionTime = dateToInstant("2024-09-02"),
                        creditor = ibanPayto("DE89500105173198527518", "Grothoff Hans")
                    ),
                    OutgoingPayment(
                        id = OutgoingId("YF5QBARGQ0MNY0VK59S477VDG4", "YF5QBARGQ0MNY0VK59S477VDG4", "2024041810552821000"),
                        amount = TalerAmount("EUR:1.1"),
                        subject = "Simple tx",
                        executionTime = dateToInstant("2024-04-18"),
                        creditor = ibanPayto("DE20500105172419259181", "John Smith")
                    ),
                    OutgoingBatch(
                        msgId = "BATCH_MANY_SUCCESS",
                        executionTime = dateToInstant("2024-09-20"),
                    ),
                    OutgoingPayment(
                        id = OutgoingId("BATCH_SINGLE_RETURN", "KLJJ28S1LVNDK1R2HCHLN884M7EKM5XGM5", "2024092100252498000"),
                        amount = TalerAmount("EUR:0.42"),
                        subject = "This should fail because bad iban",
                        executionTime = dateToInstant("2024-09-23"),
                        creditor = ibanPayto("DE18500105173385245163", "John Smith")
                    ),
                    OutgoingReversal(
                        endToEndId = "KLJJ28S1LVNDK1R2HCHLN884M7EKM5XGM5",
                        reason = "IncorrectAccountNumber 'Format of the account number specified is not correct' - 'IBAN fehlerhaft und ungültig'",
                        executionTime = dateToInstant("2024-09-24")
                    ),
                )
            ))
        )
    }

    @Test
    fun gls_camt053() {
        assertContentEquals(
            parseTx(Path("sample/platform/gls_camt053.xml").inputStream()),
            listOf(AccountTransactions(
                iban = "DE84500105177118117964",
                currency = "EUR",
                txs = listOf(
                    OutgoingPayment(
                        id = OutgoingId("COMPAT_SUCCESS", "COMPAT_SUCCESS", "2024041801514102000"),
                        amount = TalerAmount("EUR:2"),
                        subject = "TestABC123",
                        executionTime = dateToInstant("2024-04-18"),
                        creditor = ibanPayto("DE20500105172419259181", "John Smith")
                    ),
                    OutgoingReversal(
                        endToEndId = "KGTDBASWTJ6JM89WXD3Q5KFQC4",
                        reason = "Retoure aus SEPA Überweisung multi line",
                        executionTime = dateToInstant("2024-09-04")
                    ),
                    OutgoingBatch(
                        msgId = "BATCH_MANY_PART",
                        executionTime = dateToInstant("2024-09-04")
                    ),
                    IncomingPayment(
                        id = IncomingId(null, "BYLADEM1WOR-G2910276709458A2", "2024041210041357000"),
                        amount = TalerAmount("EUR:3"),
                        subject = "Taler FJDQ7W6G7NWX4H9M1MKA12090FRC9K7DA6N0FANDZZFXTR6QHX5G Test.,-",
                        executionTime = dateToInstant("2024-04-12"),
                        debtor = ibanPayto("DE84500105177118117964", "John Smith")
                    ),
                    OutgoingReversal(
                        endToEndId = "COMPAT_FAILURE",
                        reason = "IncorrectAccountNumber 'Format of the account number specified is not correct' - 'IBAN ...'",
                        executionTime = dateToInstant("2024-04-12")
                    ),
                    OutgoingPayment(
                        id = OutgoingId("BATCH_SINGLE_SUCCESS", "FD622SMXKT5QWSAHDY0H8NYG3G", "2024090216552232000"),
                        amount = TalerAmount("EUR:1.1"),
                        subject = "single 2024-09-02T14:29:52.875253314Z",
                        executionTime = dateToInstant("2024-09-02"),
                        creditor = ibanPayto("DE89500105173198527518", "Grothoff Hans")
                    ),
                    OutgoingPayment(
                        id = OutgoingId("YF5QBARGQ0MNY0VK59S477VDG4", "YF5QBARGQ0MNY0VK59S477VDG4", "2024041810552821000"),
                        amount = TalerAmount("EUR:1.1"),
                        subject = "Simple tx",
                        executionTime = dateToInstant("2024-04-18"),
                        creditor = ibanPayto("DE20500105172419259181", "John Smith")
                    ),
                ))
            )
        )
    }

    @Test
    fun gls_camt054() {
        assertContentEquals(
            parseTx(Path("sample/platform/gls_camt054.xml").inputStream()),
            listOf(AccountTransactions(
                iban = "DE84500105177118117964",
                currency = "EUR",
                txs = listOf<TxNotification>(
                    IncomingPayment(
                        id = IncomingId(null, "IS11PGENODEFF2DA8899900378806", null),
                        amount = TalerAmount("EUR:2.5"),
                        subject = "Test ICT",
                        executionTime = dateToInstant("2024-05-05"),
                        debtor = ibanPayto("DE84500105177118117964", "Mr Test")
                    )
                )
            ))
        )
    }

    @Test
    fun maerki_baumann_camt053() {
        assertContentEquals(
            parseTx(Path("sample/platform/maerki_baumann_camt053.xml").inputStream()),
            listOf(AccountTransactions(
                iban = "CH7389144832588726658",
                currency = "CHF",
                txs = listOf<TxNotification>(
                    IncomingPayment(
                        id = IncomingId("adbe4a5a-6cea-4263-b259-8ab964561a32", "41103099704.0002", "ZV20241104/765446/1"),
                        amount = TalerAmount("CHF:1"),
                        creditFee = TalerAmount("CHF:0.2"),
                        subject = "SFHP6H24C16A5J05Q3FJW2XN1PB3EK70ZPY 5SJ30ADGY68FWN68G",
                        executionTime = dateToInstant("2024-11-04"),
                        debtor = ibanPayto("CH7389144832588726658", "Mr Test")
                    ),
                    IncomingPayment(
                        id = IncomingId("7371795e-62fa-42dd-93b7-da89cc120faa", "41103099704.0003", "ZV20241104/765447/1"),
                        amount = TalerAmount("CHF:1"),
                        creditFee = TalerAmount("CHF:0.2"),
                        subject = "Random subject",
                        executionTime = dateToInstant("2024-11-04"),
                        debtor = ibanPayto("CH7389144832588726658", "Mr Test")
                    ),
                    IncomingPayment(
                        id = IncomingId(null, "50523424675.0001", "ZV20250523/851716/1"),
                        amount = TalerAmount("CHF:0.5"),
                        creditFee = TalerAmount("CHF:0.2"),
                        subject = null,
                        executionTime = dateToInstant("2025-05-23"),
                        debtor = ibanPayto("CH7389144832588726658", "Grothoff Hans")
                    ),
                    OutgoingPayment(
                        id = OutgoingId("BATCH_SINGLE_REPORTING", "5IBJZOWESQGPCSOXSNNBBY49ZURI5W7Q4H", "ZV20241121/773541/1"),
                        amount = TalerAmount("CHF:0.1"),
                        subject = "multi 0 2024-11-21T15:21:59.8859234 63Z",
                        executionTime = dateToInstant("2024-11-27"),
                        creditor = ibanPayto("CH7389144832588726658", "Grothoff Hans")
                    ),
                    OutgoingPayment(
                        id = OutgoingId("BATCH_SINGLE_REPORTING", "XZ15UR0XU52QWI7Q4XB88EDS44PLH7DYXH", "ZV20241121/773541/4"),
                        amount = TalerAmount("CHF:0.13"),
                        subject = "multi 3 2024-11-21T15:21:59.8859234 63Z",
                        executionTime = dateToInstant("2024-11-27"),
                        creditor = ibanPayto("CH7389144832588726658", "Grothoff Hans")
                    ),
                    OutgoingPayment(
                        id = OutgoingId("BATCH_SINGLE_REPORTING", "A09R35EW0359SZ51464E7TC37A0P2CBK04", "ZV20241121/773541/3"),
                        amount = TalerAmount("CHF:0.12"),
                        subject = "multi 2 2024-11-21T15:21:59.8859234 63Z",
                        executionTime = dateToInstant("2024-11-27"),
                        creditor = ibanPayto("CH7389144832588726658", "Grothoff Hans")
                    ),
                    OutgoingPayment(
                        id = OutgoingId("BATCH_SINGLE_REPORTING", "UYXZ78LE9KAIMBY6UNXFYT1K8KNY8VLZLT", "ZV20241121/773541/2"),
                        amount = TalerAmount("CHF:0.11"),
                        subject = "multi 1 2024-11-21T15:21:59.8859234 63Z",
                        executionTime = dateToInstant("2024-11-27"),
                        creditor = ibanPayto("CH7389144832588726658", "Grothoff Hans")
                    ),
                    IncomingPayment(
                        id = IncomingId("f203fbb4-6e13-4c78-9b2a-d852fea6374a", "41202060702.0001", "ZV20241202/778108/1"),
                        amount = TalerAmount("CHF:0.05"),
                        creditFee = TalerAmount("CHF:0.2"),
                        subject = "mini",
                        executionTime = dateToInstant("2024-12-02"),
                        debtor = ibanPayto("CH7389144832588726658", "Grothoff Hans")
                    ),
                    IncomingPayment(
                        id = IncomingId("81b0d8c6-a677-4577-b75e-a639dcc03681", "41120636093.0001", "ZV20241121/773118/1"),
                        amount = TalerAmount("CHF:0.1"),
                        creditFee = TalerAmount("CHF:0.2"),
                        subject = "small transfer test",
                        executionTime = dateToInstant("2024-11-21"),
                        debtor = ibanPayto("CH7389144832588726658", "Grothoff Hans")
                    ),
                    OutgoingPayment(
                        id = OutgoingId(null, null, "GB20241220/205792/1"),
                        amount = TalerAmount("CHF:3000"),
                        subject = null,
                        executionTime = dateToInstant("2024-12-20"),
                        creditor = null
                    ),
                    IncomingPayment(
                        id = IncomingId(null, null, "ZV20250114/796191/1"),
                        amount = TalerAmount("CHF:3003"),
                        subject = "Fix bad payment by MB.",
                        executionTime = dateToInstant("2025-01-27"),
                        debtor = null
                    ),
                    IncomingPayment(
                        id = IncomingId(null, "F000787951230001", "ZV20250526/852733/1"),
                        amount = TalerAmount("CHF:1.38"),
                        creditFee = TalerAmount("CHF:0.2"),
                        subject = "Taler XT3D9MADR4V85JBWX47SMJFDQD2FDZDHHPH8R25YDG1KNVTSEH6G",
                        executionTime = dateToInstant("2025-05-26"),
                        debtor = ibanPayto("DE20500105172419259181", "Mr German")
                    ),
                )
            ))
        )
    }

    @Test
    fun pain002() {
        assertEquals(
            parseCustomerPaymentStatusReport(Path("sample/platform/pain002_part.xml").inputStream()),
            MsgStatus(
                id = "05BD4C5B4A2649B5B08F6EF6A31F197A",
                code = ExternalPaymentGroupStatusCode.PART,
                reasons = emptyList(),
                payments = listOf(
                    PmtStatus(
                        id = "NOTPROVIDED",
                        code = ExternalPaymentGroupStatusCode.PART,
                        reasons = listOf(
                            Reason(
                                code = ExternalStatusReasonCode.DT06,
                                information = "Due date is not a working day. Order will be executed on the next working day"
                            )
                        ),
                        transactions = listOf(
                            TxStatus(
                                id = "AQCXNCPWD8PHW5JTN65Y5XTF7R",
                                endToEndId = "AQCXNCPWD8PHW5JTN65Y5XTF7R",
                                code = ExternalPaymentTransactionStatusCode.RJCT, 
                                reasons = listOf(
                                    Reason(
                                        code = ExternalStatusReasonCode.AC04, 
                                        information = "Error message"
                                    )
                                )
                            ),
                            TxStatus(
                                id = "EE9SX76FC5YSC657EK3GMVZ9TC",
                                endToEndId = "EE9SX76FC5YSC657EK3GMVZ9TC",
                                code = ExternalPaymentTransactionStatusCode.RJCT,
                                reasons = listOf(
                                    Reason(
                                        code = ExternalStatusReasonCode.MS03,
                                        information = "Error message"
                                    )
                                )
                            ),
                            TxStatus(
                                id = "V5B3MXPEWES9VQW1JDRD6VAET4",
                                endToEndId = "V5B3MXPEWES9VQW1JDRD6VAET4",
                                code = ExternalPaymentTransactionStatusCode.RJCT,
                                reasons = listOf(
                                    Reason(
                                        code = ExternalStatusReasonCode.RR02,
                                        information = "Error message"
                                    )
                                )
                            )
                        )
                    )
                )
            )
        )
        assertEquals(
            parseCustomerPaymentStatusReport(Path("sample/platform/pain002_accp.xml").inputStream()),
            MsgStatus(
                id = "5HIS3433VVIBAANHW3GX9DR1AXRS43KZ4U",
                code = ExternalPaymentGroupStatusCode.ACCP,
                reasons = listOf(
                    Reason(
                        code = null,
                        information = "PN10630020F0297329.20251030104613.EBTUAAAC.PN1.0002372"
                    )
                ),
                payments = emptyList()
            )
        )
    }
}