package ch.threema.data.storage

import ch.threema.data.datatypes.AvailabilityStatus
import ch.threema.data.datatypes.ConversationVisibility
import ch.threema.domain.models.AcquaintanceLevel
import ch.threema.domain.models.ContactSyncState
import ch.threema.domain.models.IdentityState
import ch.threema.domain.models.IdentityType
import ch.threema.domain.models.ReadReceiptPolicy
import ch.threema.domain.models.TypingIndicatorPolicy
import ch.threema.domain.models.UserState
import ch.threema.domain.models.VerificationLevel
import ch.threema.domain.models.WorkVerificationLevel
import ch.threema.domain.types.IdentityString
import java.time.Instant

// This file contains the types used in the database abstraction layer.

// TODO(ANDR-2998): Notification sound policy override
data class DbContact(
    /** The contact identity string. Must be 8 characters long. */
    val identity: IdentityString,
    /** The 32-byte public key of the contact. */
    val publicKey: ByteArray,
    /** Timestamp when this contact was added to the contact list. */
    val createdAt: Instant,
    /** Timestamp when this contact was last updated. Also known as _last update flag_. */
    val lastUpdateAt: Instant?,
    /** First name. */
    val firstName: String,
    /** Last name. */
    val lastName: String,
    /** Public nickname. */
    val nickname: String?,
    /** Color index. */
    val colorIndex: Int,
    /** Verification level. */
    val verificationLevel: VerificationLevel,
    /** Threema Work verification level. */
    val workVerificationLevel: WorkVerificationLevel,
    /** Identity type (regular / work). */
    val identityType: IdentityType,
    /** Acquaintance level (direct / group_or_deleted). */
    val acquaintanceLevel: AcquaintanceLevel,
    /** Activity state (active / inactive / invalid). */
    val activityState: IdentityState,
    /** Contact sync state. */
    val syncState: ContactSyncState,
    /** Feature mask. */
    val featureMask: ULong,
    /** Read receipt policy. */
    val readReceiptPolicy: ReadReceiptPolicy,
    /** Typing indicator policy. */
    val typingIndicatorPolicy: TypingIndicatorPolicy,
    /** The conversation visibility of the 1:1 chat with this contact. */
    val conversationVisibility: ConversationVisibility,
    /** Android contact lookup key. */
    val androidContactLookupKey: String?,
    /** Local avatar expiration date. */
    val localAvatarExpires: Instant?,
    /** Whether this contact has been restored from backup. */
    val isRestored: Boolean,
    /** BlobId of the latest profile picture that was sent to this contact. */
    val profilePictureBlobId: ByteArray?,
    val jobTitle: String?,
    val department: String?,
    val notificationTriggerPolicyOverridePolicy: Int?,
    val notificationTriggerPolicyOverrideExpiresAt: Instant?,
    /**
     *  In work builds, work contacts can have an optional [AvailabilityStatus.Set].
     *  On database an explicit value of [AvailabilityStatus.None] is never stored.
     *
     *  This value is joined in from a separate database table ([DbAvailabilityStatus.TABLE]).
     */
    val availabilityStatusSet: AvailabilityStatus.Set?,
    val workLastFullSyncAt: Instant?,
)

data class DbGroup(
    /** The group creator identity string. Must be 8 characters long. */
    val creatorIdentity: IdentityString,
    /**
     * The group id of the group. It is the hex string representation of the group id as little
     * endian byte array.
     */
    val groupId: String,
    /** The group name. */
    val name: String?,
    /** The creation date. */
    val createdAt: Instant,
    /** Currently not used. Might be used for periodic group sync. TODO(SE-146) */
    val synchronizedAt: Instant?,
    /** Last update flag. */
    val lastUpdate: Instant?,
    /** The conversation visibility of this group chat. */
    val conversationVisibility: ConversationVisibility,
    /** The color index. */
    val colorIndex: Int,
    /** The group description. */
    val groupDescription: String?,
    /** The group description changed timestamp. */
    val groupDescriptionChangedAt: Instant?,
    /** The group members' identities. */
    val members: Set<String>,
    /** The group user state. */
    val userState: UserState,
    val notificationTriggerPolicyOverridePolicy: Int?,
    val notificationTriggerPolicyOverrideExpiresAt: Instant?,
)

data class DbEditHistoryEntry(
    /** The unique id used as primary key. */
    val uid: Int = 0,
    /** The uid of the edited message referencing the [ch.threema.storage.models.AbstractMessageModel.COLUMN_UID] */
    val messageUid: String,
    /** The id of the edited message referencing the [ch.threema.storage.models.AbstractMessageModel.COLUMN_ID]
     *  Can be identical for different classes of messages that are stored in different tables
     *  This is only used as foreign key because uid is not actually constrained as unique
     */
    val messageId: Int,
    /** The former text of the edited message. */
    val text: String?,
    /** Timestamp when the message was edited and hence the entry created. */
    val editedAt: Instant,
) {
    companion object {
        const val COLUMN_UID = "uid"
        const val COLUMN_MESSAGE_UID = "messageUid"
        const val COLUMN_MESSAGE_ID = "messageId"
        const val COLUMN_TEXT = "text"
        const val COLUMN_EDITED_AT = "editedAt"
    }
}

data class DbEmojiReaction(
    /** The row id of the message this reaction refers to - see [ch.threema.storage.models.AbstractMessageModel.COLUMN_ID] */
    val messageId: Int,
    /** The identity of the person who reacted. This may differ from the sender of the message */
    val senderIdentity: IdentityString,
    /** The emoji codepoint sequence of the reaction. This can never be empty */
    val emojiSequence: String,
    /** Timestamp when the reaction was locally created. */
    val reactedAt: Instant,
) {
    companion object {
        const val COLUMN_MESSAGE_ID = "messageId"
        const val COLUMN_SENDER_IDENTITY = "senderIdentity"
        const val COLUMN_EMOJI_SEQUENCE = "emojiSequence"
        const val COLUMN_REACTED_AT = "reactedAt"
    }
}
