/*
 * Copyright (c) 2022 Proton AG
 *
 * This file is part of Proton Mail.
 *
 * Proton Mail is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Proton Mail 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Proton Mail. If not, see https://www.gnu.org/licenses/.
 */
package ch.protonmail.android.crypto

import android.text.TextUtils
import androidx.test.filters.LargeTest
import ch.protonmail.android.api.models.Keys
import ch.protonmail.android.core.UserManager
import ch.protonmail.android.data.local.model.Attachment
import ch.protonmail.android.mapper.bridge.AddressKeyBridgeMapper
import ch.protonmail.android.mapper.bridge.UserKeyBridgeMapper
import ch.protonmail.android.utils.crypto.OpenPGP
import io.mockk.every
import io.mockk.mockk
import io.mockk.mockkStatic
import me.proton.core.crypto.common.keystore.EncryptedByteArray
import me.proton.core.crypto.common.keystore.KeyStoreCrypto
import me.proton.core.domain.arch.map
import me.proton.core.domain.entity.UserId
import me.proton.core.user.domain.entity.AddressId
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import javax.mail.internet.InternetHeaders
import kotlin.test.Test

@LargeTest
internal class CryptoTest {

    private val oneAddressKeyUserManagerMock: UserManager = mockk()
    private val manyAddressKeysUserManagerMock: UserManager = mockk()
    private val openPgp = OpenPGP()
    private val keyStoreCrypto: KeyStoreCrypto = NoEncryptionKeyStoreCrypto
    private val openPgpMock: OpenPGP = mockk()

    //region One Address Key Setup
    private val oneAddressKeyUserId = UserId("one_address_key_user")
    private val oneAddressKeyMailboxPassword = "7NgO4d0h72zt4XuFLOUbg352vhrn.tu"
    private val oneAddressKeyAddressId =
        "MMxTCP7DMErrWkOREQljdviitcZ1mDzjWcnzdg8wqObisClP25ILZ18vUsNgUVi-JD3O2EgmOuiEmx8C5qmofw=="
    private val oneAddressKeyUserKeyFingerprint = "20cf363b58ec99e722e53ec411c31e8e5e07f4d0"
    private val armoredPrivateKey =
        """
                -----BEGIN PGP PRIVATE KEY BLOCK-----
                Version: ProtonMail

[encoded data, 4389 characters]
                dlEt7f8XNvX3HxQw9w==
                =FW0u
                -----END PGP PRIVATE KEY BLOCK-----
        """.trimIndent()
    private val oneAddressKeyAddressKeys = listOf(
        Keys(
            "DvRZxrFRFUnjsL6MCOdGjyMZ9AoECd7kNXX9uKxmV-75K4iArEHijRPvd7Dhw43yBlCDxIsbNSW7cg2Uu5FUFg==",
            armoredPrivateKey,
            3,
            1,
            null,
            null,
            null,
            1
        )
    )
    private val oneAddressKeyUserKeys = listOf(
        Keys(
            "ScOOyl7_x7HXDuIUGUzWaIz83IFQJKWHi85smpaV-QH-4gVnDBwnWBtDixsVMfehF-ZGOjxrbUfUsmm7cO4R5Q==",
            armoredPrivateKey,
            0,
            1,
            null,
            null,
            null,
            1
        )
    )
    //endregion

    //region Many Address Keys Setup
    private val manyAddressKeysUserId = UserId("many_address_keys_user")
    private val manyAddressKeysMailboxPassword = "ikaAA3dimv9p7D.bqZ6mq.R45LRS6oi"
    private val manyAddressKeysAddressId =
        "odHOhMzF3YKgGR9firZjLxRWn9lfF2CPuS4XX2t0VWaKggxd3qqQ6QWv-hSbavF6VjZRmuFdDVXsMgh_lhUX-Q=="
    private val manyAddressKeysAddressKeys = listOf(
        Keys(
            "i9DnLBbuJ8VfUf3ZG78KSz9vr8A6Tx--ylLAWOSvlvXskdW8deVC_UVA_Yvx6UZf5xv9vCRjfwNkq7JrJuiaYw==",
            """
                -----BEGIN PGP PRIVATE KEY BLOCK-----
                Version: ProtonMail

[encoded data, 4389 characters]
                a2j5Ak+MfeXknuaYqP6hs5BzulMTTJjM
                =4S1O
                -----END PGP PRIVATE KEY BLOCK-----
            """.trimIndent(),
            3,
            1,
            """
                -----BEGIN PGP MESSAGE-----
                Version: ProtonMail

                wcBMA/AwZ+kGahlZAQf/fkz6NVnIhvSFSMA5GpaakdUC57vCPZa3Zf0VLJZO
                j3Nh3Xn1kIvFDGe75H4HZsAGJFFGyFkjKIEoyR4bMOzK1M7vKilm6O47ydnS
                hGutVmAo7nHEdbgDjUEnwJnePwYK8IaTpPK7QjRxBAI553NQNLM9OJ+byluU
                /bR670tG4UJpMkA8eEvjpHS6+xLngq+HT3PM81QsKUwBmkRFVHyLqqd3y1yg
                GSTFedNqOZae7CXHlxJe88wU9n9egZPiIsbRErf4ZJWhVbPQQxYx4cavVa00
                QncdJ00QDWStjZFZucK8RZU3UPfhuV1W7FfIhtp/x/+hf7iIX1Y4eVZ9kjR0
                /tJ4ARMLQc/NBQdHCwmMHYGJZc9r85dX6YplrdaROlvc2f2oEKxUlH0MVQoO
                qpYay7uM+X1ywV1NJNlrZsSDwoeR+lGRidhq/Y4r6K2g/MJCJv2xSK+Lrp7m
                M8EKUXj+dFaq00ViLsBEYeqnRQRsg4GRjEI+luZOT4u0
                =Xd62
                -----END PGP MESSAGE-----
            """.trimIndent(),
            """
                -----BEGIN PGP SIGNATURE-----
                Version: ProtonMail

                wsBcBAEBCAAGBQJddheAAAoJEPiq8c68NCm8FN8IAKV+VmWYfkuiisCsWkrF
                VCU3sRxz//Gno6sZl01bOoJJ1rDbJH584nfVoLP2mmu12gcO6nKWVj7eAN0j
                FuKp9ZEB6XW4LdxVd1KAklTPYN+OePvbZBgXoH/OX4+VSadkBgZfPUeZ9oNU
                WcBjzYWEZNWNCxRlDOiaZX7q4mNMlnvhZF0zk3/6g88CKToXlhW7f4iJ36EX
                wYnWjwQGhsBEJ3BoYeYFW2M6mXlh6Fiembe9FZmORbhlCpJ0exPOC4rKg8EE
                7XKWrrAVncwhXb3IbBPwbsWVS5yBziaiw1Ozo6HyAzsBEskLRajBjZoByO8x
                TkchT8r9OTDm26fYGVdGiQg=
                =68Qs
                -----END PGP SIGNATURE-----
            """.trimIndent(),
            null,
            1
        ),
        Keys(
            "QtsLAEJcOo_jhThoFLMfCQrWme3lRiQ16TWHwE9O0Vr-4Qn-3xSWvHGzYesK72--nTwebC9ZK01RhMd16ymDFg==",
            """
                -----BEGIN PGP PRIVATE KEY BLOCK-----
                Version: ProtonMail

                xYYEXXYRuxYJKwYBBAHaRw8BAQdAtZY+Jb6pR3lMwGroH7k6/eG8UrOql+FV
                3pH1Bd/6xCf+CQMIE8QkUA7nY/xgLDtKTJ0J4wS3fgT5+0/ztay5u3PRJt5m
                TUVOZzhd8ReeDOu4xsP4exFGMy/CVu6A90cQthyaDxJGCMR5c7ySt/OwfU7k
                iM0vYXJvbjIyQHByb3Rvbm1haWwuYmx1ZSA8YXJvbjIyQHByb3Rvbm1haWwu
                Ymx1ZT7CdwQQFgoAHwUCXXYRuwYLCQcIAwIEFQgKAgMWAgECGQECGwMCHgEA
                CgkQgovwMGfg5xzb9AD/TQaYoyas7x0lbb/sX/AwWmPos4FOoj2Bu+IYcblr
                b/QA/2Fdbxgep0qSTfDWW2cJ465NLekrj/BSWuBkUmFc+AQLx4sEXXYRuxIK
                KwYBBAGXVQEFAQEHQMjPZ/LK0Vteukg6Ah0EyV4ClzjQBS7Bf/Ay0gbh8ONj
                AwEIB/4JAwhX9ycQRkdaqWC6Vtauscd8gYHgTdTosb6ANkVrrQd6w7s6u7BH
                Abe3NjrWcbQo+FkXbca9r/+YHqme7oSwF0Cp4QATmXEwAf8aIDvWkOTnwmEE
                GBYIAAkFAl12EbsCGwwACgkQgovwMGfg5xwhvQD+NvvdyEEY+4g1tkp2qC2y
                q0SamQiEOg6/yz5gzwPEatoBAOk+AJwP+1qdJncILj0KJ30KnfBHbEa86veO
                z7XCwucC
                =GzAB
                -----END PGP PRIVATE KEY BLOCK-----
            """.trimIndent(),
            1,
            0,
            """
                -----BEGIN PGP MESSAGE-----
                Version: ProtonMail

                wcBMA7M4YhTWmh7GAQgAi8nn7wQcb+bh0EZknNdPHMJ3D1QLijgTSv/WfD3p
                2k14RoJReYW7/gvPBUJQKC+unZGuUDrceSJsAZskBGTnJ2ZLNVkAjSljUl9l
                za+XYHKfJnhrVsF9E1edeh6KY32nd7F11UPcJ5/7ca1kZCNdUIaAoDTdPI7B
                wpC+g8A6vylVJ5P1gTKRPi+YR4inRPIxXz3f4nrdrZWO5ta4Yt8wSwgF8VRx
                KItqunhuphaR2E66aUftennIrj8SQRl+ExqDRRMOQGpwF53UnZBX+JvMjq64
                tFDoIheOolCCt6yUa85iLTuCiMLNms+Mz/T8FvrqUs4ousKawEi6cVYK5tca
                CdJ4AUa86f/szoTH+oWuFApaLzK5j8KYQF0Z7YB8P/TGkkGrtpbl6ldSCoc3
                UuFCTHEbf+n/AbErz2om6UojgPaP7ezzpOZdCCWI1GG5o8iQodrUstbe1SMR
                ++kf6m7JU1dU/1tC1PjOxUoo7b4DNB1PGBLmH1uoSJlM
                =pcs5
                -----END PGP MESSAGE-----
            """.trimIndent(),
            """
                -----BEGIN PGP SIGNATURE-----
                Version: ProtonMail

                wsBcBAEBCAAGBQJddhY6AAoJEFW4yVpiddmBBDYH+wW9RXwIqtwFo1mE5T+z
                Wq7rxWJKu7qqeSTWmgMjhBEjrLlvD2CzIH4LZw5O+y9iVye6/4bsBMWjHgGX
                Rb59zR5nncqIDyKQu9sbIJYzLyl9nTnes/MgUfLwhHgJ3BDRKlg8qnxepBnr
                i6cin+Z81kmaQccHFSxabpA7g6KCdFOUKoq9eyvaKZIWQ3lgaMqSpJO0/3WA
                qP4/vPwgbVsPR5X8cxnP5fkW81l2Stz+fQKdznTM1CG1ImfuWKXxq8huXsYY
                wKUdbdKzG14vsCrZY/UUNq/o9515aRojjV2KgZByq4KICra6jPxkAnvz8jRx
                ulskRhRJqufYuGUUBmK8fx8=
                =4SVY
                -----END PGP SIGNATURE-----
            """.trimIndent(),
            null,
            1
        ),
        Keys(
            "Kufr0UxSSqOB6975FEPC17yNhhq6FyE_Jc18-O_Q3w7bB3yWgC-hgJrxRF2iJxfqTDAwMjtvv8_roYJhDpv8Pg==",
            """
                -----BEGIN PGP PRIVATE KEY BLOCK-----
                Version: ProtonMail

[encoded data, 4389 characters]
                PG6pu/4dcMT67x9K7G/QEgP/AD+jTSMS
                =N8jj
                -----END PGP PRIVATE KEY BLOCK-----
            """.trimIndent(),
            1,
            0,
            """
                -----BEGIN PGP MESSAGE-----
                Version: ProtonMail

                wcBMA7M4YhTWmh7GAQf+NpXNbsOlshLPYAbyuRYKaOfCz8m6kMirO29XPXcj
                1c9a1ruZTC8N3y3IVbhmCRQp5ykSDmv+yUGCbSt45G5IgIeOTFJLdfD19QHr
                dpnhmlziohqmCciLkbwRQwXbfLP4rr5n1RDIOf8ZiIKGNWrRJ2CIExhW9dM0
                Rc2Ijiw3i76DyPpfELTjYxOB5IR9MhDGt9UHyJr60N47RoQQiibfwu6qWq9V
                1xN7Kl+Kl5DRQFrYWnPsXYRKNHGgWZFiDRaMvzLjQLDsWeDn2+bUIwxVzoM3
                N53MYkkDMKOsHr/RUCuCuGVGP4kRcYMH0MEvwCixhyr6GZvCyIiEtOFMj0TS
                Z9J4AZ8FMkHaF5wzmlURQn4+NP/XmFjqDDcPgjrTTcIU0VloWd/Rcrxtay54
                2lHK/zrzMYkrRG7jgZvCzBoqzCjMEVbNPv3qfmz45DN5m+OfpNkN7WbYFaqH
                sPBRgjr9+HxsyqPu3/wdawgLlI0c5lBrhivNojZBtACj
                =77u7
                -----END PGP MESSAGE-----
            """.trimIndent(),
            """
                -----BEGIN PGP SIGNATURE-----
                Version: ProtonMail

                wsBcBAEBCAAGBQJddhY5AAoJEFW4yVpiddmBjI4H+gImMlzpBRCRnDaAYWtm
                Io59SeLCUYC9ML2oqIuwcM1yIfvBhpdmxNuDGAmGqazJAzLUpeiV7iz2ymdM
                Mk9NxHngP2dkT31q8ZdV7rvGItAVV2lgpLFHcgWPMkdCo7a3jgbbo4qbgc4p
                Z2+2KwHOo5NIrrjgZHRoRWrx7p96OjqWZ38buvUQXl+bjhDLh0GBYRGRY0fM
                dV4FK/W1cu//cwBgjKAOmLhxKNMigSxDJMY33DTPOhaiviqpKVx/3qw6EUgt
                nqLuiSwSM4oUQzQnbDluDVVI68E0JlxJC8KerJWP8aeq3LvyrJgbNLSSWBju
                LgA1n0GjKKT+n1fJR2/DfUg=
                =yh1P
                -----END PGP SIGNATURE-----
            """.trimIndent(),
            null,
            1
        ),
        Keys(
            "v3foSmcRMfxukR9VdZH-ql-sm4lFfAkHYbgsCzUbSrHQD-49BkEQVlmgkWk1u8oxMkceVW5Loaxwma3RSFTK8w==",
            """
                -----BEGIN PGP PRIVATE KEY BLOCK-----
                Version: ProtonMail

[encoded data, 4389 characters]
                b5BlAx31rUZ+NdCZyPnU+83opOdYrRjy
                =4Q+q
                -----END PGP PRIVATE KEY BLOCK-----
            """.trimIndent(),
            1,
            0,
            """
                -----BEGIN PGP MESSAGE-----
                Version: ProtonMail

                wcBMA7M4YhTWmh7GAQgAwb04y2B+brcyyIrknDy23xQPN8sOyXhUjSOkD4b+
                oS9MrA5jJoh4roeicDGAmfs8YFWBhr/raLG6t2iesxqSZ8zpf52u05DTeJy8
                8nRd+1ACh6hEMYPrMzQeHC+joDjYxRtuOh/kDetQlO/RVVrOmLAlCCxXE+eR
                unr5G7029u7VhaCV7tg1t/b+wYfu8wiQCmZBvDXZVjlHvcCSGWCDdtHYk6sV
                q/rQvnSJgqC+6ilJkk1ujHkaP4Xt4CSHSDOmzHPuYs2rLVLum8U8EEpZVRVe
                plt6P6smMIm6dgfBUhVrJUKYCCn/HVH1aN19saBUVpOJ4MZFJhfxynEgcstT
                ddJ4AYZxxOU2VgdwDePMqYXtDTlL7xi46LW8fJvUitAv6BWpLJhhUR6HsjG7
                oJj0VjFCreBFHXniBPyFCaivX28U+PFgSduHfq+8W5dIn94E3/Bx6Xck/wcp
                y/iDQpC6sVUOvsGeuErACZPuqF6sOzIL+Bva91qhoMDO
                =5QCS
                -----END PGP MESSAGE-----
            """.trimIndent(),
            """
                -----BEGIN PGP SIGNATURE-----
                Version: ProtonMail

                wsBcBAEBCAAGBQJddhY4AAoJEFW4yVpiddmBB1AH/j7O0LnFxKSpPLj2s0Cl
                btmfj1MljLpAu303VxL6pFNxdlTQ0ehrt8Ff76aE8YRXU33zukm8mcHOM31e
                tjrfJhib011TcxACgkKtgs0WPpERhtyxhGpAGcIXzuEdyHIDnBfvbU4sls6j
                4KYNDFBcN3vCk2DiWRRVJlXnF88cffWNq31fpkkfWAaGl5ePFqnEz54mzxm0
                /MlZ+i9LP6bBBpnF6QBAO8DWYnGl3IVT9qjR0Crzp7T1obRbO32gorhU/ifA
                YGyKRSN6axG+6+01a523I+0qnCmhI4bFiGvE7f3BJucB/QZI4wuWLMhAqxGW
                IKS2Qorq1xywg/8FbDNG7GQ=
                =Jrx1
                -----END PGP SIGNATURE-----
            """.trimIndent(),
            null,
            1
        )
    )
    private val manyAddressKeysUserKeys = listOf(
        Keys(
            "IB2lsghg5bLlCJkSu7eNPq-PD7Ae9ZXn_yy52sObxxF1NzlM8iuVY-oFvfFFxE4egvWMqse402s_ERB9SbM7HQ==",
            """
                    -----BEGIN PGP PRIVATE KEY BLOCK-----
                    Version: ProtonMail

[encoded data, 4617 characters]
                    a2j5Ak+MfeXknuaYqP6hs5BzulMTTJjM
                    =sm1p
                    -----END PGP PRIVATE KEY BLOCK-----
            """.trimIndent(),
            0,
            1,
            null,
            null,
            null,
            1
        ),
        Keys(
            "XFEG7ogZjpsk23o8AIPlzKZiqLnLlATQmbIJzt-RubRpwhNd6F2I29OSJWqwKiq73IQfctWOn9mgJ8J3Av4Xew==",
            """
                    -----BEGIN PGP PRIVATE KEY BLOCK-----
                    Version: ProtonMail

[encoded data, 4617 characters]
                    b5BlAx31rUZ+NdCZyPnU+83opOdYrRjy
                    =kArG
                    -----END PGP PRIVATE KEY BLOCK-----
            """.trimIndent(),
            0,
            0,
            null,
            null,
            null,
            1
        )
    )
    //endregion

    //region Token and Signature generation
    private val tokenAndSignatureUserId = UserId("token_and_sign")
    private val passphrase = EncryptedByteArray("7NgO4d0h72zt4XuFLOUbg352vhrn.tu".toByteArray())
    private val randomTokenString = "9efb6173a8da137e7ead1a9d2b6ada0f707a19156dee0c84899761fee73e556a"
    private val randomToken =
        randomTokenString.chunked(2).map {
            it.toInt(16).toByte()
        }.toByteArray()
    //endregion

    private val addressKeyMapper = AddressKeyBridgeMapper()
    private val userKeyMapper = UserKeyBridgeMapper()

    private val oneKeyUserMock: ch.protonmail.android.domain.entity.user.User = mockk {
        every { addresses } returns mockk {
            every { findBy(AddressId(oneAddressKeyAddressId)) } answers { addresses[1] }
            every { addresses } returns mapOf(
                1 to mockk {
                    every { keys } returns mockk {
                        every { keys } returns oneAddressKeyAddressKeys.map(addressKeyMapper) { it.toNewModel() }
                        every { primaryKey } returns keys.first()
                    }
                }
            )
        }
        every { keys } returns mockk {
            every { keys } returns oneAddressKeyUserKeys.map(userKeyMapper) { it.toNewModel() }
            every { primaryKey } returns keys.first()
        }
    }

    private val manyAddressKeysUserMock: ch.protonmail.android.domain.entity.user.User = mockk {
        every { addresses } returns mockk {
            every { findBy(AddressId(manyAddressKeysAddressId)) } answers { addresses[1] }
            every { addresses } returns mapOf(
                1 to mockk {
                    every { keys } returns mockk {
                        every { keys } returns manyAddressKeysAddressKeys.map(addressKeyMapper) { it.toNewModel() }
                        every { primaryKey } returns keys.first()
                    }
                }
            )
        }
        every { keys } returns mockk {
            every { keys } returns manyAddressKeysUserKeys.map(userKeyMapper) { it.toNewModel() }
            every { primaryKey } returns keys.first()
        }
    }

    init {
        mockkStatic(TextUtils::class)

        every { oneAddressKeyUserManagerMock.openPgp } returns openPgp
        every { oneAddressKeyUserManagerMock.keyStoreCrypto } returns keyStoreCrypto
        every { manyAddressKeysUserManagerMock.openPgp } returns openPgp
        every { manyAddressKeysUserManagerMock.keyStoreCrypto } returns keyStoreCrypto

        // one address key
        /*
        every { oneKeyUserMock.keys } returns oneAddressKeyUserKeys
        every { oneKeyUserMock.getAddressById(oneAddressKeyAddressId) } returns mockk {
            every { keys } returns oneAddressKeyAddressKeys
        }*/
        every { oneAddressKeyUserManagerMock.getUserBlocking(oneAddressKeyUserId) } returns oneKeyUserMock
        every {
            oneAddressKeyUserManagerMock.getUserPassphraseBlocking(
                oneAddressKeyUserId
            )
        } returns EncryptedByteArray(oneAddressKeyMailboxPassword.toByteArray())

        // many address keys
        /*
        every { manyAddressKeysUserMock.keys } returns manyAddressKeysUserKeys
        every { manyAddressKeysUserMock.getAddressById(manyAddressKeysAddressId) } returns mockk {
            every { keys } returns manyAddressKeysAddressKeys
        }*/
        every { manyAddressKeysUserManagerMock.getUserBlocking(manyAddressKeysUserId) } returns manyAddressKeysUserMock
        every {
            manyAddressKeysUserManagerMock.getUserPassphraseBlocking(
                manyAddressKeysUserId
            )
        } returns EncryptedByteArray(manyAddressKeysMailboxPassword.toByteArray())

        // token and signature generation
        every { oneAddressKeyUserManagerMock.currentUserId } returns tokenAndSignatureUserId
        every { oneAddressKeyUserManagerMock.requireCurrentUserId() } returns tokenAndSignatureUserId
        every { oneAddressKeyUserManagerMock.getUserPassphraseBlocking(tokenAndSignatureUserId) } returns passphrase
        every { openPgpMock.randomToken() } returns randomToken


        // token and signature generation
        every { manyAddressKeysUserManagerMock.currentUser } returns manyAddressKeysUserMock
        every { manyAddressKeysUserManagerMock.currentUserId } returns tokenAndSignatureUserId
        every { manyAddressKeysUserManagerMock.requireCurrentUserId() } returns tokenAndSignatureUserId
        every { manyAddressKeysUserManagerMock.getUserPassphraseBlocking(tokenAndSignatureUserId) } returns passphrase
    }

    @Test
    fun get_key_fingerprint() {
        assertEquals(
            oneAddressKeyUserKeyFingerprint,
            openPgp.getFingerprint(oneAddressKeyAddressKeys.first().privateKey)
        )
    }

    @Test
    fun encrypt_and_decrypt_message() {
        val message = "Text to encrypt and decrypt."

        val userCrypto = Crypto.forUser(oneAddressKeyUserManagerMock, oneAddressKeyUserId)
        val encrypted = userCrypto.encrypt(message, false)
        val decrypted = userCrypto.decrypt(encrypted)

        // TODO this assert fails because we probably incorrectly handle SignatureVerificationError
        //  in TextDecryptionResult(hasSignature), or Helper.decryptExplicitVerify returns incorrect
        //  value, 2 instead of 1 when there is no signature
        // assertFalse(decrypted.hasSignature())
        assertFalse(decrypted.isSignatureValid)
        assertEquals(message, decrypted.decryptedData)
    }

    @Test
    fun encrypt_and_decrypt_signed_message() {
        val message = "Text to encrypt and decrypt, signed."

        val userCrypto = Crypto.forUser(oneAddressKeyUserManagerMock, oneAddressKeyUserId)
        val encryptedAndSigned = userCrypto.encrypt(message, true)
        val decrypted = userCrypto.decrypt(encryptedAndSigned)

        assert(decrypted.hasSignature())
        assert(decrypted.isSignatureValid)
        assertEquals(message, decrypted.decryptedData)
    }

    @Test
    fun decrypt_pgp_mime_message_body_only() {
        val encryptedMessage = """
            -----BEGIN PGP MESSAGE-----
            Version: ProtonMail

            wcBMA5kajsUECZmgAQf/ZPNo2ycCcSfoHJpRvHBpaxDOhj+pJmynsIwptekE
            ygoiPTUhLRtVCGSoAZOBzWYGU2wxWUAUZupJx3enkY9GGUTNFYxNgoWIjSqZ
            G0BmASdgQBLGfINjNACdafiFtm1to2z4s41Vwv9ENBornkABzR7VqbrSe5EY
            fef+ZwtXDzg5lyO6G4HqOMHmrX+H8gbDKslS3OgHk66+e58HsWPRDK9DvUfz
            YqGAybRZpMwAs0UXhr9MXrnUBzzd010NGo58iWugt4zggyO/xfiMaC4cXLrm
            2LmGlTQrJ8+gNUSTPcOqpDtovS/Ve0LbFAcXjLMZsxyTx5UwQSFTgDZiaQwz
            gcHBTANv03LIBj82fgEQAIC2NiDaRLanLPwlDZx12YbrgDKcjywDWTdJDg3X
            ABmKK2RlnMpK8xV3ffRN+MHQv6o1a1kz8U+l5PZx1NxFwEUPEFzCgU43hg/t
            qgWkZDs20BfPEv84uwnxB0UKvN0BqUorCRfIqrGmcAgj/9ZcbQqp9xUGk3Wo
            rM3CbgCDjkL6uu9USpPdiT+sVx/I4BatZQFBBGUn6IBkTGA4jivBmlCOyoed
            q0IKXLL/HhcdaiicY3EgVkSVOmzv4Qvl5rS2NhqUuuzhm7J/Q0pBTjD09MuB
            ypFpxZ3SChTdCvYrSzXSdTHV0A3WzmjcWAPxFBQeu6EyAKDFY8xlbIGmJcuw
            x1xd36IZ3Lz9wvHjVkK6AGUwLX4Gbr4LqI+cv0737Kylsn8nZqNYzYyu1pIJ
            SRtOigIERnQQ7tJUdB9MPCQYV1HNoqtERyIsWsYxHxxIBjyh08574IbRFov0
            SYvBGyeiWuUbxIWIYKNRloezrr1VdO3Ir2NXpOQcg9X5bLmFcyWLb+HkmP0L
            IoqPip2oj8p9bK3W5eugGpuB0Wg4rtLMC/y4uGagZWQEuIfDwbaU1DJY53Gd
            gLOrrwugxokWpff46nsJm7fDuKtS9JRRSrIf0kEK9U9r2PiZJ5EZGk6Xlfls
            rf+/B//B6CraAxchCuBKZWfiSkwzlp5JLNCHoJ9ClfiQ0sDMAUuVdfoLxykG
            pEgYd7WZWhL/HWqL6wnJwIgLWc0KNlNfLTe3xDzsrH40TrggeLkhxt5SMt+/
            Z1qHe1I2ySAG71T+h9nXQvf59/TCJCrYeovONMytFWWM86IAlWdaGUf3UgQJ
            2nbRBA1mjdlDXLASnR026jQZCGLvwI/AtEtwf/rFZCr+9BHRp3xqL/7N5eAM
            rQkeVtR4GHQ/5b2k/nAgikHSwPZVq3rWW7zq6LZov5o+bWrpkTC/jADoPJhS
            17culs74jO0+uJIDvrXjs15/2wy8gCorjP1+uVo9jSwEl7R0YXe3N1Dk3GLJ
            qfXCH7M6YagGA+QrKPGVbf+u9mzW8Xa0a0LkiztOQAjVeIATQchc2CULuDaQ
            3GQI5plpG+UXk56hKaHaWqOW4DFUwqytfpUouqC8HYtkNK/U/qof7W7XyK0a
            IQDm/u9BGpUTGi0RRIKw3MceOaqhx4CsVY+4KI8TZxTBUgz0FEolsSGc3n4z
            b84EjTEttONJFdRubt7KSWkoibrlQ7BBLfkd
            =47eC
            -----END PGP MESSAGE-----
        """.trimIndent()

        val expected = "Test PGP/MIME Message\r\n\r\n\r\n"

        val addressCrypto = Crypto.forAddress(
            oneAddressKeyUserManagerMock,
            oneAddressKeyUserId,
            AddressId(oneAddressKeyAddressId)
        )

        var errorCallbackCalled = false
        lateinit var resultBody: String

        addressCrypto.decryptMime(
            message = CipherText(encryptedMessage),
            onBody = { eventBody: String, _ ->
                resultBody = eventBody
            },
            onError = { errorCallbackCalled = true },
            onVerified = { _, _ -> },
            onAttachment = { _, _ -> },
            keys = listOf(),
            time = 0
        )

        assertEquals(expected, resultBody)
        assertFalse(errorCallbackCalled)
    }

    @Test
    fun call_error_callback_when_none_of_the_address_keys_works() {
        val encryptedMessage = """
            -----BEGIN PGP MESSAGE-----
            Version: ProtonMail

            wcBMA5kajsUECZmgAQf/ZPNo2ycCcSfoHJpRvHBpaxDOhj+pJmynsIwptekE
            ygoiPTUhLRtVCGSoAZOBzWYGU2wxWUAUZupJx3enkY9GGUTNFYxNgoWIjSqZ
            G0BmASdgQBLGfINjNACdafiFtm1to2z4s41Vwv9ENBornkABzR7VqbrSe5EY
            fef+ZwtXDzg5lyO6G4HqOMHmrX+H8gbDKslS3OgHk66+e58HsWPRDK9DvUfz
            YqGAybRZpMwAs0UXhr9MXrnUBzzd010NGo58iWugt4zggyO/xfiMaC4cXLrm
            2LmGlTQrJ8+gNUSTPcOqpDtovS/Ve0LbFAcXjLMZsxyTx5UwQSFTgDZiaQwz
            gcHBTANv03LIBj82fgEQAIC2NiDaRLanLPwlDZx12YbrgDKcjywDWTdJDg3X
            ABmKK2RlnMpK8xV3ffRN+MHQv6o1a1kz8U+l5PZx1NxFwEUPEFzCgU43hg/t
            qgWkZDs20BfPEv84uwnxB0UKvN0BqUorCRfIqrGmcAgj/9ZcbQqp9xUGk3Wo
            rM3CbgCDjkL6uu9USpPdiT+sVx/I4BatZQFBBGUn6IBkTGA4jivBmlCOyoed
            q0IKXLL/HhcdaiicY3EgVkSVOmzv4Qvl5rS2NhqUuuzhm7J/Q0pBTjD09MuB
            ypFpxZ3SChTdCvYrSzXSdTHV0A3WzmjcWAPxFBQeu6EyAKDFY8xlbIGmJcuw
            x1xd36IZ3Lz9wvHjVkK6AGUwLX4Gbr4LqI+cv0737Kylsn8nZqNYzYyu1pIJ
            SRtOigIERnQQ7tJUdB9MPCQYV1HNoqtERyIsWsYxHxxIBjyh08574IbRFov0
            SYvBGyeiWuUbxIWIYKNRloezrr1VdO3Ir2NXpOQcg9X5bLmFcyWLb+HkmP0L
            IoqPip2oj8p9bK3W5eugGpuB0Wg4rtLMC/y4uGagZWQEuIfDwbaU1DJY53Gd
            gLOrrwugxokWpff46nsJm7fDuKtS9JRRSrIf0kEK9U9r2PiZJ5EZGk6Xlfls
            rf+/B//B6CraAxchCuBKZWfiSkwzlp5JLNCHoJ9ClfiQ0sDMAUuVdfoLxykG
            pEgYd7WZWhL/HWqL6wnJwIgLWc0KNlNfLTe3xDzsrH40TrggeLkhxt5SMt+/
            Z1qHe1I2ySAG71T+h9nXQvf59/TCJCrYeovONMytFWWM86IAlWdaGUf3UgQJ
            2nbRBA1mjdlDXLASnR026jQZCGLvwI/AtEtwf/rFZCr+9BHRp3xqL/7N5eAM
            rQkeVtR4GHQ/5b2k/nAgikHSwPZVq3rWW7zq6LZov5o+bWrpkTC/jADoPJhS
            17culs74jO0+uJIDvrXjs15/2wy8gCorjP1+uVo9jSwEl7R0YXe3N1Dk3GLJ
            qfXCH7M6YagGA+QrKPGVbf+u9mzW8Xa0a0LkiztOQAjVeIATQchc2CULuDaQ
            3GQI5plpG+UXk56hKaHaWqOW4DFUwqytfpUouqC8HYtkNK/U/qof7W7XyK0a
            IQDm/u9BGpUTGi0RRIKw3MceOaqhx4CsVY+4KI8TZxTBUgz0FEolsSGc3n4z
            b84EjTEttONJFdRubt7KSWkoibrlQ7BBLfkd
            =47eC
            -----END PGP MESSAGE-----
        """.trimIndent()

        val addressCrypto = Crypto.forAddress(
            manyAddressKeysUserManagerMock,
            manyAddressKeysUserId,
            AddressId(manyAddressKeysAddressId)
        )
        var errorCallbackCalled = false
        var onBodyCallbackCalled = false

        addressCrypto.decryptMime(
            message = CipherText(encryptedMessage),
            onBody = { _, _ -> onBodyCallbackCalled = true },
            onError = { errorCallbackCalled = true },
            onVerified = { _, _ -> },
            onAttachment = { _, _ -> },
            keys = listOf(),
            time = 0
        )

        assertTrue(errorCallbackCalled)
        assertFalse(onBodyCallbackCalled)
    }

    @Test
    fun decrypt_pgp_mime_message_with_attachments() {
        //region Encrypted Message
        val encryptedMessage = """
            -----BEGIN PGP MESSAGE-----
            Version: ProtonMail

[encoded data, 49348 characters]
            OAUBTdhDjCoqYxx48+D3+Q==
            =X3FI
            -----END PGP MESSAGE-----
        """.trimIndent()
        //endregion

        val expectedBody = "Test PGP/MIME Message with attachment\r\n\r\n\r\n"

        val mockedMessageId = "0-KKFldtlrtWQRGmOQR1V4QVsnqq7nuHw_nkmdDAd2xtIvibEqnV0IYVS3FfX-RT8BruIrL35HQ35rQkP6VbBg=="
        val mockedAttachments = listOf<Attachment>(
            mockk {
                every { attachmentId } returns "PGPAttachment/0-KKFldtlrtWQRGmOQR1V4QVsnqq7nuHw_nkmdDAd2xtIvibEqnV0IYVS3FfX-RT8BruIrL35HQ35rQkP6VbBg==/dbfcdb13e07ef2fcf26249fec3a4bae2/0"
                every { fileName } returns "default"
                every { mimeType } returns "text/rfc822-headers; protected-headers=\"v1\""
                every { fileSize } returns 48
                every { messageId } returns mockedMessageId
                // every { headers } returns
            },
            mockk {
                every { attachmentId } returns "PGPAttachment/0-KKFldtlrtWQRGmOQR1V4QVsnqq7nuHw_nkmdDAd2xtIvibEqnV0IYVS3FfX-RT8BruIrL35HQ35rQkP6VbBg==/778b4f3c8e74a652aefbee588e67421a/1"
                every { fileName } returns "elon.jpg"
                every { mimeType } returns "image/jpeg; name=\"elon.jpg\""
                every { fileSize } returns 27723
                every { messageId } returns mockedMessageId
                // every { headers } returns
            }
        )

        lateinit var resultBody: String
        var errorCallbackCalled = false
        val attachments = mutableListOf<Attachment>()
        val addressCrypto =
            Crypto.forAddress(oneAddressKeyUserManagerMock, oneAddressKeyUserId, AddressId(oneAddressKeyAddressId))

        addressCrypto.decryptMime(
            message = CipherText(encryptedMessage),
            onBody = { eventBody: String, _ ->
                resultBody = eventBody
            },
            onAttachment = { headers: InternetHeaders, content: ByteArray ->
                attachments.add(Attachment.fromMimeAttachment(content, headers, mockedMessageId, attachments.size))
            },
            onError = { errorCallbackCalled = true },
            onVerified = { _, _ -> },
            keys = emptyList(),
            time = 0
        )

        attachments.forEachIndexed { i, attachment ->
            val expected = mockedAttachments[i]
            assertEquals(expected.attachmentId, attachment.attachmentId)
            assertEquals(expected.fileName, attachment.fileName)
            assertEquals(expected.mimeType, attachment.mimeType)
            assertEquals(expected.fileSize, attachment.fileSize)
            assertEquals(expected.messageId, attachment.messageId)
            assert(attachment.isPGPAttachment)
        }

        assertEquals(expectedBody, resultBody)
        assertEquals(attachments.size, mockedAttachments.size)
        assertFalse(errorCallbackCalled)
    }

    @Test
    fun check_key_passphrase() {
        assertTrue(
            openPgp.checkPassphrase(oneAddressKeyAddressKeys[0].privateKey, oneAddressKeyMailboxPassword.toByteArray())
        )
        assertFalse(
            openPgp.checkPassphrase(oneAddressKeyAddressKeys[0].privateKey, "incorrect key password".toByteArray())
        )
    }

}
