package ch.threema.domain.protocol.csp.messages

import ch.threema.base.utils.getThreemaLogger
import ch.threema.domain.models.GroupId
import ch.threema.domain.protocol.csp.ProtocolDefines
import ch.threema.domain.types.IdentityString
import ch.threema.protobuf.csp.e2e.fs.Version
import ch.threema.protobuf.d2d.IncomingMessage
import ch.threema.protobuf.d2d.OutgoingMessage
import ch.threema.protobuf.d2d.conversationOrNull
import ch.threema.protobuf.d2d.groupOrNull
import java.io.ByteArrayOutputStream

private val logger = getThreemaLogger("GroupSyncRequestMessage")

/**
 * Request current group information to be sent back.
 */
class GroupSyncRequestMessage : AbstractGroupMessage() {
    override fun getMinimumRequiredForwardSecurityVersion(): Version = Version.V1_2

    override fun allowUserProfileDistribution(): Boolean = false

    override fun exemptFromBlocking(): Boolean = true

    override fun createImplicitlyDirectContact(): Boolean = false

    override fun protectAgainstReplay(): Boolean = true

    override fun reflectIncoming(): Boolean = true

    override fun reflectOutgoing(): Boolean = true

    override fun reflectSentUpdate(): Boolean = false

    override fun sendAutomaticDeliveryReceipt(): Boolean = false

    override fun bumpLastUpdate(): Boolean = false

    override fun getType(): Int = ProtocolDefines.MSGTYPE_GROUP_REQUEST_SYNC

    override fun getBody(): ByteArray? {
        try {
            val bos = ByteArrayOutputStream()
            bos.write(apiGroupId.groupId)
            return bos.toByteArray()
        } catch (e: Exception) {
            logger.error(e.message)
            return null
        }
    }

    companion object {
        @JvmStatic
        @Throws(BadMessageException::class)
        fun fromReflected(
            message: IncomingMessage,
            myIdentity: IdentityString,
        ): GroupSyncRequestMessage {
            val groupSyncRequestMessage = fromByteArray(message.body.toByteArray(), myIdentity)
            groupSyncRequestMessage.initializeCommonProperties(message)
            return groupSyncRequestMessage
        }

        @JvmStatic
        @Throws(BadMessageException::class)
        fun fromReflected(message: OutgoingMessage): GroupSyncRequestMessage {
            val creatorIdentity = message.conversationOrNull?.groupOrNull?.creatorIdentity
                ?: throw BadMessageException("Group conversation is not set on group-sync-request message")
            val groupSyncRequestMessage = fromByteArray(message.body.toByteArray(), creatorIdentity)
            groupSyncRequestMessage.initializeCommonProperties(message)
            return groupSyncRequestMessage
        }

        @JvmStatic
        @Throws(BadMessageException::class)
        fun fromByteArray(data: ByteArray, creatorIdentity: IdentityString): GroupSyncRequestMessage =
            fromByteArray(
                data = data,
                offset = 0,
                length = data.size,
                creatorIdentity = creatorIdentity,
            )

        @JvmStatic
        @Throws(BadMessageException::class)
        fun fromByteArray(
            data: ByteArray,
            offset: Int,
            length: Int,
            creatorIdentity: IdentityString,
        ): GroupSyncRequestMessage {
            when {
                length != ProtocolDefines.GROUP_ID_LEN -> throw BadMessageException("Bad length ($length) for group-sync-request message")
                offset < 0 -> throw BadMessageException("Bad offset ($offset) for group-sync-request message")
                data.size < length + offset -> throw BadMessageException(
                    "Invalid byte array length (${data.size}) for offset $offset and length $length",
                )
            }

            return GroupSyncRequestMessage().apply {
                groupCreator = creatorIdentity
                apiGroupId = GroupId(data, offset)
            }
        }
    }
}
