package com.seven.ikar.kotlin.core.model

import kotlinx.serialization.KSerializer
import kotlinx.serialization.Serializable
import kotlinx.serialization.descriptors.PrimitiveKind
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder

@Serializable(with = ChatTypeSerializer::class)
enum class ChatType(val wireValue: Int) {
    Direct(1),
    Group(2),
    Channel(3);

    companion object {
        fun fromWireValue(value: Int): ChatType = entries.firstOrNull { it.wireValue == value } ?: Direct
    }
}

@Serializable(with = ChatMemberRoleSerializer::class)
enum class ChatMemberRole(val wireValue: Int) {
    Member(0),
    Admin(1),
    Owner(2);

    companion object {
        fun fromWireValue(value: Int): ChatMemberRole = entries.firstOrNull { it.wireValue == value } ?: Member
    }
}

object ChatMemberRoleSerializer : KSerializer<ChatMemberRole> {
    override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("ChatMemberRole", PrimitiveKind.INT)
    override fun deserialize(decoder: Decoder): ChatMemberRole = ChatMemberRole.fromWireValue(decoder.decodeInt())
    override fun serialize(encoder: Encoder, value: ChatMemberRole) = encoder.encodeInt(value.wireValue)
}

@Serializable(with = ChatJoinRequestStatusSerializer::class)
enum class ChatJoinRequestStatus(val wireValue: Int) {
    Pending(0),
    Approved(1),
    Declined(2);

    companion object {
        fun fromWireValue(value: Int): ChatJoinRequestStatus = entries.firstOrNull { it.wireValue == value } ?: Pending
    }
}

object ChatJoinRequestStatusSerializer : KSerializer<ChatJoinRequestStatus> {
    override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("ChatJoinRequestStatus", PrimitiveKind.INT)
    override fun deserialize(decoder: Decoder): ChatJoinRequestStatus = ChatJoinRequestStatus.fromWireValue(decoder.decodeInt())
    override fun serialize(encoder: Encoder, value: ChatJoinRequestStatus) = encoder.encodeInt(value.wireValue)
}

@Serializable(with = ModerationLogTargetTypeSerializer::class)
enum class ModerationLogTargetType(val wireValue: Int) {
    Chat(0),
    Message(1),
    User(2),
    InviteLink(3),
    JoinRequest(4),
    Story(5);

    companion object {
        fun fromWireValue(value: Int): ModerationLogTargetType = entries.firstOrNull { it.wireValue == value } ?: Chat
    }
}

object ModerationLogTargetTypeSerializer : KSerializer<ModerationLogTargetType> {
    override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("ModerationLogTargetType", PrimitiveKind.INT)
    override fun deserialize(decoder: Decoder): ModerationLogTargetType = ModerationLogTargetType.fromWireValue(decoder.decodeInt())
    override fun serialize(encoder: Encoder, value: ModerationLogTargetType) = encoder.encodeInt(value.wireValue)
}

object ChatTypeSerializer : KSerializer<ChatType> {
    override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("ChatType", PrimitiveKind.INT)
    override fun deserialize(decoder: Decoder): ChatType = ChatType.fromWireValue(decoder.decodeInt())
    override fun serialize(encoder: Encoder, value: ChatType) = encoder.encodeInt(value.wireValue)
}

@Serializable(with = AttachmentKindSerializer::class)
enum class AttachmentKind(val wireValue: Int) {
    File(1),
    VoiceNote(2);

    companion object {
        fun fromWireValue(value: Int): AttachmentKind = entries.firstOrNull { it.wireValue == value } ?: File
    }
}

object AttachmentKindSerializer : KSerializer<AttachmentKind> {
    override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("AttachmentKind", PrimitiveKind.INT)
    override fun deserialize(decoder: Decoder): AttachmentKind = AttachmentKind.fromWireValue(decoder.decodeInt())
    override fun serialize(encoder: Encoder, value: AttachmentKind) = encoder.encodeInt(value.wireValue)
}

@Serializable(with = MessageDeliveryStateSerializer::class)
enum class MessageDeliveryState(val wireValue: Int) {
    Sent(0),
    Delivered(1),
    Read(2);

    companion object {
        fun fromWireValue(value: Int): MessageDeliveryState = entries.firstOrNull { it.wireValue == value } ?: Sent
    }
}

object MessageDeliveryStateSerializer : KSerializer<MessageDeliveryState> {
    override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("MessageDeliveryState", PrimitiveKind.INT)
    override fun deserialize(decoder: Decoder): MessageDeliveryState = MessageDeliveryState.fromWireValue(decoder.decodeInt())
    override fun serialize(encoder: Encoder, value: MessageDeliveryState) = encoder.encodeInt(value.wireValue)
}

@Serializable(with = CallMediaTypeSerializer::class)
enum class CallMediaType(val wireValue: Int) {
    Audio(0),
    Video(1);

    companion object {
        fun fromWireValue(value: Int): CallMediaType = entries.firstOrNull { it.wireValue == value } ?: Audio
    }
}

object CallMediaTypeSerializer : KSerializer<CallMediaType> {
    override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("CallMediaType", PrimitiveKind.INT)
    override fun deserialize(decoder: Decoder): CallMediaType = CallMediaType.fromWireValue(decoder.decodeInt())
    override fun serialize(encoder: Encoder, value: CallMediaType) = encoder.encodeInt(value.wireValue)
}

@Serializable(with = PushPlatformSerializer::class)
enum class PushPlatform(val wireValue: Int) {
    Unknown(0),
    Android(1),
    Windows(2);

    companion object {
        fun fromWireValue(value: Int): PushPlatform = entries.firstOrNull { it.wireValue == value } ?: Unknown
    }
}

object PushPlatformSerializer : KSerializer<PushPlatform> {
    override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("PushPlatform", PrimitiveKind.INT)
    override fun deserialize(decoder: Decoder): PushPlatform = PushPlatform.fromWireValue(decoder.decodeInt())
    override fun serialize(encoder: Encoder, value: PushPlatform) = encoder.encodeInt(value.wireValue)
}

@Serializable(with = StoryVisibilitySerializer::class)
enum class StoryVisibility(val wireValue: Int) {
    Everyone(0),
    Contacts(1),
    CloseFriends(2),
    Private(3);

    companion object {
        fun fromWireValue(value: Int): StoryVisibility = entries.firstOrNull { it.wireValue == value } ?: Everyone
    }
}

object StoryVisibilitySerializer : KSerializer<StoryVisibility> {
    override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("StoryVisibility", PrimitiveKind.INT)
    override fun deserialize(decoder: Decoder): StoryVisibility = StoryVisibility.fromWireValue(decoder.decodeInt())
    override fun serialize(encoder: Encoder, value: StoryVisibility) = encoder.encodeInt(value.wireValue)
}

@Serializable
data class UserSummaryDto(
    val id: String,
    val username: String,
    val displayName: String,
    val isOnline: Boolean,
    val phoneNumber: String? = null,
    val lastSeenAt: String? = null,
    val about: String? = null,
    val avatarPath: String? = null,
    val isBot: Boolean = false
)

@Serializable
data class AttachmentDto(
    val id: String,
    val fileName: String,
    val contentType: String,
    val fileSizeBytes: Long,
    val downloadPath: String,
    val kind: AttachmentKind,
    val sortOrder: Int = 0
)

@Serializable
data class MessageReplyDto(
    val messageId: String,
    val senderId: String,
    val senderDisplayName: String,
    val previewText: String
)

@Serializable
data class MessageReactionDto(
    val emoji: String,
    val count: Int,
    val isMine: Boolean
)

@Serializable
data class MessageDto(
    val id: String,
    val chatId: String,
    val chatType: ChatType = ChatType.Direct,
    val sender: UserSummaryDto,
    val text: String,
    val attachments: List<AttachmentDto> = emptyList(),
    val sentAt: String,
    val editedAt: String? = null,
    val deletedAt: String? = null,
    val deliveryState: MessageDeliveryState,
    val forwardedFromDisplayName: String? = null,
    val replyTo: MessageReplyDto? = null,
    val pinnedAt: String? = null,
    val pinnedBy: UserSummaryDto? = null,
    val mediaAlbumId: String? = null,
    val reactions: List<MessageReactionDto> = emptyList(),
    val hasProtectedContent: Boolean = false,
    val expiresAt: String? = null,
    val ttlSeconds: Int? = null,
    val postedAsChannel: Boolean = false,
    val displayAuthorName: String? = null,
    val viewCount: Int? = null
)

@Serializable
data class ChatPermissionsDto(
    val canPostMessages: Boolean = true,
    val canPinMessages: Boolean = true,
    val canDeleteMessages: Boolean = false,
    val canInviteUsers: Boolean = true,
    val canManageMembers: Boolean = false
)

@Serializable
data class ChatMemberDto(
    val user: UserSummaryDto,
    val role: ChatMemberRole = ChatMemberRole.Member,
    val isOwner: Boolean = false,
    val permissions: ChatPermissionsDto = ChatPermissionsDto()
)

@Serializable
data class ChatSummaryDto(
    val id: String,
    val title: String,
    val type: ChatType,
    val secondaryText: String? = null,
    val lastActivityAt: String? = null,
    val lastMessagePreview: String? = null,
    val participants: List<UserSummaryDto> = emptyList(),
    val canSendMessages: Boolean = true,
    val unreadCount: Int = 0,
    val isPinned: Boolean = false,
    val isArchived: Boolean = false,
    val isMuted: Boolean = false,
    val folderKey: String? = null,
    val hasProtectedContent: Boolean = false,
    val defaultMessageTtlSeconds: Int? = null,
    val lastMessageAttachment: AttachmentDto? = null,
    val subscriberCount: Int = 0,
    val adminCount: Int = 0,
    val isSubscribed: Boolean = false,
    val canSubscribe: Boolean = false,
    val canManageChannel: Boolean = false,
    val canPostAsChannel: Boolean = false,
    val publicUsername: String? = null,
    val linkedDiscussionChatId: String? = null,
    val channelSignaturesEnabled: Boolean = false,
    val description: String? = null
)

@Serializable
data class ChatDetailsDto(
    val id: String,
    val title: String,
    val type: ChatType,
    val participants: List<UserSummaryDto> = emptyList(),
    val canSendMessages: Boolean = true,
    val messages: List<MessageDto> = emptyList(),
    val firstUnreadMessageId: String? = null,
    val hasMoreMessages: Boolean = false,
    val pinnedMessages: List<MessageDto> = emptyList(),
    val currentUserPermissions: ChatPermissionsDto? = null,
    val members: List<ChatMemberDto> = emptyList(),
    val hasProtectedContent: Boolean = false,
    val defaultMessageTtlSeconds: Int? = null,
    val subscriberCount: Int = 0,
    val adminCount: Int = 0,
    val isSubscribed: Boolean = false,
    val canSubscribe: Boolean = false,
    val canManageChannel: Boolean = false,
    val canPostAsChannel: Boolean = false,
    val publicUsername: String? = null,
    val linkedDiscussionChatId: String? = null,
    val channelSignaturesEnabled: Boolean = false,
    val description: String? = null
)

@Serializable
data class ChatInfoDto(
    val chat: ChatDetailsDto,
    val mediaCount: Int = 0,
    val fileCount: Int = 0,
    val linkCount: Int = 0,
    val voiceCount: Int = 0,
    val pinnedCount: Int = 0,
    val topicCount: Int = 0,
    val publicUsername: String? = null,
    val inviteLinks: List<ChatInviteLinkDto> = emptyList(),
    val topics: List<ChatTopicDto> = emptyList(),
    val subscriberCount: Int = 0,
    val adminCount: Int = 0,
    val linkedDiscussionChatId: String? = null,
    val channelSignaturesEnabled: Boolean = false,
    val canManageChannel: Boolean = false,
    val canPostAsChannel: Boolean = false,
    val description: String? = null
)

@Serializable
data class ChatMessagesPageDto(
    val messages: List<MessageDto> = emptyList(),
    val hasMoreMessages: Boolean = false
)

@Serializable
data class TypingIndicatorDto(
    val chatId: String,
    val user: UserSummaryDto,
    val isTyping: Boolean,
    val typedAt: String
)

@Serializable
data class ChatFolderDto(
    val key: String,
    val title: String,
    val totalCount: Int,
    val unreadCount: Int
)

@Serializable
data class ChatStateRequest(
    val isPinned: Boolean? = null,
    val isArchived: Boolean? = null,
    val mutedUntil: String? = null,
    val folderKey: String? = null,
    val isMuted: Boolean? = null,
    val hasProtectedContent: Boolean? = null,
    val defaultMessageTtlSeconds: Int? = null,
    val channelSignaturesEnabled: Boolean? = null,
    val linkedDiscussionChatId: String? = null
)

@Serializable
data class ChatInviteLinkDto(
    val id: String,
    val chatId: String,
    val token: String,
    val link: String,
    val title: String? = null,
    val createsJoinRequest: Boolean = false,
    val isRevoked: Boolean = false,
    val createdAt: String,
    val revokedAt: String? = null
)

@Serializable
data class CreateChatInviteLinkRequest(
    val title: String? = null,
    val createsJoinRequest: Boolean = false
)

@Serializable
data class ChatJoinRequestDto(
    val id: String,
    val chatId: String,
    val inviteLinkId: String,
    val user: UserSummaryDto,
    val status: ChatJoinRequestStatus,
    val requestedAt: String,
    val resolvedAt: String? = null,
    val resolvedBy: UserSummaryDto? = null
)

@Serializable
data class ResolveChatJoinRequestRequest(
    val approve: Boolean
)

@Serializable
data class ModerationLogDto(
    val id: Long,
    val chatId: String? = null,
    val actorUserId: String,
    val actorDisplayName: String,
    val targetType: ModerationLogTargetType,
    val targetId: String? = null,
    val action: String,
    val reason: String? = null,
    val createdAt: String
)

@Serializable
data class ChatTopicDto(
    val id: String,
    val chatId: String,
    val title: String,
    val icon: String = "💬",
    val isPinned: Boolean = false,
    val isClosed: Boolean = false,
    val createdAt: String,
    val lastActivityAt: String,
    val messageCount: Int = 0
)

@Serializable
data class CreateChatTopicRequest(
    val title: String,
    val icon: String? = null
)

@Serializable
data class UpdateChatMemberPermissionsRequest(
    val role: ChatMemberRole,
    val canPinMessages: Boolean,
    val canDeleteMessages: Boolean,
    val canInviteUsers: Boolean,
    val canPostMessages: Boolean
)

@Serializable
data class AddChatMembersRequest(
    val memberIds: List<String>,
    val role: ChatMemberRole = ChatMemberRole.Member,
    val canPinMessages: Boolean = false,
    val canDeleteMessages: Boolean = false,
    val canInviteUsers: Boolean = false,
    val canPostMessages: Boolean = false
)

@Serializable
data class ChatSearchResultDto(
    val chat: ChatSummaryDto,
    val message: MessageDto? = null,
    val matchText: String,
    val matchedAt: String? = null,
    val chatId: String? = null,
    val messageId: String? = null,
    val senderUserId: String? = null,
    val messageSentAt: String? = null
)

@Serializable
data class ChatSearchPageDto(
    val results: List<ChatSearchResultDto> = emptyList(),
    val page: Int = 1,
    val limit: Int = 50,
    val hasMore: Boolean = false
)

@Serializable
data class MessageSearchPageDto(
    val messages: List<MessageDto> = emptyList(),
    val page: Int = 1,
    val limit: Int = 50,
    val hasMore: Boolean = false
)

@Serializable
data class CreateDirectChatRequest(
    val userId: String
)

@Serializable
data class CreateGroupChatRequest(
    val title: String,
    val memberIds: List<String>
)

@Serializable
data class CreateChannelRequest(
    val title: String,
    val memberIds: List<String>,
    val description: String? = null,
    val publicUsername: String? = null,
    val createInviteLink: Boolean = false,
    val channelSignaturesEnabled: Boolean = false
)

@Serializable
data class RequestPhoneCodeRequest(
    val phoneNumber: String
)

@Serializable
data class PhoneCodeChallengeDto(
    val challengeId: String,
    val expiresAt: String,
    val testCode: String,
    val isRegistered: Boolean
)

@Serializable
data class VerifyPhoneCodeRequest(
    val challengeId: String,
    val phoneNumber: String,
    val code: String,
    val displayName: String? = null
)

@Serializable
data class RefreshSessionRequest(
    val refreshToken: String
)

@Serializable
data class AuthSessionDto(
    val accessToken: String,
    val refreshToken: String,
    val accessTokenExpiresAt: String,
    val user: UserSummaryDto
)

@Serializable
data class SendMessageRequest(
    val text: String,
    val replyToMessageId: String? = null,
    val topicId: String? = null,
    val hasProtectedContent: Boolean? = null,
    val ttlSeconds: Int? = null
)

@Serializable
data class UpdateMessageRequest(
    val text: String
)

@Serializable
data class UpdateMessageReceiptRequest(
    val messageId: String
)

@Serializable
data class ForwardMessageRequest(
    val targetChatId: String
)

@Serializable
data class SetMessageReactionRequest(
    val emoji: String
)

@Serializable
data class RegisterPushDeviceRequest(
    val platform: PushPlatform,
    val installationId: String,
    val deviceToken: String,
    val deviceName: String? = null,
    val notificationsEnabled: Boolean
)

@Serializable
data class AndroidAppReleaseDto(
    val versionCode: Int,
    val versionName: String,
    val downloadPath: String,
    val publishedAt: String,
    val notes: String? = null,
    val isRequired: Boolean = false,
    val minimumSupportedVersionCode: Int? = null
)

@Serializable
data class ArgusManifestDto(
    val release: ArgusReleaseDto
)

@Serializable
data class ArgusReleaseDto(
    val id: String,
    val version: String,
    val downloadPath: String,
    val originalFileName: String? = null,
    val packageSizeBytes: Long? = null,
    val publishedAt: String,
    val releaseNotes: String? = null
)

@Serializable
data class ResolveContactsRequest(
    val phoneNumbers: List<String>
)

@Serializable
data class ContactMatchDto(
    val phoneNumber: String,
    val user: UserSummaryDto
)

@Serializable
data class StoryDto(
    val id: String,
    val author: UserSummaryDto,
    val text: String,
    val attachments: List<AttachmentDto> = emptyList(),
    val visibility: StoryVisibility = StoryVisibility.Everyone,
    val hasProtectedContent: Boolean = false,
    val createdAt: String,
    val expiresAt: String,
    val deletedAt: String? = null,
    val viewCount: Int = 0,
    val viewedByMe: Boolean = false
)

@Serializable
data class CreateStoryRequest(
    val text: String? = null,
    val visibility: StoryVisibility = StoryVisibility.Everyone,
    val hasProtectedContent: Boolean = false,
    val ttlSeconds: Int = 86_400
)

@Serializable
data class StoryViewDto(
    val storyId: String,
    val viewer: UserSummaryDto,
    val viewedAt: String
)

@Serializable
data class UpdateMyProfileRequest(
    val displayName: String,
    val about: String? = null
)

@Serializable
data class PrivacySettingsDto(
    val phoneNumberVisibility: String = "contacts",
    val lastSeenVisibility: String = "contacts",
    val profilePhotoVisibility: String = "everyone",
    val blockedUserIds: List<String> = emptyList(),
    val alwaysAllowUserIds: List<String> = emptyList(),
    val neverAllowUserIds: List<String> = emptyList(),
    val passcodeLockEnabled: Boolean = false,
    val showMessagePreview: Boolean = true,
    val updatedAt: String
)

@Serializable
data class UpdatePrivacySettingsRequest(
    val phoneNumberVisibility: String,
    val lastSeenVisibility: String,
    val profilePhotoVisibility: String,
    val blockedUserIds: List<String>? = null,
    val alwaysAllowUserIds: List<String>? = null,
    val neverAllowUserIds: List<String>? = null,
    val passcodeLockEnabled: Boolean,
    val showMessagePreview: Boolean
)

@Serializable
data class UserSessionDto(
    val id: String,
    val createdAt: String,
    val lastSeenAt: String,
    val isCurrent: Boolean,
    val deviceName: String
)

@Serializable
data class BotCommandDto(
    val command: String,
    val description: String
)

@Serializable
data class BotSummaryDto(
    val id: String,
    val userId: String,
    val username: String,
    val displayName: String,
    val about: String? = null,
    val isEnabled: Boolean,
    val createdAt: String,
    val commands: List<BotCommandDto> = emptyList()
)

@Serializable
data class CreateBotRequest(
    val username: String,
    val displayName: String,
    val about: String? = null
)

@Serializable
data class UpdateBotRequest(
    val displayName: String,
    val about: String? = null,
    val isEnabled: Boolean
)

@Serializable
data class CreatedBotDto(
    val bot: BotSummaryDto,
    val accessToken: String
)

@Serializable
data class RegenerateBotTokenResponseDto(
    val accessToken: String
)

@Serializable
data class SetBotCommandsRequest(
    val commands: List<BotCommandDto>
)

@Serializable
data class OutgoingCallDto(
    val callId: String,
    val chatId: String,
    val peer: UserSummaryDto,
    val mediaType: CallMediaType
)

@Serializable
data class IncomingCallDto(
    val callId: String,
    val chatId: String,
    val caller: UserSummaryDto,
    val mediaType: CallMediaType
)

@Serializable
data class CallConnectedDto(
    val callId: String,
    val chatId: String,
    val connectedAt: String,
    val mediaType: CallMediaType,
    val iceServers: List<CallIceServerDto> = emptyList(),
    val shouldCreateOffer: Boolean = false
)

@Serializable
data class CallEndedDto(
    val callId: String,
    val chatId: String,
    val reason: String,
    val mediaType: CallMediaType
)

@Serializable
data class CallIceServerDto(
    val urls: List<String>,
    val username: String? = null,
    val credential: String? = null
)

@Serializable
data class CallOfferDto(
    val callId: String,
    val type: String,
    val sdp: String
)

@Serializable
data class CallAnswerDto(
    val callId: String,
    val type: String,
    val sdp: String
)

@Serializable
data class CallIceCandidateDto(
    val callId: String,
    val candidate: String,
    val sdpMid: String? = null,
    val sdpMLineIndex: Int
)

data class DownloadedAttachmentFile(
    val fileName: String,
    val contentType: String,
    val fileSizeBytes: Long,
    val localPath: String
)
