package com.rosetta.messenger.ui.chats

import android.content.Context
import android.widget.Toast
import androidx.activity.compose.BackHandler
import androidx.compose.animation.*
import androidx.compose.animation.core.*
import androidx.compose.foundation.*
import androidx.compose.foundation.gestures.awaitEachGesture
import androidx.compose.foundation.gestures.awaitFirstDown
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Close
import androidx.compose.material.icons.filled.Pause
import androidx.compose.material.icons.filled.PlayArrow
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.clipToBounds
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.graphics.BlendMode
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.CompositingStrategy
import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.graphics.Path
import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.graphics.drawscope.clipPath
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.graphics.lerp
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.input.pointer.changedToUpIgnoreConsumed
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.input.pointer.positionChange
import androidx.compose.ui.input.pointer.util.VelocityTracker
import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.layout.onSizeChanged
import androidx.compose.ui.layout.positionInRoot
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.window.Dialog
import androidx.compose.ui.window.DialogProperties
import androidx.core.view.drawToBitmap
import com.airbnb.lottie.compose.*
import com.rosetta.messenger.R
import com.rosetta.messenger.BuildConfig
import com.rosetta.messenger.data.AccountManager
import com.rosetta.messenger.data.EncryptedAccount
import com.rosetta.messenger.data.MessageRepository
import com.rosetta.messenger.data.RecentSearchesManager
import com.rosetta.messenger.data.isPlaceholderAccountName
import com.rosetta.messenger.data.resolveAccountDisplayName
import com.rosetta.messenger.di.ProtocolGateway
import com.rosetta.messenger.database.RosettaDatabase
import com.rosetta.messenger.network.CallPhase
import com.rosetta.messenger.network.CallUiState
import com.rosetta.messenger.network.DeviceEntry
import com.rosetta.messenger.network.ProtocolState
import com.rosetta.messenger.repository.AvatarRepository
import com.rosetta.messenger.ui.chats.calls.CallsHistoryScreen
import com.rosetta.messenger.ui.chats.calls.CallTopBanner
import com.rosetta.messenger.ui.chats.components.AnimatedDotsText
import com.rosetta.messenger.ui.chats.components.DeviceVerificationBanner
import com.rosetta.messenger.ui.chats.components.VoicePlaybackCoordinator
import com.rosetta.messenger.ui.components.AppleEmojiText
import com.rosetta.messenger.ui.components.AvatarImage
import com.rosetta.messenger.ui.components.VerifiedBadge
import com.rosetta.messenger.ui.onboarding.PrimaryBlue
import com.rosetta.messenger.ui.onboarding.PrimaryBlueDark
import com.rosetta.messenger.update.UpdateManager
import com.rosetta.messenger.update.UpdateState
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
import androidx.compose.ui.platform.LocalHapticFeedback
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.res.painterResource
import androidx.hilt.navigation.compose.hiltViewModel
import compose.icons.TablerIcons
import compose.icons.tablericons.*
import com.rosetta.messenger.ui.icons.TelegramIcons
import java.text.SimpleDateFormat
import java.util.*
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withTimeoutOrNull
import kotlin.math.hypot
import kotlin.math.roundToInt

@Immutable
data class Chat(
        val id: String,
        val name: String,
        val lastMessage: String,
        val lastMessageTime: Date,
        val unreadCount: Int = 0,
        val isOnline: Boolean = false,
        val publicKey: String,
        val isSavedMessages: Boolean = false,
        val isPinned: Boolean = false
)

private enum class DeviceResolveAction {
        ACCEPT,
        DECLINE
}

private const val SKELETON_VISIBILITY_DELAY_MS = 180L

// Avatar colors matching React Native app (Mantine inspired)
// Light theme colors (background lighter, text darker)
private val avatarColorsLight =
        listOf(
                Color(0xFF1971c2) to Color(0xFFd0ebff), // blue
                Color(0xFF0c8599) to Color(0xFFc5f6fa), // cyan
                Color(0xFF9c36b5) to Color(0xFFeebefa), // grape
                Color(0xFF2f9e44) to Color(0xFFd3f9d8), // green
                Color(0xFF4263eb) to Color(0xFFdbe4ff), // indigo
                Color(0xFF5c940d) to Color(0xFFe9fac8), // lime
                Color(0xFFd9480f) to Color(0xFFffe8cc), // orange
                Color(0xFFc2255c) to Color(0xFFffdeeb), // pink
                Color(0xFFe03131) to Color(0xFFffe0e0), // red
                Color(0xFF099268) to Color(0xFFc3fae8), // teal
                Color(0xFF6741d9) to Color(0xFFe5dbff) // violet
        )

// Dark theme colors (background darker, text lighter)
private val avatarColorsDark =
        listOf(
                Color(0xFF7dd3fc) to Color(0xFF2d3548), // blue
                Color(0xFF67e8f9) to Color(0xFF2d4248), // cyan
                Color(0xFFd8b4fe) to Color(0xFF39334c), // grape
                Color(0xFF86efac) to Color(0xFF2d3f32), // green
                Color(0xFFa5b4fc) to Color(0xFF333448), // indigo
                Color(0xFFbef264) to Color(0xFF383f2d), // lime
                Color(0xFFfdba74) to Color(0xFF483529), // orange
                Color(0xFFf9a8d4) to Color(0xFF482d3d), // pink
                Color(0xFFfca5a5) to Color(0xFF482d2d), // red
                Color(0xFF5eead4) to Color(0xFF2d4340), // teal
                Color(0xFFc4b5fd) to Color(0xFF3a334c) // violet
        )

// Cache для цветов аватаров
data class AvatarColors(val textColor: Color, val backgroundColor: Color)

private val avatarColorCache = object : LinkedHashMap<String, AvatarColors>(128, 0.75f, true) {
        override fun removeEldestEntry(eldest: MutableMap.MutableEntry<String, AvatarColors>?) = size > 500
}

/**
 * Определяет, является ли цвет светлым (true) или темным (false) Использует формулу relative
 * luminance из WCAG
 */
fun isColorLight(color: Color): Boolean {
        val luminance = 0.299f * color.red + 0.587f * color.green + 0.114f * color.blue
        return luminance > 0.5f
}

fun getAvatarColor(name: String, isDarkTheme: Boolean): AvatarColors {
        val cacheKey = "${name}_${if (isDarkTheme) "dark" else "light"}"
        return avatarColorCache.getOrPut(cacheKey) {
                val colors = if (isDarkTheme) avatarColorsDark else avatarColorsLight
                val index =
                        name.hashCode().mod(colors.size).let {
                                if (it < 0) it + colors.size else it
                        }
                val (textColor, bgColor) = colors[index]
                AvatarColors(textColor, bgColor)
        }
}

// Cache для инициалов
private val initialsCache = object : LinkedHashMap<String, String>(128, 0.75f, true) {
        override fun removeEldestEntry(eldest: MutableMap.MutableEntry<String, String>?) = size > 500
}

fun getInitials(name: String): String {
        return initialsCache.getOrPut(name) {
                val words = name.trim().split(Regex("\\s+")).filter { it.isNotEmpty() }
                when {
                        words.isEmpty() -> "??"
                        words.size == 1 -> words[0].take(2).uppercase()
                        else -> "${words[0].first()}${words[1].first()}".uppercase()
                }
        }
}

// Get avatar text from public key (first 2 chars)
fun getAvatarText(publicKey: String): String {
        return publicKey.take(2).uppercase()
}

private fun isGroupDialogKey(value: String): Boolean {
        val normalized = value.trim().lowercase()
        return normalized.startsWith("#group:") || normalized.startsWith("group:")
}

private fun normalizeGroupDialogKey(value: String): String {
        val trimmed = value.trim()
        val normalized = trimmed.lowercase(Locale.ROOT)
        return when {
                normalized.startsWith("#group:") -> "#group:${trimmed.substringAfter(':').trim()}"
                normalized.startsWith("group:") -> "#group:${trimmed.substringAfter(':').trim()}"
                else -> trimmed
        }
}

private fun isTypingForDialog(dialogKey: String, typingDialogs: Set<String>): Boolean {
        if (typingDialogs.isEmpty()) return false
        if (isGroupDialogKey(dialogKey)) {
                val normalizedDialogKey = normalizeGroupDialogKey(dialogKey)
                return typingDialogs.any {
                        isGroupDialogKey(it) &&
                                normalizeGroupDialogKey(it).equals(normalizedDialogKey, ignoreCase = true)
                }
        }
        return typingDialogs.any { it.equals(dialogKey.trim(), ignoreCase = true) }
}

private fun isVoicePlayingForDialog(dialogKey: String, playingDialogKey: String?): Boolean {
        val active = playingDialogKey?.trim().orEmpty()
        if (active.isEmpty()) return false
        if (isGroupDialogKey(dialogKey) || isGroupDialogKey(active)) {
                return normalizeGroupDialogKey(dialogKey).equals(
                        normalizeGroupDialogKey(active),
                        ignoreCase = true
                )
        }
        return dialogKey.trim().equals(active, ignoreCase = true)
}

private fun shortPublicKey(value: String): String {
        val trimmed = value.trim()
        if (trimmed.length <= 12) return trimmed
        return "${trimmed.take(6)}...${trimmed.takeLast(4)}"
}

private fun resolveTypingDisplayName(protocolGateway: ProtocolGateway, publicKey: String): String {
        val normalized = publicKey.trim()
        if (normalized.isBlank()) return ""
        val cached = protocolGateway.getCachedUserInfo(normalized)
        val resolvedName =
                cached?.title?.trim().orEmpty().ifBlank { cached?.username?.trim().orEmpty() }
        return if (resolvedName.isNotBlank()) resolvedName else shortPublicKey(normalized)
}

private fun rosettaDev1Log(context: Context, tag: String, message: String) {
        runCatching {
                val dir = java.io.File(context.filesDir, "crash_reports")
                if (!dir.exists()) dir.mkdirs()
                val ts = SimpleDateFormat("HH:mm:ss.SSS", Locale.getDefault()).format(Date())
                java.io.File(dir, "rosettadev1.txt").appendText("$ts [$tag] $message\n")
        }
}

internal val TELEGRAM_DIALOG_AVATAR_START = 10.dp
internal val TELEGRAM_DIALOG_TEXT_START = 72.dp
internal val TELEGRAM_DIALOG_AVATAR_SIZE = 54.dp
internal val TELEGRAM_DIALOG_ROW_HEIGHT = 72.dp
internal val TELEGRAM_DIALOG_VERTICAL_PADDING = 9.dp
internal val TELEGRAM_DIALOG_AVATAR_GAP =
        TELEGRAM_DIALOG_TEXT_START - TELEGRAM_DIALOG_AVATAR_START - TELEGRAM_DIALOG_AVATAR_SIZE

private fun maxRevealRadius(center: Offset, bounds: IntSize): Float {
        if (bounds.width <= 0 || bounds.height <= 0) return 0f
        val width = bounds.width.toFloat()
        val height = bounds.height.toFloat()
        return maxOf(
                hypot(center.x, center.y),
                hypot(width - center.x, center.y),
                hypot(center.x, height - center.y),
                hypot(width - center.x, height - center.y)
        )
}

@OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class)
@Composable
fun ChatsListScreen(
        isDarkTheme: Boolean,
        accountName: String,
        accountUsername: String,
        accountVerified: Int = 0,
        accountPublicKey: String,
        accountPrivateKey: String = "",
        onToggleTheme: () -> Unit,
        onProfileClick: () -> Unit,
        onNewGroupClick: () -> Unit,
        onCallsClick: () -> Unit,
        onSavedMessagesClick: () -> Unit,
        onSettingsClick: () -> Unit,
        onSearchClick: () -> Unit,
        onRequestsClick: () -> Unit = {},
        onNewChat: () -> Unit,
        onUserSelect: (com.rosetta.messenger.network.SearchUser) -> Unit = {},
        onStartCall: (com.rosetta.messenger.network.SearchUser) -> Unit = {},
        pinnedChats: Set<String> = emptySet(),
        onTogglePin: (String) -> Unit = {},
        protocolGateway: ProtocolGateway,
        accountManager: AccountManager,
        preferencesManager: com.rosetta.messenger.data.PreferencesManager,
        chatsViewModel: ChatsListViewModel = hiltViewModel(),
        avatarRepository: com.rosetta.messenger.repository.AvatarRepository? = null,
        callUiState: CallUiState = CallUiState(),
        isCallOverlayExpanded: Boolean = true,
        onOpenCallOverlay: () -> Unit = {},
        onAddAccount: () -> Unit = {},
        onSwitchAccount: (String) -> Unit = {},
        onDeleteAccountFromSidebar: (String) -> Unit = {},
        onQrScanClick: () -> Unit = {},
        onMyQrClick: () -> Unit = {}
) {
        // Theme transition state
        var hasInitialized by remember { mutableStateOf(false) }

        LaunchedEffect(Unit) { hasInitialized = true }

        val view = androidx.compose.ui.platform.LocalView.current
        val context = androidx.compose.ui.platform.LocalContext.current
        val focusManager = androidx.compose.ui.platform.LocalFocusManager.current
        val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed)
        val scope = rememberCoroutineScope()
        val sduUpdateState by UpdateManager.updateState.collectAsState()
        val themeRevealRadius = remember { Animatable(0f) }
        var rootSize by remember { mutableStateOf(IntSize.Zero) }
        var themeToggleCenterInRoot by remember { mutableStateOf<Offset?>(null) }
        var themeRevealActive by remember { mutableStateOf(false) }
        var themeRevealToDark by remember { mutableStateOf(false) }
        var themeRevealCenter by remember { mutableStateOf(Offset.Zero) }
        var themeRevealSnapshot by remember { mutableStateOf<ImageBitmap?>(null) }
        var prewarmedBitmap by remember { mutableStateOf<android.graphics.Bitmap?>(null) }

        // Prewarm: capture bitmap on first appear + when drawer opens
        LaunchedEffect(Unit) {
            kotlinx.coroutines.delay(1000)
            if (prewarmedBitmap == null) {
                prewarmedBitmap = runCatching { view.drawToBitmap() }.getOrNull()
            }
        }
        LaunchedEffect(drawerState.isOpen) {
            if (drawerState.isOpen) {
                kotlinx.coroutines.delay(200)
                prewarmedBitmap = runCatching { view.drawToBitmap() }.getOrNull()
            }
        }

        fun startThemeReveal() {
                if (themeRevealActive) {
                        return
                }
                if (rootSize.width <= 0 || rootSize.height <= 0) {
                        onToggleTheme()
                        return
                }

                val center =
                        themeToggleCenterInRoot
                                ?: Offset(rootSize.width * 0.85f, rootSize.height * 0.12f)

                // Use prewarmed bitmap or capture fresh
                val snapshotBitmap = prewarmedBitmap ?: runCatching { view.drawToBitmap() }.getOrNull()
                prewarmedBitmap = null
                if (snapshotBitmap == null) {
                        onToggleTheme()
                        return
                }

                val toDark = !isDarkTheme
                val maxRadius = maxRevealRadius(center, rootSize)
                if (maxRadius <= 0f) {
                        snapshotBitmap.recycle()
                        onToggleTheme()
                        return
                }

                themeRevealActive = true
                themeRevealToDark = toDark
                themeRevealCenter = center
                themeRevealSnapshot = snapshotBitmap.asImageBitmap()

                scope.launch {
                        try {
                                if (toDark) {
                                        themeRevealRadius.snapTo(0f)
                                } else {
                                        themeRevealRadius.snapTo(maxRadius)
                                }
                                onToggleTheme()
                                withFrameNanos { }
                                themeRevealRadius.animateTo(
                                        targetValue = if (toDark) maxRadius else 0f,
                                        animationSpec =
                                                tween(
                                                        durationMillis = 400,
                                                        easing = CubicBezierEasing(0.45f, 0.05f, 0.55f, 0.95f)
                                                )
                                )
                        } finally {
                                themeRevealSnapshot = null
                                themeRevealActive = false
                        }
                }
        }

        // 🔥 ВСЕГДА закрываем клавиатуру при появлении ChatsListScreen
        // Используем DisposableEffect чтобы срабатывало при каждом появлении экрана
        DisposableEffect(Unit) {
                // Закрываем клавиатуру сразу
                val imm =
                        context.getSystemService(android.content.Context.INPUT_METHOD_SERVICE) as
                                android.view.inputmethod.InputMethodManager
                imm.hideSoftInputFromWindow(view.windowToken, 0)
                focusManager.clearFocus()

                onDispose {}
        }

        // Дополнительно закрываем клавиатуру с небольшой задержкой (на случай если она появляется
        // после)
        LaunchedEffect(Unit) {
                kotlinx.coroutines.delay(100)
                val imm =
                        context.getSystemService(android.content.Context.INPUT_METHOD_SERVICE) as
                                android.view.inputmethod.InputMethodManager
                imm.hideSoftInputFromWindow(view.windowToken, 0)
                focusManager.clearFocus()
        }

        // Update status bar appearance
        DisposableEffect(isDarkTheme) {
                val window = (view.context as android.app.Activity).window
                val insetsController =
                        androidx.core.view.WindowCompat.getInsetsController(window, view)

                // Status bar — always white icons (header is blue)
                insetsController.isAppearanceLightStatusBars = false
                window.statusBarColor = android.graphics.Color.TRANSPARENT

                onDispose { }
        }

        // Colors - instant change, no animation - 🔥 КЭШИРУЕМ для производительности
        val backgroundColor =
                remember(isDarkTheme) { if (isDarkTheme) Color(0xFF1A1A1A) else Color(0xFFF2F2F7) }
        val drawerBackgroundColor =
                remember(isDarkTheme) { if (isDarkTheme) Color(0xFF1C1C1E) else Color(0xFFF2F2F7) }
        val textColor = remember(isDarkTheme) { if (isDarkTheme) Color.White else Color.Black }
        val secondaryTextColor =
                remember(isDarkTheme) { if (isDarkTheme) Color(0xFF8E8E8E) else Color(0xFF8E8E93) }

        // Protocol connection state
        val protocolState by protocolGateway.state.collectAsState()
        val syncInProgress by protocolGateway.syncInProgress.collectAsState()
        val ownProfileUpdated by protocolGateway.ownProfileUpdated.collectAsState()
        val pendingDeviceVerification by protocolGateway.pendingDeviceVerification.collectAsState()

        // 📥 Active FILE downloads tracking (account-scoped, excludes photo downloads)
        val currentAccountKey = remember(accountPublicKey) { accountPublicKey.trim() }
        val allFileDownloads by
                com.rosetta.messenger.network.FileDownloadManager.downloads.collectAsState()
        val accountFileDownloads = remember(allFileDownloads, currentAccountKey) {
                allFileDownloads.values
                        .filter {
                                it.accountPublicKey.equals(currentAccountKey, ignoreCase = true)
                        }
                        .sortedByDescending { it.progress }
        }
        val database = remember(context) { RosettaDatabase.getDatabase(context) }
        val activeFileDownloads = remember(accountFileDownloads) {
                accountFileDownloads.filter {
                        it.status == com.rosetta.messenger.network.FileDownloadStatus.QUEUED ||
                                it.status ==
                                        com.rosetta.messenger.network.FileDownloadStatus
                                                .DOWNLOADING ||
                                it.status ==
                                        com.rosetta.messenger.network.FileDownloadStatus
                                                .PAUSED ||
                                it.status ==
                                        com.rosetta.messenger.network.FileDownloadStatus
                                                .DECRYPTING
                }
        }
        val hasActiveDownloads = activeFileDownloads.isNotEmpty()

        // �🔥 Пользователи, которые сейчас печатают
        val typingUsers by protocolGateway.typingUsers.collectAsState()
        val typingUsersByDialogSnapshot by protocolGateway.typingUsersByDialogSnapshot.collectAsState()
        val playingVoiceAttachmentId by VoicePlaybackCoordinator.playingAttachmentId.collectAsState()
        val playingVoiceDialogKey by VoicePlaybackCoordinator.playingDialogKey.collectAsState()
        val isVoicePlaybackRunning by VoicePlaybackCoordinator.isPlaying.collectAsState()
        val voicePlaybackSpeed by VoicePlaybackCoordinator.playbackSpeed.collectAsState()
        val playingVoiceSenderLabel by VoicePlaybackCoordinator.playingSenderLabel.collectAsState()
        val playingVoiceTimeLabel by VoicePlaybackCoordinator.playingTimeLabel.collectAsState()

        // Load dialogs as soon as public key is available.
        // Private key may appear a bit later right after fresh registration on some devices.
        LaunchedEffect(accountPublicKey, accountPrivateKey) {
                val normalizedPublicKey = accountPublicKey.trim()
                if (normalizedPublicKey.isEmpty()) return@LaunchedEffect

                val normalizedPrivateKey = accountPrivateKey.trim()
                val launchStart = System.currentTimeMillis()

                chatsViewModel.setAccount(normalizedPublicKey, normalizedPrivateKey)
                // Устанавливаем аккаунт для RecentSearchesManager
                RecentSearchesManager.setAccount(normalizedPublicKey)

                // Protocol/account initialization is handled globally in MainScreen.
                // ChatsList keeps only dialog/account-dependent UI state binding.

                android.util.Log.d(
                        "ChatsListScreen",
                        "✅ Account init effect: pubReady=true privReady=${normalizedPrivateKey.isNotEmpty()} " +
                                "in ${System.currentTimeMillis() - launchStart}ms"
                )
                rosettaDev1Log(
                        context = context,
                        tag = "ChatsListScreen",
                        message =
                                "Account init effect pub=${shortPublicKey(normalizedPublicKey)} " +
                                        "privReady=${normalizedPrivateKey.isNotEmpty()}"
                )
        }

        // Status dialog state
        var showStatusDialog by remember { mutableStateOf(false) }

        // 📬 Requests screen state
        var showRequestsScreen by remember { mutableStateOf(false) }
        var showCallsScreen by remember { mutableStateOf(false) }
        var showCallsMenu by remember { mutableStateOf(false) }
        var showDownloadsScreen by remember { mutableStateOf(false) }
        var isInlineRequestsTransitionLocked by remember { mutableStateOf(false) }
        var isInlineCallsTransitionLocked by remember { mutableStateOf(false) }
        var isRequestsRouteTapLocked by remember { mutableStateOf(false) }
        val inlineRequestsTransitionLockMs = 340L
        val inlineCallsTransitionLockMs = 340L
        val requestsRouteTapLockMs = 420L

        fun setInlineRequestsVisible(visible: Boolean) {
                if (showRequestsScreen == visible || isInlineRequestsTransitionLocked) return
                if (visible) showCallsScreen = false
                isInlineRequestsTransitionLocked = true
                showRequestsScreen = visible
                scope.launch {
                        kotlinx.coroutines.delay(inlineRequestsTransitionLockMs)
                        isInlineRequestsTransitionLocked = false
                }
        }

        fun setInlineCallsVisible(visible: Boolean) {
                if (showCallsScreen == visible || isInlineCallsTransitionLocked) return
                if (visible) showRequestsScreen = false
                isInlineCallsTransitionLocked = true
                showCallsScreen = visible
                if (!visible) showCallsMenu = false
                scope.launch {
                        kotlinx.coroutines.delay(inlineCallsTransitionLockMs)
                        isInlineCallsTransitionLocked = false
                }
        }

        suspend fun clearAllCallsHistory(): Int {
                if (accountPublicKey.isBlank()) return 0
                val messageDao = database.messageDao()
                val dialogDao = database.dialogDao()
                val peers = messageDao.getCallHistoryPeers(accountPublicKey).map { it.trim() }
                        .filter { it.isNotBlank() }.distinct()

                val deletedCount = messageDao.deleteAllCallMessages(accountPublicKey)
                if (deletedCount <= 0) return 0

                peers.forEach { peerKey ->
                        val dialogKey =
                                if (accountPublicKey == peerKey) {
                                        accountPublicKey
                                } else if (accountPublicKey < peerKey) {
                                        "$accountPublicKey:$peerKey"
                                } else {
                                        "$peerKey:$accountPublicKey"
                                }

                        val remaining = messageDao.getMessageCount(accountPublicKey, dialogKey)
                        if (remaining > 0) {
                                if (peerKey == accountPublicKey) {
                                        dialogDao.updateSavedMessagesDialogFromMessages(accountPublicKey)
                                } else {
                                        dialogDao.updateDialogFromMessages(accountPublicKey, peerKey)
                                }
                        } else {
                                dialogDao.deleteDialog(accountPublicKey, peerKey)
                        }
                }
                return deletedCount
        }

        fun openRequestsRouteSafely() {
                if (isRequestsRouteTapLocked) return
                isRequestsRouteTapLocked = true
                onRequestsClick()
                scope.launch {
                        kotlinx.coroutines.delay(requestsRouteTapLockMs)
                        isRequestsRouteTapLocked = false
                }
        }

        LaunchedEffect(currentAccountKey) {
                showDownloadsScreen = false
                showCallsScreen = false
        }

        // 📂 Accounts section expanded state (arrow toggle)
        var accountsSectionExpanded by remember { mutableStateOf(false) }

        // 👥 Load all accounts for sidebar (current account always first)
        var allAccounts by remember { mutableStateOf<List<EncryptedAccount>>(emptyList()) }
        LaunchedEffect(accountPublicKey, ownProfileUpdated) {
                var accounts = accountManager.getAllAccounts()
                val preferredPublicKey =
                        accountPublicKey.trim().ifBlank {
                                accountManager.getLastLoggedPublicKey().orEmpty()
                        }

                if (preferredPublicKey.isNotBlank()) {
                        val cachedOwn = protocolGateway.getCachedUserInfo(preferredPublicKey)
                        val cachedTitle = cachedOwn?.title?.trim().orEmpty()
                        val cachedUsername = cachedOwn?.username?.trim().orEmpty()
                        val existing =
                                accounts.firstOrNull {
                                        it.publicKey.equals(preferredPublicKey, ignoreCase = true)
                                }
                        var changed = false

                        if (existing != null &&
                                cachedTitle.isNotBlank() &&
                                !isPlaceholderAccountName(cachedTitle) &&
                                (existing.name.isBlank() || isPlaceholderAccountName(existing.name))) {
                                runCatching {
                                        accountManager.updateAccountName(preferredPublicKey, cachedTitle)
                                }.onSuccess { changed = true }
                        }

                        if (existing != null &&
                                cachedUsername.isNotBlank() &&
                                existing.username.orEmpty().isBlank()) {
                                runCatching {
                                        accountManager.updateAccountUsername(preferredPublicKey, cachedUsername)
                                }.onSuccess { changed = true }
                        }

                        if (changed) {
                                accounts = accountManager.getAllAccounts()
                        }
                }
                allAccounts = accounts.sortedByDescending { it.publicKey == preferredPublicKey }
        }

        val effectiveCurrentPublicKey =
                remember(accountPublicKey, allAccounts) {
                        accountPublicKey.trim().ifBlank { allAccounts.firstOrNull()?.publicKey.orEmpty() }
                }
        val currentSidebarAccount =
                remember(allAccounts, effectiveCurrentPublicKey) {
                        allAccounts.firstOrNull {
                                it.publicKey.equals(effectiveCurrentPublicKey, ignoreCase = true)
                        } ?: allAccounts.firstOrNull()
                }
        val sidebarAccountUsername =
                remember(accountUsername, currentSidebarAccount) {
                        accountUsername.ifBlank { currentSidebarAccount?.username.orEmpty() }
                }
        val sidebarAccountName =
                remember(accountName, sidebarAccountUsername, currentSidebarAccount, effectiveCurrentPublicKey) {
                        val preferredName =
                                when {
                                        accountName.isNotBlank() &&
                                                !isPlaceholderAccountName(accountName) -> accountName
                                        !currentSidebarAccount?.name.isNullOrBlank() ->
                                                currentSidebarAccount?.name.orEmpty()
                                        else -> accountName
                                }
                        resolveAccountDisplayName(
                                effectiveCurrentPublicKey,
                                preferredName,
                                sidebarAccountUsername
                        )
                }

        // Confirmation dialogs state
        var dialogsToDelete by remember { mutableStateOf<List<DialogUiModel>>(emptyList()) }
        var dialogToLeave by remember { mutableStateOf<DialogUiModel?>(null) }
        var dialogToBlock by remember { mutableStateOf<DialogUiModel?>(null) }
        var dialogToUnblock by remember { mutableStateOf<DialogUiModel?>(null) }
        var accountToDelete by remember { mutableStateOf<EncryptedAccount?>(null) }
        var showDeleteCallsDialog by remember { mutableStateOf(false) }
        var deviceResolveRequest by
                remember {
                        mutableStateOf<Pair<DeviceEntry, DeviceResolveAction>?>(null)
                }

        // 🔥 Selection mode state
        var selectedChatKeys by remember { mutableStateOf<Set<String>>(emptySet()) }
        val isSelectionMode = selectedChatKeys.isNotEmpty()
        val hapticFeedback = LocalHapticFeedback.current
        var showSelectionMenu by remember { mutableStateOf(false) }
        val mutedChats by preferencesManager.mutedChatsForAccount(effectiveCurrentPublicKey)
                .collectAsState(initial = emptySet())

        // Back: drawer → закрыть, selection → сбросить
        // Когда ничего не открыто — НЕ перехватываем, система сама закроет приложение корректно
        BackHandler(enabled = showDownloadsScreen || showCallsScreen || isSelectionMode || drawerState.isOpen) {
                if (showDownloadsScreen) {
                        showDownloadsScreen = false
                } else if (showCallsScreen) {
                        setInlineCallsVisible(false)
                } else if (isSelectionMode) {
                        selectedChatKeys = emptySet()
                } else if (drawerState.isOpen) {
                        scope.launch { drawerState.close() }
                }
        }

        // Close selection when drawer opens
        LaunchedEffect(drawerState.isOpen) {
                if (drawerState.isOpen) selectedChatKeys = emptySet()
        }

        // Реактивный set заблокированных пользователей из ViewModel (Room Flow)
        val blockedUsers by chatsViewModel.blockedUsers.collectAsState()

        // Requests count for badge on hamburger & sidebar
        val topLevelChatsState by chatsViewModel.chatsState.collectAsState()
        val topLevelIsLoading by chatsViewModel.isLoading.collectAsState()
        val topLevelRequestsCount = topLevelChatsState.requestsCount
        val visibleTopLevelRequestsCount = if (syncInProgress) 0 else topLevelRequestsCount

        // Anti-stuck guard:
        // если соединение уже AUTHENTICATED и синхронизация завершена,
        // loading не должен висеть бесконечно.
        LaunchedEffect(accountPublicKey, protocolState, syncInProgress, topLevelIsLoading) {
                val normalizedPublicKey = accountPublicKey.trim()
                if (normalizedPublicKey.isBlank()) return@LaunchedEffect
                if (!topLevelIsLoading) return@LaunchedEffect
                if (protocolState != ProtocolState.AUTHENTICATED || syncInProgress) return@LaunchedEffect

                delay(1200)
                if (
                        topLevelIsLoading &&
                                protocolState == ProtocolState.AUTHENTICATED &&
                                !syncInProgress
                ) {
                        rosettaDev1Log(
                                context = context,
                                tag = "ChatsListScreen",
                                message =
                                        "loading guard fired pub=${shortPublicKey(normalizedPublicKey)}"
                        )
                        chatsViewModel.forceStopLoading("ui_guard_authenticated_no_sync")
                }
        }

        // Dev console dialog - commented out for now
        /*
        if (showDevConsole) {
            AlertDialog(
                onDismissRequest = { showDevConsole = false },
                title = { Text("Dev Console", fontWeight = FontWeight.Bold) },
                text = { Text("Dev console temporarily disabled") },
                confirmButton = {
                    Button(onClick = { showDevConsole = false }) {
                        Text("Close")
                    }
                },
                containerColor = if (isDarkTheme) Color(0xFF212121) else Color.White
            )
        }
        */

        // Status dialog
        if (showStatusDialog) {
                AlertDialog(
                        onDismissRequest = { showStatusDialog = false },
                        title = {
                                Text(
                                        "Connection Status",
                                        fontWeight = FontWeight.Bold,
                                        color = textColor
                                )
                        },
                        text = {
                                Column(modifier = Modifier.fillMaxWidth()) {
                                        // Status indicator
                                        Row(
                                                verticalAlignment = Alignment.CenterVertically,
                                                modifier =
                                                        Modifier.fillMaxWidth()
                                                                .padding(bottom = 12.dp)
                                        ) {
                                                Box(
                                                        modifier =
                                                                Modifier.size(12.dp)
                                                                        .clip(CircleShape)
                                                                        .background(
                                                                                when (protocolState
                                                                                ) {
                                                                                        ProtocolState
                                                                                                .AUTHENTICATED ->
                                                                                                Color(
                                                                                                        0xFF4CAF50
                                                                                                )
                                                                                        ProtocolState
                                                                                                .DEVICE_VERIFICATION_REQUIRED ->
                                                                                                Color(
                                                                                                        0xFFFF9800
                                                                                                )
                                                                                        ProtocolState
                                                                                                .CONNECTING,
                                                                                        ProtocolState
                                                                                                .CONNECTED,
                                                                                        ProtocolState
                                                                                                .HANDSHAKING ->
                                                                                                Color(
                                                                                                        0xFFFFC107
                                                                                                )
                                                                                        ProtocolState
                                                                                                .DISCONNECTED ->
                                                                                                Color(
                                                                                                        0xFFF44336
                                                                                                )
                                                                                }
                                                                        )
                                                )
                                                Spacer(modifier = Modifier.width(12.dp))
                                                when (protocolState) {
                                                        ProtocolState.DISCONNECTED -> {
                                                                Text(
                                                                        text = "Disconnected",
                                                                        fontSize = 16.sp,
                                                                        fontWeight =
                                                                                FontWeight.Medium,
                                                                        color = textColor
                                                                )
                                                        }
                                                        ProtocolState.CONNECTING -> {
                                                                AnimatedDotsText(
                                                                        baseText = "Connecting",
                                                                        color = textColor,
                                                                        fontSize = 16.sp,
                                                                        fontWeight =
                                                                                FontWeight.Medium
                                                                )
                                                        }
                                                        ProtocolState.CONNECTED -> {
                                                                Text(
                                                                        text = "Connected",
                                                                        fontSize = 16.sp,
                                                                        fontWeight =
                                                                                FontWeight.Medium,
                                                                        color = textColor
                                                                )
                                                        }
                                                        ProtocolState.HANDSHAKING -> {
                                                                AnimatedDotsText(
                                                                        baseText = "Authenticating",
                                                                        color = textColor,
                                                                        fontSize = 16.sp,
                                                                        fontWeight =
                                                                                FontWeight.Medium
                                                                )
                                                        }
                                                        ProtocolState.AUTHENTICATED -> {
                                                                Text(
                                                                        text = "Authenticated",
                                                                        fontSize = 16.sp,
                                                                        fontWeight =
                                                                                FontWeight.Medium,
                                                                        color = textColor
                                                                )
                                                        }
                                                        ProtocolState.DEVICE_VERIFICATION_REQUIRED -> {
                                                                Text(
                                                                        text = "Device verification required",
                                                                        fontSize = 16.sp,
                                                                        fontWeight =
                                                                                FontWeight.Medium,
                                                                        color = textColor
                                                                )
                                                        }
                                                }
                                        }
                                }
                        },
                        confirmButton = {
                                Button(
                                        onClick = { showStatusDialog = false },
                                        colors =
                                                ButtonDefaults.buttonColors(
                                                        containerColor = PrimaryBlue
                                                )
                                ) { Text("Close", color = Color.White) }
                        },
                        containerColor = if (isDarkTheme) Color(0xFF212121) else Color.White
                )
        }

        // Simple background
        Box(
                modifier =
                        Modifier.fillMaxSize()
                                .onSizeChanged { rootSize = it }
                                .background(backgroundColor)
        ) {
                ModalNavigationDrawer(
                        drawerState = drawerState,
                        gesturesEnabled = !showRequestsScreen && !showDownloadsScreen && !showCallsScreen,
                        drawerContent = {
                                ModalDrawerSheet(
                                        drawerContainerColor = Color.Transparent,
                                        windowInsets =
                                                WindowInsets(0),
                                        modifier = Modifier.width(300.dp)
                                ) {
                                        Column(
                                                modifier =
                                                        Modifier.fillMaxSize()
                                                                .background(drawerBackgroundColor)
                                        ) {
                                                ChatsDrawerHeaderAndAccounts(
                                                        isDarkTheme = isDarkTheme,
                                                        drawerBackgroundColor = drawerBackgroundColor,
                                                        accountPublicKey = accountPublicKey,
                                                        accountVerified = accountVerified,
                                                        allAccounts = allAccounts,
                                                        effectiveCurrentPublicKey = effectiveCurrentPublicKey,
                                                        sidebarAccountName = sidebarAccountName,
                                                        sidebarAccountUsername = sidebarAccountUsername,
                                                        avatarRepository = avatarRepository,
                                                        accountsSectionExpanded = accountsSectionExpanded,
                                                        onAccountsSectionExpandedChange = { accountsSectionExpanded = it },
                                                        onProfileClick = {
                                                                scope.launch {
                                                                        accountsSectionExpanded = false
                                                                        drawerState.close()
                                                                        kotlinx.coroutines.delay(150)
                                                                        onProfileClick()
                                                                }
                                                        },
                                                        onCurrentAccountLongPress = {
                                                                hapticFeedback.performHapticFeedback(
                                                                        HapticFeedbackType.LongPress
                                                                )
                                                                accountToDelete =
                                                                        allAccounts.firstOrNull {
                                                                                it.publicKey == accountPublicKey
                                                                        }
                                                        },
                                                        onSwitchAccount = { publicKey ->
                                                                scope.launch {
                                                                        accountsSectionExpanded = false
                                                                        drawerState.close()
                                                                        kotlinx.coroutines.delay(150)
                                                                        onSwitchAccount(publicKey)
                                                                }
                                                        },
                                                        onAccountLongPress = { account ->
                                                                hapticFeedback.performHapticFeedback(
                                                                        HapticFeedbackType.LongPress
                                                                )
                                                                accountToDelete = account
                                                        },
                                                        onAddAccountClick = {
                                                                scope.launch {
                                                                        drawerState.close()
                                                                        kotlinx.coroutines.delay(150)
                                                                        onAddAccount()
                                                                }
                                                        },
                                                        onThemeToggleClick = { startThemeReveal() },
                                                        onThemeToggleCenterChanged = { center ->
                                                                themeToggleCenterInRoot = center
                                                        }
                                                )

                                                // ═══════════════════════════════════════════════════════════
                                                // 📱 MENU ITEMS
                                                // ═══════════════════════════════════════════════════════════
                                                DrawerContent(
                                                        isDarkTheme = isDarkTheme,
                                                        visibleTopLevelRequestsCount = visibleTopLevelRequestsCount,
                                                        onProfileClick = {
                                                                scope.launch {
                                                                        drawerState.close()
                                                                        kotlinx.coroutines.delay(100)
                                                                        onProfileClick()
                                                                }
                                                        },
                                                        onRequestsClick = {
                                                                scope.launch {
                                                                        drawerState.close()
                                                                        kotlinx.coroutines.delay(100)
                                                                        setInlineRequestsVisible(true)
                                                                }
                                                        },
                                                        onCallsClick = {
                                                                scope.launch {
                                                                        drawerState.close()
                                                                        kotlinx.coroutines.delay(100)
                                                                        setInlineCallsVisible(true)
                                                                        onCallsClick()
                                                                }
                                                        },
                                                        onNewGroupClick = {
                                                                scope.launch {
                                                                        drawerState.close()
                                                                        kotlinx.coroutines.delay(100)
                                                                        onNewGroupClick()
                                                                }
                                                        },
                                                        onQrScanClick = {
                                                                scope.launch {
                                                                        drawerState.close()
                                                                        kotlinx.coroutines.delay(100)
                                                                        onQrScanClick()
                                                                }
                                                        },
                                                        onSavedMessagesClick = {
                                                                scope.launch {
                                                                        drawerState.close()
                                                                        kotlinx.coroutines.delay(250)
                                                                        onSavedMessagesClick()
                                                                }
                                                        },
                                                        onSettingsClick = {
                                                                scope.launch {
                                                                        drawerState.close()
                                                                        kotlinx.coroutines.delay(100)
                                                                        onSettingsClick()
                                                                }
                                                        }
                                                )

                                                // ═══════════════════════════════════════════════════════════
                                                // FOOTER - Version + Update Banner
                                                // ═══════════════════════════════════════════════════════════
                                                ChatsDrawerFooter(
                                                        isDarkTheme = isDarkTheme,
                                                        appVersion = BuildConfig.VERSION_NAME,
                                                        updateState = sduUpdateState,
                                                        onUpdateClick = { update ->
                                                                when (update) {
                                                                        is UpdateState.UpdateAvailable ->
                                                                                UpdateManager.downloadAndInstall(context)
                                                                        is UpdateState.Downloading ->
                                                                                UpdateManager.cancelDownload()
                                                                        is UpdateState.ReadyToInstall ->
                                                                                UpdateManager.downloadAndInstall(context)
                                                                        else -> {}
                                                                }
                                                        }
                                                )
                                        }
                                }
                        }
                ) {
                    // ═══════════════════════════════════════════════════════════
                    // Telegram-style scale animation: main content shrinks when drawer opens
                    // ═══════════════════════════════════════════════════════════
                    val drawerWidthPx = with(LocalDensity.current) { 300.dp.toPx() }
                    val translateXPx = with(LocalDensity.current) { 4.dp.toPx() }
                    val density = LocalDensity.current

                    Box(
                        modifier = Modifier
                            .fillMaxSize()
                            .background(backgroundColor)
                            .graphicsLayer {
                                @Suppress("DEPRECATION")
                                val offset = drawerState.offset.value
                                val progress = if (offset.isNaN()) 0f
                                    else ((drawerWidthPx + offset) / drawerWidthPx).coerceIn(0f, 1f)

                                if (progress > 0.001f) {
                                    val s = 1f - 0.07f * progress
                                    scaleX = s
                                    scaleY = s
                                    translationX = translateXPx * progress
                                    transformOrigin = androidx.compose.ui.graphics.TransformOrigin(1f, 0f)
                                    val cornerPx = with(density) { (16.dp * progress).toPx() }
                                    shape = RoundedCornerShape(cornerPx)
                                    clip = true
                                    compositingStrategy = CompositingStrategy.Offscreen
                                }
                            }
                    ) {
                        Scaffold(
                                topBar = {
                                        key(
                                                isDarkTheme,
                                                showRequestsScreen,
                                                showCallsScreen,
                                                showDownloadsScreen,
                                                isSelectionMode
                                        ) {
                                                Crossfade(
                                                        targetState = isSelectionMode,
                                                        animationSpec = tween(200),
                                                        label = "headerCrossfade"
                                                ) { inSelection ->
                                                        if (inSelection) {
                                                                // ═══ SELECTION MODE HEADER ═══
                                                                TopAppBar(
                                                                        navigationIcon = {
                                                                                IconButton(onClick = { selectedChatKeys = emptySet() }) {
                                                                                        Icon(
                                                                                                painter = TelegramIcons.Close,
                                                                                                contentDescription = "Close",
                                                                                                tint = Color.White
                                                                                        )
                                                                                }
                                                                        },
                                                                        title = {
                                                                                Text(
                                                                                        "${selectedChatKeys.size}",
                                                                                        fontWeight = FontWeight.Bold,
                                                                                        fontSize = 20.sp,
                                                                                        color = Color.White
                                                                                )
                                                                        },
                                                                        actions = {
                                                                                // Mute / Unmute
                                                                                val allMuted = selectedChatKeys.all { mutedChats.contains(it) }
                                                                                IconButton(onClick = {
                                                                                        val keys = selectedChatKeys.toSet()
                                                                                        selectedChatKeys = emptySet()
                                                                                        scope.launch {
                                                                                                keys.forEach { key ->
                                                                                                        preferencesManager.setChatMuted(accountPublicKey, key, !allMuted)
                                                                                                }
                                                                                        }
                                                                                }) {
                                                                                        Icon(
                                                                                                painter = if (allMuted) TelegramIcons.Notifications else TelegramIcons.Mute,
                                                                                                contentDescription = if (allMuted) "Unmute" else "Mute",
                                                                                                tint = Color.White
                                                                                        )
                                                                                }

                                                                                // Delete
                                                                                IconButton(onClick = {
                                                                                        val allDialogs = topLevelChatsState.dialogs
                                                                                        val selected = allDialogs.filter { selectedChatKeys.contains(it.opponentKey) }
                                                                                        if (selected.isNotEmpty()) dialogsToDelete = selected
                                                                                        selectedChatKeys = emptySet()
                                                                                }) {
                                                                                        Icon(
                                                                                                painter = TelegramIcons.Delete,
                                                                                                contentDescription = "Delete",
                                                                                                tint = Color.White
                                                                                        )
                                                                                }

                                                                                // Three dots menu
                                                                                Box {
                                                                                        IconButton(onClick = { showSelectionMenu = true }) {
                                                                                                Icon(
                                                                                                        painter = TelegramIcons.More,
                                                                                                        contentDescription = "More",
                                                                                                        tint = Color.White
                                                                                                )
                                                                                        }
                                                                                        DropdownMenu(
                                                                                                expanded = showSelectionMenu,
                                                                                                onDismissRequest = { showSelectionMenu = false },
                                                                                                modifier = Modifier.background(if (isDarkTheme) Color(0xFF2C2C2E) else Color.White)
                                                                                        ) {
                                                                                                // Pin / Unpin
                                                                                                val allPinned = selectedChatKeys.all { pinnedChats.contains(it) }
                                                                                                DropdownMenuItem(
                                                                                                        text = {
                                                                                                                Text(
                                                                                                                        if (allPinned) "Unpin" else "Pin",
                                                                                                                        color = if (isDarkTheme) Color.White else Color.Black
                                                                                                                )
                                                                                                        },
                                                                                                        onClick = {
                                                                                                                selectedChatKeys.forEach { onTogglePin(it) }
                                                                                                                showSelectionMenu = false
                                                                                                                selectedChatKeys = emptySet()
                                                                                                        },
                                                                                                        leadingIcon = {
                                                                                                                Icon(
                                                                                                                        painter = if (allPinned) TelegramIcons.Unpin else TelegramIcons.Pin,
                                                                                                                        contentDescription = null,
                                                                                                                        tint = if (isDarkTheme) Color.White else Color.Black
                                                                                                                )
                                                                                                        }
                                                                                                )
                                                                                                // Block
                                                                                                val anyBlocked = selectedChatKeys.any { blockedUsers.contains(it) }
                                                                                                DropdownMenuItem(
                                                                                                        text = {
                                                                                                                Text(
                                                                                                                        if (anyBlocked) "Unblock" else "Block",
                                                                                                                        color = Color(0xFFE53935)
                                                                                                                )
                                                                                                        },
                                                                                                        onClick = {
                                                                                                                val allDialogs = topLevelChatsState.dialogs
                                                                                                                val first = selectedChatKeys.firstOrNull()
                                                                                                                val dlg = allDialogs.find { it.opponentKey == first }
                                                                                                                if (dlg != null) {
                                                                                                                        if (anyBlocked) dialogToUnblock = dlg
                                                                                                                        else dialogToBlock = dlg
                                                                                                                }
                                                                                                                showSelectionMenu = false
                                                                                                                selectedChatKeys = emptySet()
                                                                                                        },
                                                                                                        leadingIcon = {
                                                                                                                Icon(
                                                                                                                        painter = TelegramIcons.Block,
                                                                                                                        contentDescription = null,
                                                                                                                        tint = Color(0xFFE53935)
                                                                                                                )
                                                                                                        }
                                                                                                )
                                                                                        }
                                                                                }
                                                                        },
                                                                        colors = TopAppBarDefaults.topAppBarColors(
                                                                                containerColor = if (isDarkTheme) Color(0xFF2A2A2A) else Color(0xFF228BE6),
                                                                                scrolledContainerColor = if (isDarkTheme) Color(0xFF2A2A2A) else Color(0xFF228BE6),
                                                                                navigationIconContentColor = Color.White,
                                                                                titleContentColor = Color.White,
                                                                                actionIconContentColor = Color.White
                                                                        )
                                                                )
                                                        } else {
                                                                // ═══ NORMAL HEADER ═══
                                                                TopAppBar(
                                                        navigationIcon = {
                                                                if (showRequestsScreen || showDownloadsScreen || showCallsScreen) {
                                                                        IconButton(
                                                                                onClick = {
                                                                                        if (showDownloadsScreen) {
                                                                                                showDownloadsScreen = false
                                                                                        } else if (showCallsScreen) {
                                                                                                setInlineCallsVisible(
                                                                                                        false
                                                                                                )
                                                                                        } else {
                                                                                                setInlineRequestsVisible(
                                                                                                        false
                                                                                                )
                                                                                        }
                                                                                }
                                                                        ) {
                                                                                Icon(
                                                                                        TablerIcons
                                                                                                .ChevronLeft,
                                                                                        contentDescription =
                                                                                                "Back",
                                                                                        tint =
                                                                                                Color.White
                                                                                )
                                                                        }
                                                                } else {
                                                                        IconButton(
                                                                                onClick = {
                                                                                        scope
                                                                                                .launch {
                                                                                                        drawerState
                                                                                                                .open()
                                                                                                }
                                                                                }
                                                                        ) {
                                                                                Box {
                                                                                        Icon(
                                                                                                TablerIcons
                                                                                                        .Menu2,
                                                                                                contentDescription =
                                                                                                        "Menu",
                                                                                                tint =
                                                                                                        Color.White
                                                                                        )
                                                                                        // Badge с числом запросов
                                                                                        androidx.compose.animation.AnimatedVisibility(
                                                                                                visible = visibleTopLevelRequestsCount > 0,
                                                                                                enter = scaleIn(
                                                                                                        animationSpec = spring(
                                                                                                                dampingRatio = Spring.DampingRatioMediumBouncy,
                                                                                                                stiffness = Spring.StiffnessMedium
                                                                                                        )
                                                                                                ) + fadeIn(),
                                                                                                exit = scaleOut() + fadeOut(),
                                                                                                modifier = Modifier.align(Alignment.TopEnd)
                                                                                        ) {
                                                                                                val badgeText = remember(visibleTopLevelRequestsCount) {
                                                                                                        when {
                                                                                                                visibleTopLevelRequestsCount > 99 -> "99+"
                                                                                                                else -> visibleTopLevelRequestsCount.toString()
                                                                                                        }
                                                                                                }
                                                                                                val badgeBg = Color.White
                                                                                                val badgeTextColor =
                                                                                                        if (isDarkTheme) Color(0xFF2A2A2A) else Color(0xFF228BE6)
                                                                                                val badgeShape = RoundedCornerShape(50)
                                                                                                Box(
                                                                                                        modifier = Modifier
                                                                                                                .offset(x = 6.dp, y = (-6).dp)
                                                                                                                .defaultMinSize(minWidth = 20.dp, minHeight = 20.dp)
                                                                                                                .clip(badgeShape)
                                                                                                                .background(
                                                                                                                        color = if (isDarkTheme) Color(0xFF2A2A2A) else Color(0xFF228BE6)
                                                                                                                )
                                                                                                                .padding(2.dp)
                                                                                                                .clip(badgeShape)
                                                                                                                .background(color = badgeBg),
                                                                                                        contentAlignment = Alignment.Center
                                                                                                ) {
                                                                                                        Text(
                                                                                                                text = badgeText,
                                                                                                                fontSize = 10.sp,
                                                                                                                fontWeight = FontWeight.Bold,
                                                                                                                color = badgeTextColor,
                                                                                                                lineHeight = 10.sp,
                                                                                                                modifier = Modifier.padding(horizontal = 4.dp, vertical = 2.dp)
                                                                                                        )
                                                                                                }
                                                                                        }
                                                                                }
                                                                        }
                                                                }
                                                        },
                                                        title = {
                                                                if (showDownloadsScreen) {
                                                                        Text(
                                                                                "Downloads",
                                                                                fontWeight = FontWeight.Bold,
                                                                                fontSize = 20.sp,
                                                                                color = Color.White
                                                                        )
                                                                } else if (showCallsScreen) {
                                                                        Text(
                                                                                "Calls",
                                                                                fontWeight = FontWeight.Bold,
                                                                                fontSize = 20.sp,
                                                                                color = Color.White
                                                                        )
                                                                } else if (showRequestsScreen) {
                                                                        Text(
                                                                                "Requests",
                                                                                fontWeight =
                                                                                        FontWeight
                                                                                                .Bold,
                                                                                fontSize = 20.sp,
                                                                                color = Color.White
                                                                        )
                                                                } else {
                                                                        if (protocolState != ProtocolState.AUTHENTICATED) {
                                                                                AnimatedDotsText(
                                                                                        baseText = "Connecting",
                                                                                        color = Color.White,
                                                                                        fontSize = 20.sp,
                                                                                        fontWeight = FontWeight.Bold
                                                                                )
                                                                        } else if (syncInProgress) {
                                                                                AnimatedDotsText(
                                                                                        baseText = "Synchronizing",
                                                                                        fontWeight = FontWeight.Bold,
                                                                                        fontSize = 20.sp,
                                                                                        color = Color.White
                                                                                )
                                                                        } else {
                                                                                Text(
                                                                                        "Rosetta",
                                                                                        fontWeight =
                                                                                                FontWeight
                                                                                                        .Bold,
                                                                                        fontSize =
                                                                                                20.sp,
                                                                                        color =
                                                                                                Color.White
                                                                                )
                                                                        }
                                                                }
                                                        },
                                                        actions = {
                                                                if (showCallsScreen) {
                                                                        Box {
                                                                                IconButton(
                                                                                        onClick = {
                                                                                                showCallsMenu = true
                                                                                        }
                                                                                ) {
                                                                                        Icon(
                                                                                                TablerIcons.DotsVertical,
                                                                                                contentDescription = "Calls menu",
                                                                                                tint = Color.White
                                                                                        )
                                                                                }
                                                                                DropdownMenu(
                                                                                        expanded = showCallsMenu,
                                                                                        onDismissRequest = {
                                                                                                showCallsMenu = false
                                                                                        },
                                                                                        modifier = Modifier.background(
                                                                                                if (isDarkTheme) Color(0xFF2C2C2E) else Color.White
                                                                                        )
                                                                                ) {
                                                                                        DropdownMenuItem(
                                                                                                text = {
                                                                                                        Text(
                                                                                                                "Delete all calls",
                                                                                                                color = if (isDarkTheme) Color.White else Color.Black
                                                                                                        )
                                                                                                },
                                                                                                onClick = {
                                                                                                        showCallsMenu = false
                                                                                                        showDeleteCallsDialog = true
                                                                                                },
                                                                                                leadingIcon = {
                                                                                                        Icon(
                                                                                                                imageVector = TablerIcons.Trash,
                                                                                                                contentDescription = null,
                                                                                                                tint = Color(0xFFE55A5A)
                                                                                                        )
                                                                                                }
                                                                                        )
                                                                                }
                                                                        }
                                                                } else if (!showRequestsScreen && !showDownloadsScreen) {
                                                                        // 📥 Animated download indicator (Telegram-style)
                                                                        Box(
                                                                                modifier =
                                                                                        androidx.compose.ui.Modifier
                                                                                                .size(48.dp)
                                                                                                .clickable(
                                                                                                        enabled = hasActiveDownloads,
                                                                                                        onClick = {
                                                                                                                showDownloadsScreen = true
                                                                                                        }
                                                                                                ),
                                                                                contentAlignment = Alignment.Center
                                                                        ) {
                                                                                com.rosetta.messenger.ui.components.AnimatedDownloadIndicator(
                                                                                        isActive = hasActiveDownloads,
                                                                                        color = Color.White
                                                                                )
                                                                        }
                                                                        IconButton(
                                                                                onClick = {
                                                                                        if (protocolState ==
                                                                                                        ProtocolState
                                                                                                                .AUTHENTICATED
                                                                                        ) {
                                                                                                onSearchClick()
                                                                                        }
                                                                                },
                                                                                enabled =
                                                                                        protocolState ==
                                                                                                ProtocolState
                                                                                                        .AUTHENTICATED
                                                                        ) {
                                                                                Icon(
                                                                                        TablerIcons
                                                                                                .Search,
                                                                                        contentDescription =
                                                                                                "Search",
                                                                                        tint =
                                                                                                if (protocolState ==
                                                                                                                ProtocolState
                                                                                                                        .AUTHENTICATED
                                                                                                )
                                                                                                        Color.White
                                                                                                else
                                                                                                        Color.White
                                                                                                                .copy(
                                                                                                                        alpha =
                                                                                                                                0.5f
                                                                                                                )
                                                                                )
                                                                        }
                                                                }
                                                        },
                                                        colors =
                                                                TopAppBarDefaults.topAppBarColors(
                                                                        containerColor =
                                                                                if (isDarkTheme) Color(0xFF2A2A2A) else Color(0xFF228BE6),
                                                                        scrolledContainerColor =
                                                                                if (isDarkTheme) Color(0xFF2A2A2A) else Color(0xFF228BE6),
                                                                        navigationIconContentColor =
                                                                                Color.White,
                                                                        titleContentColor =
                                                                                Color.White,
                                                                        actionIconContentColor =
                                                                                Color.White
                                                                )
                                                )
                                                        } // end else normal header
                                                } // end Crossfade
                                        }
                                },
                                floatingActionButton = {
                                        AnimatedVisibility(
                                                visible = false, // Hidden for now
                                                enter =
                                                        fadeIn(tween(500, delayMillis = 300)) +
                                                                scaleIn(
                                                                        initialScale = 0.5f,
                                                                        animationSpec =
                                                                                tween(
                                                                                        500,
                                                                                        delayMillis =
                                                                                                300
                                                                                )
                                                                )
                                        ) {
                                                FloatingActionButton(
                                                        onClick = onNewChat,
                                                        containerColor = PrimaryBlue,
                                                        contentColor = Color.White,
                                                        shape = CircleShape
                                                ) {
                                                        Icon(
                                                                painter = TelegramIcons.Edit,
                                                                contentDescription = "New Chat"
                                                        )
                                                }
                                        }
                                },
                                containerColor = backgroundColor
                        ) { paddingValues ->
                                // Main content
                                Box(
                                        modifier =
                                                Modifier.fillMaxSize()
                                                        .background(backgroundColor)
                                                        .padding(paddingValues)
                                ) {
                                        // � Используем комбинированное состояние для атомарного
                                        // обновления
                                        // Это предотвращает "дергание" UI когда dialogs и requests
                                        // обновляются
                                        // независимо
                                        val chatsState = topLevelChatsState
                                        val isLoading = topLevelIsLoading
                                        val hideRequests = syncInProgress || protocolState != ProtocolState.AUTHENTICATED
                                        val requests = if (hideRequests) emptyList() else chatsState.requests
                                        val requestsCount = if (hideRequests) 0 else chatsState.requestsCount

                                        val showSkeleton by
                                                produceState(
                                                        initialValue = false,
                                                        key1 = isLoading
                                                ) {
                                                        if (!isLoading) {
                                                                value = false
                                                                return@produceState
                                                        }
                                                        delay(SKELETON_VISIBILITY_DELAY_MS)
                                                        value = isLoading
                                                }
                                        val chatListState = rememberLazyListState()
                                        var isRequestsVisible by remember { mutableStateOf(true) }
                                        var requestsPullProgress by remember { mutableStateOf(0f) }
                                        var lastAutoScrolledVerificationId by remember {
                                                mutableStateOf<String?>(null)
                                        }
                                        val localDensity = LocalDensity.current
                                        val requestsRevealThresholdPx =
                                                remember(localDensity) { with(localDensity) { 28.dp.toPx() } }
                                        val requestsHideThresholdPx =
                                                remember(localDensity) { with(localDensity) { 16.dp.toPx() } }

                                        AnimatedContent(
                                                targetState = showDownloadsScreen,
                                                transitionSpec = {
                                                        if (targetState) {
                                                                // Opening downloads: slide from right with fade
                                                                slideInHorizontally(
                                                                        animationSpec =
                                                                                tween(
                                                                                        280,
                                                                                        easing =
                                                                                                FastOutSlowInEasing
                                                                                )
                                                                ) { fullWidth ->
                                                                        fullWidth
                                                                } + fadeIn(
                                                                        animationSpec = tween(200)
                                                                ) togetherWith
                                                                        slideOutHorizontally(
                                                                                animationSpec =
                                                                                        tween(
                                                                                                280,
                                                                                                easing =
                                                                                                        FastOutSlowInEasing
                                                                                        )
                                                                        ) { fullWidth ->
                                                                                -fullWidth / 4
                                                                        } + fadeOut(
                                                                                animationSpec = tween(150)
                                                                        )
                                                        } else {
                                                                // Closing downloads: slide back to right
                                                                slideInHorizontally(
                                                                        animationSpec =
                                                                                tween(
                                                                                        280,
                                                                                        easing =
                                                                                                FastOutSlowInEasing
                                                                                )
                                                                ) { fullWidth ->
                                                                        -fullWidth / 4
                                                                } + fadeIn(
                                                                        animationSpec = tween(200)
                                                                ) togetherWith
                                                                        slideOutHorizontally(
                                                                                animationSpec =
                                                                                        tween(
                                                                                                280,
                                                                                                easing =
                                                                                                        FastOutSlowInEasing
                                                                                        )
                                                                        ) { fullWidth ->
                                                                                fullWidth
                                                                        } + fadeOut(
                                                                                animationSpec = tween(150)
                                                                        )
                                                        }
                                                },
                                                label = "DownloadsTransition"
                                        ) { isDownloadsScreen ->
                                        if (isDownloadsScreen) {
                                                FileDownloadsScreen(
                                                        downloads = activeFileDownloads,
                                                        isDarkTheme = isDarkTheme,
                                                        modifier = Modifier.fillMaxSize()
                                                )
                                        } else {
                                                // 🎬 Animated content transition between main list and
                                                // calls
                                                AnimatedContent(
                                                        targetState = showCallsScreen,
                                                        transitionSpec = {
                                                                if (targetState) {
                                                                        slideInHorizontally(
                                                                                animationSpec = tween(280, easing = FastOutSlowInEasing)
                                                                        ) { fullWidth -> fullWidth } + fadeIn(
                                                                                animationSpec = tween(200)
                                                                        ) togetherWith
                                                                                slideOutHorizontally(
                                                                                        animationSpec = tween(280, easing = FastOutSlowInEasing)
                                                                                ) { fullWidth -> -fullWidth / 4 } + fadeOut(
                                                                                        animationSpec = tween(150)
                                                                                )
                                                                } else {
                                                                        slideInHorizontally(
                                                                                animationSpec = tween(280, easing = FastOutSlowInEasing)
                                                                        ) { fullWidth -> -fullWidth / 4 } + fadeIn(
                                                                                animationSpec = tween(200)
                                                                        ) togetherWith
                                                                                slideOutHorizontally(
                                                                                        animationSpec = tween(280, easing = FastOutSlowInEasing)
                                                                                ) { fullWidth -> fullWidth } + fadeOut(
                                                                                        animationSpec = tween(150)
                                                                                )
                                                                }
                                                        },
                                                        label = "CallsTransition"
                                                ) { isCallsScreen ->
                                                if (isCallsScreen) {
                                                        CallsRouteContent(
                                                                isDarkTheme = isDarkTheme,
                                                                accountPublicKey = accountPublicKey,
                                                                avatarRepository = avatarRepository,
                                                                onUserSelect = onUserSelect,
                                                                onStartCall = onStartCall,
                                                                onStartNewCall = onSearchClick,
                                                                onBack = { setInlineCallsVisible(false) }
                                                        )
                                                } else {
                                                // 🎬 Animated content transition between main list and
                                                // requests
                                                AnimatedContent(
                                                        targetState = showRequestsScreen,
                                                        transitionSpec = {
                                                                if (targetState) {
                                                                        // Opening requests: slide in from right
                                                                        slideInHorizontally(
                                                                                animationSpec = tween(280, easing = FastOutSlowInEasing)
                                                                        ) { fullWidth -> fullWidth } + fadeIn(
                                                                                animationSpec = tween(200)
                                                                        ) togetherWith
                                                                                slideOutHorizontally(
                                                                                        animationSpec = tween(280, easing = FastOutSlowInEasing)
                                                                                ) { fullWidth -> -fullWidth / 4 } + fadeOut(
                                                                                        animationSpec = tween(150)
                                                                                )
                                                                } else {
                                                                        // Closing requests: slide out to right
                                                                        slideInHorizontally(
                                                                                animationSpec = tween(280, easing = FastOutSlowInEasing)
                                                                        ) { fullWidth -> -fullWidth / 4 } + fadeIn(
                                                                                animationSpec = tween(200)
                                                                        ) togetherWith
                                                                                slideOutHorizontally(
                                                                                        animationSpec = tween(280, easing = FastOutSlowInEasing)
                                                                                ) { fullWidth -> fullWidth } + fadeOut(
                                                                                        animationSpec = tween(150)
                                                                                )
                                                                }
                                                        },
                                                        label = "RequestsTransition"
                                                ) { isRequestsScreen ->
                                                if (isRequestsScreen) {
                                                        RequestsRouteContent(
                                                                requests = requests,
                                                                isDarkTheme = isDarkTheme,
                                                                avatarRepository = avatarRepository,
                                                                blockedUsers = blockedUsers,
                                                                pinnedChats = pinnedChats,
                                                                isDrawerOpen =
                                                                        drawerState.isOpen ||
                                                                                drawerState.isAnimationRunning,
                                                                onTogglePin = onTogglePin,
                                                                onDeleteDialog = { opponentKey ->
                                                                        scope.launch {
                                                                                chatsViewModel.deleteDialog(opponentKey)
                                                                        }
                                                                },
                                                                onBlockUser = { opponentKey ->
                                                                        scope.launch {
                                                                                chatsViewModel.blockUser(opponentKey)
                                                                        }
                                                                },
                                                                onUnblockUser = { opponentKey ->
                                                                        scope.launch {
                                                                                chatsViewModel.unblockUser(opponentKey)
                                                                        }
                                                                },
                                                                onRequestClick = { request ->
                                                                        val user =
                                                                                chatsViewModel.dialogToSearchUser(
                                                                                        request
                                                                                )
                                                                        onUserSelect(user)
                                                                },
                                                                onBack = {
                                                                        setInlineRequestsVisible(false)
                                                                }
                                                        )
                                                } else if (showSkeleton) {
                                                        ChatsListSkeleton(isDarkTheme = isDarkTheme)
                                                } else if (isLoading && chatsState.isEmpty) {
                                                        Box(modifier = Modifier.fillMaxSize())
                                                } else if (chatsState.isEmpty) {
                                                        EmptyChatsState(
                                                                isDarkTheme = isDarkTheme,
                                                                modifier = Modifier.fillMaxSize()
                                                        )
                                                } else {
                                                        // Show dialogs list
                                                        val dividerColor =
                                                                remember(isDarkTheme) {
                                                                        if (isDarkTheme)
                                                                                Color(0xFF3A3A3A)
                                                                        else Color(0xFFE8E8E8)
                                                                }
                                                        val listBackgroundColor =
                                                                remember(isDarkTheme) {
                                                                        if (isDarkTheme)
                                                                                Color(0xFF1A1A1A)
                                                                        else Color(0xFFF2F2F7)
                                                                }
                                                        val showStickyCallBanner =
                                                                remember(callUiState, isCallOverlayExpanded) {
                                                                        callUiState.isVisible &&
                                                                                !isCallOverlayExpanded &&
                                                                                callUiState.phase != CallPhase.INCOMING
                                                                }
                                                        val callBannerHeight = 40.dp
                                                        val showVoiceMiniPlayer =
                                                                remember(
                                                                        showRequestsScreen,
                                                                        showDownloadsScreen,
                                                                        showCallsScreen,
                                                                        playingVoiceAttachmentId
                                                                ) {
                                                                        !showRequestsScreen &&
                                                                                !showDownloadsScreen &&
                                                                                !showCallsScreen &&
                                                                                !playingVoiceAttachmentId.isNullOrBlank()
                                                                }
                                                        val voiceBannerHeight = 36.dp
                                                        val stickyTopInset =
                                                                remember(
                                                                        showStickyCallBanner,
                                                                        showVoiceMiniPlayer
                                                                ) {
                                                                        var topInset = 0.dp
                                                                        if (showStickyCallBanner) {
                                                                                topInset += callBannerHeight
                                                                        }
                                                                        if (showVoiceMiniPlayer) {
                                                                                topInset += voiceBannerHeight
                                                                        }
                                                                        topInset
                                                                }
                                                        val voiceMiniPlayerTitle =
                                                                remember(
                                                                        playingVoiceSenderLabel,
                                                                        playingVoiceTimeLabel
                                                                ) {
                                                                        val sender =
                                                                                playingVoiceSenderLabel
                                                                                        .trim()
                                                                                        .ifBlank {
                                                                                                "Voice"
                                                                                        }
                                                                        val time =
                                                                                playingVoiceTimeLabel
                                                                                        .trim()
                                                                        if (time.isBlank()) sender
                                                                        else "$sender at $time"
                                                                }
                                                        // 🔥 Берем dialogs из chatsState для
                                                        // консистентности
                                                        // 📌 Порядок по времени готовится в ViewModel.
                                                        // Здесь поднимаем pinned наверх без полного sort/distinct.
                                                        val currentDialogs =
                                                                remember(
                                                                        chatsState.dialogs,
                                                                        pinnedChats
                                                                ) {
                                                                        val pinned = ArrayList<DialogUiModel>()
                                                                        val regular = ArrayList<DialogUiModel>()
                                                                        chatsState.dialogs.forEach { dialog ->
                                                                                if (
                                                                                        pinnedChats.contains(
                                                                                                dialog.opponentKey
                                                                                        )
                                                                                ) {
                                                                                        pinned.add(dialog)
                                                                                } else {
                                                                                        regular.add(dialog)
                                                                                }
                                                                        }
                                                                        pinned + regular
                                                                }

                                                        // Telegram-style: only one item can be
                                                        // swiped open at a time
                                                        var swipedItemKey by remember {
                                                                mutableStateOf<String?>(null)
                                                        }

                                                        // Close swiped item when drawer opens
                                                        LaunchedEffect(drawerState.isOpen) {
                                                                if (drawerState.isOpen) {
                                                                        swipedItemKey = null
                                                                }
                                                        }

                                                        // When a new device confirmation banner appears at the top,
                                                        // smoothly bring the list to top so the banner is visible.
                                                        LaunchedEffect(pendingDeviceVerification?.deviceId) {
                                                                val verificationId =
                                                                        pendingDeviceVerification?.deviceId
                                                                if (verificationId.isNullOrBlank()) {
                                                                        lastAutoScrolledVerificationId = null
                                                                        return@LaunchedEffect
                                                                }
                                                                if (verificationId == lastAutoScrolledVerificationId) {
                                                                        return@LaunchedEffect
                                                                }

                                                                val alreadyAtTop =
                                                                        chatListState.firstVisibleItemIndex == 0 &&
                                                                                chatListState.firstVisibleItemScrollOffset <= 2
                                                                if (!alreadyAtTop) {
                                                                        chatListState.animateScrollToItem(0)
                                                                }

                                                                lastAutoScrolledVerificationId = verificationId
                                                        }

                                                        val requestsNestedScroll =
                                                                remember(
                                                                        requestsCount,
                                                                        chatListState,
                                                                        requestsRevealThresholdPx,
                                                                        requestsHideThresholdPx,
                                                                        hapticFeedback
                                                                ) {
                                                                        var accumulatedPullDown = 0f
                                                                        var accumulatedPullUp = 0f
                                                                        val pullDownLimit =
                                                                                requestsRevealThresholdPx * 1.25f
                                                                        object : androidx.compose.ui.input.nestedscroll.NestedScrollConnection {
                                                                                override fun onPreScroll(
                                                                                        available: androidx.compose.ui.geometry.Offset,
                                                                                        source: androidx.compose.ui.input.nestedscroll.NestedScrollSource
                                                                                ): androidx.compose.ui.geometry.Offset {
                                                                                        if (source != androidx.compose.ui.input.nestedscroll.NestedScrollSource.Drag ||
                                                                                                        requestsCount <= 0
                                                                                        ) {
                                                                                                accumulatedPullDown = 0f
                                                                                                accumulatedPullUp = 0f
                                                                                                requestsPullProgress = 0f
                                                                                                return androidx.compose.ui.geometry.Offset.Zero
                                                                                        }

                                                                                        val atTop = !chatListState.canScrollBackward
                                                                                        val nearTop =
                                                                                                chatListState.firstVisibleItemIndex == 0 &&
                                                                                                        chatListState.firstVisibleItemScrollOffset <=
                                                                                                                2

                                                                                        if (available.y < 0f &&
                                                                                                        isRequestsVisible &&
                                                                                                        (atTop ||
                                                                                                                nearTop)
                                                                                        ) {
                                                                                                accumulatedPullUp += -available.y
                                                                                                accumulatedPullDown = 0f
                                                                                                requestsPullProgress = 0f
                                                                                                if (accumulatedPullUp >= requestsHideThresholdPx) {
                                                                                                        isRequestsVisible = false
                                                                                                        accumulatedPullUp = 0f
                                                                                                }
                                                                                                return androidx.compose.ui.geometry.Offset(
                                                                                                        0f,
                                                                                                        available.y
                                                                                                )
                                                                                        }
                                                                                        if (available.y >= 0f) {
                                                                                                accumulatedPullUp = 0f
                                                                                        }

                                                                                        if (!isRequestsVisible && atTop) {
                                                                                                if (available.y > 0f) {
                                                                                                        accumulatedPullDown =
                                                                                                                (accumulatedPullDown + available.y)
                                                                                                                        .coerceAtMost(
                                                                                                                                pullDownLimit
                                                                                                                        )
                                                                                                        requestsPullProgress =
                                                                                                                (accumulatedPullDown / requestsRevealThresholdPx)
                                                                                                                        .coerceIn(
                                                                                                                                0f,
                                                                                                                                1.15f
                                                                                                                        )
                                                                                                        if (accumulatedPullDown >= requestsRevealThresholdPx) {
                                                                                                                isRequestsVisible = true
                                                                                                                accumulatedPullDown = 0f
                                                                                                                accumulatedPullUp = 0f
                                                                                                                requestsPullProgress = 0f
                                                                                                                hapticFeedback.performHapticFeedback(
                                                                                                                        HapticFeedbackType.LongPress
                                                                                                                )
                                                                                                        }
                                                                                                        return androidx.compose.ui.geometry.Offset(
                                                                                                                0f,
                                                                                                                available.y
                                                                                                        )
                                                                                                }

                                                                                                if (available.y < 0f &&
                                                                                                                accumulatedPullDown > 0f
                                                                                                ) {
                                                                                                        accumulatedPullDown =
                                                                                                                (accumulatedPullDown + available.y)
                                                                                                                        .coerceAtLeast(
                                                                                                                                0f
                                                                                                                        )
                                                                                                        requestsPullProgress =
                                                                                                                (accumulatedPullDown / requestsRevealThresholdPx)
                                                                                                                        .coerceIn(
                                                                                                                                0f,
                                                                                                                                1.15f
                                                                                                                        )
                                                                                                        return androidx.compose.ui.geometry.Offset(
                                                                                                                0f,
                                                                                                                available.y
                                                                                                        )
                                                                                                }
                                                                                        } else if (!isRequestsVisible && !atTop) {
                                                                                                accumulatedPullDown = 0f
                                                                                                requestsPullProgress = 0f
                                                                                        }

                                                                                        return androidx.compose.ui.geometry.Offset.Zero
                                                                                }

                                                                                override suspend fun onPreFling(
                                                                                        available: androidx.compose.ui.unit.Velocity
                                                                                ): androidx.compose.ui.unit.Velocity {
                                                                                        if (!isRequestsVisible) {
                                                                                                accumulatedPullDown = 0f
                                                                                                requestsPullProgress = 0f
                                                                                        }
                                                                                        return androidx.compose.ui.unit.Velocity.Zero
                                                                                }

                                                                                override suspend fun onPostFling(
                                                                                        consumed: androidx.compose.ui.unit.Velocity,
                                                                                        available: androidx.compose.ui.unit.Velocity
                                                                                ): androidx.compose.ui.unit.Velocity {
                                                                                        accumulatedPullDown = 0f
                                                                                        accumulatedPullUp = 0f
                                                                                        requestsPullProgress = 0f
                                                                                        return androidx.compose.ui.unit.Velocity.Zero
                                                                                }
                                                                        }
                                                                }

                                                        Box(
                                                                modifier =
                                                                        Modifier.fillMaxSize()
                                                                                .background(listBackgroundColor)
                                                        ) {
                                                        LazyColumn(
                                                                state = chatListState,
                                                                modifier =
                                                                        Modifier.fillMaxSize()
                                                                                .padding(
                                                                                        top =
                                                                                                stickyTopInset
                                                                                )
                                                                                .then(
                                                                                        if (requestsCount > 0) Modifier.nestedScroll(requestsNestedScroll)
                                                                                        else Modifier
                                                                                )
                                                                                .background(
                                                                                        listBackgroundColor
                                                                                )
                                                        ) {
                                                                pendingDeviceVerification?.let { pendingDevice ->
                                                                        item(key = "device_verification_banner_${pendingDevice.deviceId}") {
                                                                                Column {
                                                                                        DeviceVerificationBanner(
                                                                                                device = pendingDevice,
                                                                                                isDarkTheme = isDarkTheme,
                                                                                                onAccept = {
                                                                                                        deviceResolveRequest =
                                                                                                                pendingDevice to
                                                                                                                        DeviceResolveAction.ACCEPT
                                                                                                },
                                                                                                onDecline = {
                                                                                                        deviceResolveRequest =
                                                                                                                pendingDevice to
                                                                                                                        DeviceResolveAction.DECLINE
                                                                                                }
                                                                                        )
                                                                                        Divider(
                                                                                                color = dividerColor,
                                                                                                thickness = 0.5.dp
                                                                                        )
                                                                                }
                                                                        }
                                                                }

                                                                if (requestsCount > 0) {
                                                                        item(key = "requests_section") {
                                                                                val requestsSectionProgress by
                                                                                        animateFloatAsState(
                                                                                                targetValue =
                                                                                                        if (isRequestsVisible) 1f
                                                                                                        else requestsPullProgress,
                                                                                                animationSpec =
                                                                                                        spring(
                                                                                                                dampingRatio =
                                                                                                                        Spring.DampingRatioNoBouncy,
                                                                                                                stiffness =
                                                                                                                        Spring.StiffnessMediumLow
                                                                                                        ),
                                                                                                label =
                                                                                                        "requestsSectionProgress"
                                                                                        )
                                                                                val clampedProgress =
                                                                                        requestsSectionProgress
                                                                                                .coerceIn(
                                                                                                        0f,
                                                                                                        1.15f
                                                                                                )
                                                                                val revealProgress =
                                                                                        FastOutSlowInEasing
                                                                                                .transform(
                                                                                                        clampedProgress
                                                                                                                .coerceIn(
                                                                                                                        0f,
                                                                                                                        1f
                                                                                                                )
                                                                                                )
                                                                                val stretchOvershoot =
                                                                                        (clampedProgress - 1f)
                                                                                                .coerceAtLeast(
                                                                                                        0f
                                                                                                )
                                                                                val sectionHeight =
                                                                                        76.dp *
                                                                                                revealProgress +
                                                                                                10.dp *
                                                                                                        stretchOvershoot
                                                                                val sectionAlpha =
                                                                                        (0.55f + revealProgress * 0.45f)
                                                                                                .coerceIn(
                                                                                                        0f,
                                                                                                        1f
                                                                                                )

                                                                                if (isRequestsVisible ||
                                                                                                sectionHeight > 0.5.dp
                                                                                ) {
                                                                                        Column {
                                                                                                Box(
                                                                                                        modifier =
                                                                                                                Modifier.fillMaxWidth()
                                                                                                                        .height(
                                                                                                                                sectionHeight
                                                                                                                        )
                                                                                                                        .clipToBounds()
                                                                                                                        .graphicsLayer {
                                                                                                                                alpha =
                                                                                                                                        if (isRequestsVisible)
                                                                                                                                                1f
                                                                                                                                        else sectionAlpha
                                                                                                                        }
                                                                                                ) {
                                                                                                        RequestsSection(
                                                                                                                count =
                                                                                                                        requestsCount,
                                                                                                                requests =
                                                                                                                        requests,
                                                                                                                isDarkTheme =
                                                                                                                        isDarkTheme,
                                                                                                                onClick = {
                                                                                                                        isRequestsVisible =
                                                                                                                                true
                                                                                                                        requestsPullProgress =
                                                                                                                                0f
                                                                                                                        openRequestsRouteSafely()
                                                                                                                }
                                                                                                        )
                                                                                                }
                                                                                                Divider(
                                                                                                        color =
                                                                                                                dividerColor,
                                                                                                        thickness =
                                                                                                                0.5.dp
                                                                                                )
                                                                                        }
                                                                                }
                                                                        }
                                                                }

                                                                items(
                                                                        items = currentDialogs,
                                                                        key = { dialog ->
                                                                                dialog.opponentKey
                                                                        },
                                                                        contentType = { _ ->
                                                                                "dialog"
                                                                        }
                                                                ) { dialog ->
                                                                        val isSavedMessages =
                                                                                dialog.opponentKey ==
                                                                                        accountPublicKey
                                                                        val isPinnedDialog =
                                                                                pinnedChats
                                                                                        .contains(
                                                                                                dialog.opponentKey
                                                                                        )
                                                                        val isSystemSafeDialog =
                                                                                MessageRepository.isSystemAccount(dialog.opponentKey)
                                                                        val isBlocked =
                                                                                blockedUsers
                                                                                        .contains(
                                                                                                dialog.opponentKey
                                                                                        )
                                                                        val isGroupDialog =
                                                                                isGroupDialogKey(
                                                                                        dialog.opponentKey
                                                                                )
                                                                        val isTyping by
                                                                                remember(
                                                                                        dialog.opponentKey,
                                                                                        typingUsers
                                                                                ) {
                                                                                        derivedStateOf {
                                                                                                isTypingForDialog(
                                                                                                        dialog.opponentKey,
                                                                                                        typingUsers
                                                                                                )
                                                                                        }
                                                                                }
                                                                        val typingGroupUsers by
                                                                                remember(
                                                                                        dialog.opponentKey,
                                                                                        typingUsersByDialogSnapshot
                                                                                ) {
                                                                                        derivedStateOf {
                                                                                                if (!isGroupDialog) {
                                                                                                        emptySet()
                                                                                                } else {
                                                                                                        val normalizedDialogKey =
                                                                                                                normalizeGroupDialogKey(
                                                                                                                        dialog.opponentKey
                                                                                                                )
                                                                                                        typingUsersByDialogSnapshot[normalizedDialogKey]
                                                                                                                ?: emptySet()
                                                                                                }
                                                                                        }
                                                                                }
                                                                        val typingSenderPublicKey by
                                                                                remember(
                                                                                        isGroupDialog,
                                                                                        typingGroupUsers
                                                                                ) {
                                                                                        derivedStateOf {
                                                                                                if (!isGroupDialog) {
                                                                                                        ""
                                                                                                } else {
                                                                                                        typingGroupUsers.firstOrNull().orEmpty()
                                                                                                }
                                                                                        }
                                                                                }
                                                                        val typingDisplayName by
                                                                                remember(
                                                                                        isGroupDialog,
                                                                                        typingSenderPublicKey,
                                                                                        typingGroupUsers
                                                                                                .size
                                                                                ) {
                                                                                        derivedStateOf {
                                                                                                if (!isGroupDialog ||
                                                                                                                typingSenderPublicKey.isBlank()
                                                                                                ) {
                                                                                                        ""
                                                                                                } else {
                                                                                                        val baseName =
                                                                                                                resolveTypingDisplayName(
                                                                                                                        protocolGateway,
                                                                                                                        typingSenderPublicKey
                                                                                                                )
                                                                                                        if (baseName.isBlank()) {
                                                                                                                ""
                                                                                                        } else {
                                                                                                                val extraCount =
                                                                                                                        (typingGroupUsers
                                                                                                                                                .size -
                                                                                                                                        1)
                                                                                                                                .coerceAtLeast(
                                                                                                                                        0
                                                                                                                                )
                                                                                                                if (extraCount >
                                                                                                                                0
                                                                                                                ) {
                                                                                                                        "$baseName and $extraCount"
                                                                                                                } else {
                                                                                                                        baseName
                                                                                                                }
                                                                                                        }
                                                                                                }
                                                                                        }
                                                                                }
                                                                        val isVoicePlaybackActive by
                                                                                remember(
                                                                                        dialog.opponentKey,
                                                                                        playingVoiceDialogKey
                                                                                ) {
                                                                                        derivedStateOf {
                                                                                                isVoicePlayingForDialog(
                                                                                                        dialog.opponentKey,
                                                                                                        playingVoiceDialogKey
                                                                                                )
                                                                                        }
                                                                                }
                                                                        val isSelectedDialog =
                                                                                selectedChatKeys
                                                                                        .contains(
                                                                                                dialog.opponentKey
                                                                                        )
                                                                        val dividerBackgroundColor =
                                                                                when {
                                                                                        isSelectedDialog ->
                                                                                                if (isDarkTheme)
                                                                                                        Color(
                                                                                                                0xFF1A3A5C
                                                                                                        )
                                                                                                else
                                                                                                        Color(
                                                                                                                0xFFD6EAFF
                                                                                                        )
                                                                                        isPinnedDialog ->
                                                                                                if (isDarkTheme)
                                                                                                        Color(
                                                                                                                0xFF232323
                                                                                                        )
                                                                                                else
                                                                                                        Color(
                                                                                                                0xFFE8E8ED
                                                                                                        )
                                                                                        else ->
                                                                                                listBackgroundColor
                                                                                }

                                                                        Column {
                                                                                SwipeableDialogItem(
                                                                                        dialog =
                                                                                                dialog,
                                                                                        isDarkTheme =
                                                                                                isDarkTheme,
                                                                                        isTyping =
                                                                                                isTyping,
                                                                                        typingDisplayName =
                                                                                                typingDisplayName,
                                                                                        typingSenderPublicKey =
                                                                                                typingSenderPublicKey,
                                                                                        isVoicePlaybackActive =
                                                                                                isVoicePlaybackActive,
                                                                                        isBlocked =
                                                                                                isBlocked,
                                                                                        isSavedMessages =
                                                                                                isSavedMessages,
                                                                                        isMuted =
                                                                                                mutedChats.contains(dialog.opponentKey),
                                                                                        avatarRepository =
                                                                                                avatarRepository,
                                                                                        isDrawerOpen =
                                                                                                drawerState
                                                                                                        .isOpen ||
                                                                                                        drawerState
                                                                                                                .isAnimationRunning,
                                                                                        isSwipedOpen =
                                                                                                swipedItemKey ==
                                                                                                        dialog.opponentKey,
                                                                                        isSelected =
                                                                                                isSelectedDialog,
                                                                                        syncInProgress =
                                                                                                syncInProgress,
                                                                                        onSwipeStarted = {
                                                                                                swipedItemKey =
                                                                                                        dialog.opponentKey
                                                                                        },
                                                                                        onSwipeClosed = {
                                                                                                if (swipedItemKey ==
                                                                                                                dialog.opponentKey
                                                                                                )
                                                                                                        swipedItemKey =
                                                                                                                null
                                                                                        },
                                                                                        onClick = {
                                                                                                if (isSelectionMode) {
                                                                                                        // Toggle selection
                                                                                                        selectedChatKeys = if (selectedChatKeys.contains(dialog.opponentKey))
                                                                                                                selectedChatKeys - dialog.opponentKey
                                                                                                        else
                                                                                                                selectedChatKeys + dialog.opponentKey
                                                                                                } else {
                                                                                                        swipedItemKey =
                                                                                                                null
                                                                                                        val user =
                                                                                                                chatsViewModel
                                                                                                                        .dialogToSearchUser(
                                                                                                                                dialog
                                                                                                                        )
                                                                                                        onUserSelect(
                                                                                                                user
                                                                                                        )
                                                                                                }
                                                                                        },
                                                                                        onLongClick = {
                                                                                                hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
                                                                                                selectedChatKeys = if (selectedChatKeys.contains(dialog.opponentKey))
                                                                                                        selectedChatKeys - dialog.opponentKey
                                                                                                else
                                                                                                        selectedChatKeys + dialog.opponentKey
                                                                                        },
                                                                                        onDelete = {
                                                                                                dialogsToDelete =
                                                                                                        listOf(dialog)
                                                                                        },
                                                                                        onLeave = {
                                                                                                dialogToLeave =
                                                                                                        dialog
                                                                                        },
                                                                                        onBlock = {
                                                                                                dialogToBlock =
                                                                                                        dialog
                                                                                        },
                                                                                        onUnblock = {
                                                                                                dialogToUnblock =
                                                                                                        dialog
                                                                                        },
                                                                                        isGroupChat =
                                                                                                isGroupDialog,
                                                                                        isPinned =
                                                                                                isPinnedDialog,
                                                                                        swipeEnabled =
                                                                                                !isSystemSafeDialog,
                                                                                        onPin = {
                                                                                                onTogglePin(
                                                                                                        dialog.opponentKey
                                                                                                )
                                                                                        }
                                                                                )

                                                                                // 🔥 СЕПАРАТОР -
                                                                                // линия разделения
                                                                                // между диалогами
                                                                                Box(
                                                                                        modifier =
                                                                                                Modifier.fillMaxWidth()
                                                                                                        .height(
                                                                                                                0.5.dp
                                                                                                        )
                                                                                                        .background(
                                                                                                                dividerBackgroundColor
                                                                                                        )
                                                                                ) {
                                                                                        Divider(
                                                                                                modifier =
                                                                                                        Modifier.fillMaxWidth()
                                                                                                                .padding(
                                                                                                                        start =
                                                                                                                                TELEGRAM_DIALOG_TEXT_START
                                                                                                                ),
                                                                                                color =
                                                                                                        dividerColor,
                                                                                                thickness =
                                                                                                        0.5.dp
                                                                                        )
                                                                                }
                                                                        }
                                                                }

                                                                // Footer hint
                                                                item(key = "chat_list_footer") {
                                                                        Box(
                                                                                modifier = Modifier
                                                                                        .fillMaxWidth()
                                                                                        .padding(vertical = 24.dp),
                                                                                contentAlignment = Alignment.Center
                                                                        ) {
                                                                                Text(
                                                                                        text = "Tap on search to find new chats",
                                                                                        color = Color(0xFF8E8E93),
                                                                                        fontSize = 14.sp,
                                                                                        fontWeight = FontWeight.Normal
                                                                                )
                                                                        }
                                                                }
                                                        }
                                                                if (showStickyCallBanner || showVoiceMiniPlayer) {
                                                                        Column(
                                                                                modifier =
                                                                                        Modifier.fillMaxWidth()
                                                                                                .align(
                                                                                                        Alignment.TopCenter
                                                                                                )
                                                                        ) {
                                                                                if (showStickyCallBanner) {
                                                                                        CallTopBanner(
                                                                                                state = callUiState,
                                                                                                isSticky = true,
                                                                                                isDarkTheme = isDarkTheme,
                                                                                                avatarRepository = avatarRepository,
                                                                                                onOpenCall = onOpenCallOverlay
                                                                                        )
                                                                                }
                                                                                AnimatedVisibility(
                                                                                        visible = showVoiceMiniPlayer,
                                                                                        enter = expandVertically(
                                                                                                animationSpec = tween(220, easing = FastOutSlowInEasing),
                                                                                                expandFrom = Alignment.Top
                                                                                        ) + fadeIn(animationSpec = tween(220)),
                                                                                        exit = shrinkVertically(
                                                                                                animationSpec = tween(260, easing = FastOutSlowInEasing),
                                                                                                shrinkTowards = Alignment.Top
                                                                                        ) + fadeOut(animationSpec = tween(180))
                                                                                ) {
                                                                                        VoiceTopMiniPlayer(
                                                                                                title = voiceMiniPlayerTitle,
                                                                                                isDarkTheme = isDarkTheme,
                                                                                                isPlaying = isVoicePlaybackRunning,
                                                                                                speed = voicePlaybackSpeed,
                                                                                                onTogglePlay = {
                                                                                                        VoicePlaybackCoordinator.toggleCurrentPlayback()
                                                                                                },
                                                                                                onCycleSpeed = {
                                                                                                        VoicePlaybackCoordinator.cycleSpeed()
                                                                                                },
                                                                                                onClose = {
                                                                                                        VoicePlaybackCoordinator.stop()
                                                                                                }
                                                                                        )
                                                                                }
                                                                        }
                                                                }
                                                        }
                                                }
                                                } // Close Requests AnimatedContent
                                                } // Close calls/main switch
                                        } // Close Calls AnimatedContent
                                        } // Close downloads/main content switch
                                        } // Close Downloads AnimatedContent

                                        // Console button removed
                                }
                        }
                    } // Close content Box
                } // Close ModalNavigationDrawer

                // 🔥 Confirmation Dialogs

                if (showDeleteCallsDialog) {
                        AlertDialog(
                                onDismissRequest = { showDeleteCallsDialog = false },
                                containerColor = if (isDarkTheme) Color(0xFF2C2C2E) else Color.White,
                                title = {
                                        Text(
                                                "Delete all calls",
                                                fontWeight = FontWeight.Bold,
                                                color = textColor
                                        )
                                },
                                text = {
                                        Text(
                                                "This will remove all call records from history. Chats and contacts will stay unchanged.",
                                                color = secondaryTextColor
                                        )
                                },
                                confirmButton = {
                                        TextButton(
                                                onClick = {
                                                        showDeleteCallsDialog = false
                                                        scope.launch {
                                                                val deleted = clearAllCallsHistory()
                                                                if (deleted > 0) {
                                                                        Toast.makeText(
                                                                                context,
                                                                                "Deleted $deleted call records",
                                                                                Toast.LENGTH_SHORT
                                                                        ).show()
                                                                } else {
                                                                        Toast.makeText(
                                                                                context,
                                                                                "Call history is already empty",
                                                                                Toast.LENGTH_SHORT
                                                                        ).show()
                                                                }
                                                        }
                                                }
                                        ) {
                                                Text("Delete", color = Color(0xFFE55A5A))
                                        }
                                },
                                dismissButton = {
                                        TextButton(onClick = { showDeleteCallsDialog = false }) {
                                                Text("Cancel", color = PrimaryBlue)
                                        }
                                }
                        )
                }

                // Delete Dialog Confirmation
                if (dialogsToDelete.isNotEmpty()) {
                        val count = dialogsToDelete.size
                        AlertDialog(
                                onDismissRequest = { dialogsToDelete = emptyList() },
                                containerColor =
                                        if (isDarkTheme) Color(0xFF2C2C2E) else Color.White,
                                title = {
                                        Text(
                                                if (count == 1) "Delete Chat" else "Delete $count Chats",
                                                fontWeight = FontWeight.Bold,
                                                color = textColor
                                        )
                                },
                                text = {
                                        Text(
                                                if (count == 1) "Are you sure you want to delete this chat? This action cannot be undone."
                                                else "Are you sure you want to delete $count chats? This action cannot be undone.",
                                                color = secondaryTextColor
                                        )
                                },
                                confirmButton = {
                                        TextButton(
                                                onClick = {
                                                        val toDelete = dialogsToDelete.toList()
                                                        dialogsToDelete = emptyList()
                                                        scope.launch {
                                                                toDelete.forEach { dialog ->
                                                                        chatsViewModel.deleteDialog(
                                                                                dialog.opponentKey
                                                                        )
                                                                }
                                                        }
                                                }
                                        ) { Text("Delete", color = Color(0xFFFF3B30)) }
                                },
                                dismissButton = {
                                        TextButton(onClick = { dialogsToDelete = emptyList() }) {
                                                Text("Cancel", color = PrimaryBlue)
                                        }
                                }
                        )
                }

                // Leave Group Confirmation
                dialogToLeave?.let { dialog ->
                        val groupTitle = dialog.opponentTitle.ifEmpty { "this group" }
                        AlertDialog(
                                onDismissRequest = { dialogToLeave = null },
                                containerColor =
                                        if (isDarkTheme) Color(0xFF2C2C2E) else Color.White,
                                title = {
                                        Text(
                                                "Leave Group",
                                                fontWeight = FontWeight.Bold,
                                                color = textColor
                                        )
                                },
                                text = {
                                        Text(
                                                "Are you sure you want to leave \"$groupTitle\"?",
                                                color = secondaryTextColor
                                        )
                                },
                                confirmButton = {
                                        TextButton(
                                                onClick = {
                                                        val groupKey = dialog.opponentKey
                                                        dialogToLeave = null
                                                        scope.launch {
                                                                val left = chatsViewModel.leaveGroup(groupKey)
                                                                if (!left) {
                                                                        Toast
                                                                                .makeText(
                                                                                        context,
                                                                                        "Failed to leave group",
                                                                                        Toast.LENGTH_SHORT
                                                                                )
                                                                                .show()
                                                                }
                                                        }
                                                }
                                        ) { Text("Leave", color = Color(0xFFFF3B30)) }
                                },
                                dismissButton = {
                                        TextButton(onClick = { dialogToLeave = null }) {
                                                Text("Cancel", color = PrimaryBlue)
                                        }
                                }
                        )
                }

                // Block Dialog Confirmation
                dialogToBlock?.let { dialog ->
                        AlertDialog(
                                onDismissRequest = { dialogToBlock = null },
                                containerColor =
                                        if (isDarkTheme) Color(0xFF2C2C2E) else Color.White,
                                title = {
                                        Text(
                                                "Block ${dialog.opponentTitle.ifEmpty { "User" }}",
                                                fontWeight = FontWeight.Bold,
                                                color = textColor
                                        )
                                },
                                text = {
                                        Text(
                                                "Are you sure you want to block this user? They won't be able to send you messages.",
                                                color = secondaryTextColor
                                        )
                                },
                                confirmButton = {
                                        TextButton(
                                                onClick = {
                                                        val opponentKey = dialog.opponentKey
                                                        dialogToBlock = null
                                                        scope.launch {
                                                                chatsViewModel.blockUser(
                                                                        opponentKey
                                                                )
                                                        }
                                                }
                                        ) { Text("Block", color = Color(0xFFFF3B30)) }
                                },
                                dismissButton = {
                                        TextButton(onClick = { dialogToBlock = null }) {
                                                Text("Cancel", color = PrimaryBlue)
                                        }
                                }
                        )
                }

                // Unblock Dialog Confirmation
                dialogToUnblock?.let { dialog ->
                        AlertDialog(
                                onDismissRequest = { dialogToUnblock = null },
                                containerColor =
                                        if (isDarkTheme) Color(0xFF2C2C2E) else Color.White,
                                title = {
                                        Text(
                                                "Unblock ${dialog.opponentTitle.ifEmpty { "User" }}",
                                                fontWeight = FontWeight.Bold,
                                                color = textColor
                                        )
                                },
                                text = {
                                        Text(
                                                "Are you sure you want to unblock this user? They will be able to send you messages again.",
                                                color = secondaryTextColor
                                        )
                                },
                                confirmButton = {
                                        TextButton(
                                                onClick = {
                                                        val opponentKey = dialog.opponentKey
                                                        dialogToUnblock = null
                                                        scope.launch {
                                                                chatsViewModel.unblockUser(
                                                                        opponentKey
                                                                )
                                                        }
                                                }
                                        ) { Text("Unblock", color = PrimaryBlue) }
                                },
                                dismissButton = {
                                        TextButton(onClick = { dialogToUnblock = null }) {
                                                Text("Cancel", color = Color(0xFF8E8E93))
                                        }
                                }
                        )
                }

                deviceResolveRequest?.let { (device, action) ->
                        DeviceResolveDialog(
                                isDarkTheme = isDarkTheme,
                                device = device,
                                action = action,
                                onDismiss = { deviceResolveRequest = null },
                                onConfirm = {
                                        val request = deviceResolveRequest
                                        deviceResolveRequest = null
                                        if (request != null) {
                                                when (request.second) {
                                                        DeviceResolveAction.ACCEPT -> {
                                                                protocolGateway.acceptDevice(
                                                                        request.first.deviceId
                                                                )
                                                        }
                                                        DeviceResolveAction.DECLINE -> {
                                                                protocolGateway.declineDevice(
                                                                        request.first.deviceId
                                                                )
                                                        }
                                                }
                                        }
                                }
                        )
                }

                if (themeRevealActive) {
                        val snapshot = themeRevealSnapshot
                        if (snapshot != null) {
                                Canvas(
                                        modifier =
                                                Modifier.fillMaxSize()
                                                        .graphicsLayer(
                                                                compositingStrategy =
                                                                        CompositingStrategy.Offscreen
                                                        )
                                ) {
                                        val destinationSize =
                                                IntSize(
                                                        width = size.width.roundToInt(),
                                                        height = size.height.roundToInt()
                                                )
                                        if (themeRevealToDark) {
                                                drawImage(
                                                        image = snapshot,
                                                        srcOffset = IntOffset.Zero,
                                                        srcSize = IntSize(snapshot.width, snapshot.height),
                                                        dstOffset = IntOffset.Zero,
                                                        dstSize = destinationSize
                                                )
                                                drawCircle(
                                                        color = Color.Transparent,
                                                        radius = themeRevealRadius.value,
                                                        center = themeRevealCenter,
                                                        blendMode = BlendMode.Clear
                                                )
                                        } else {
                                                val radius = themeRevealRadius.value
                                                if (radius > 0f) {
                                                        val clipCirclePath =
                                                                Path().apply {
                                                                        addOval(
                                                                                Rect(
                                                                                        left = themeRevealCenter.x - radius,
                                                                                        top = themeRevealCenter.y - radius,
                                                                                        right = themeRevealCenter.x + radius,
                                                                                        bottom = themeRevealCenter.y + radius
                                                                                )
                                                                        )
                                                                }
                                                        clipPath(clipCirclePath) {
                                                                drawImage(
                                                                        image = snapshot,
                                                                        srcOffset = IntOffset.Zero,
                                                                        srcSize =
                                                                                IntSize(
                                                                                        snapshot.width,
                                                                                        snapshot.height
                                                                                ),
                                                                        dstOffset = IntOffset.Zero,
                                                                        dstSize = destinationSize
                                                                )
                                                        }
                                                }
                                        }
                                }
                        }
                }

                accountToDelete?.let { account ->
                        val isCurrentAccount = account.publicKey == accountPublicKey
                        val displayName =
                                resolveAccountDisplayName(
                                        account.publicKey,
                                        account.name,
                                        account.username
                                )
                        AlertDialog(
                                onDismissRequest = { accountToDelete = null },
                                containerColor = if (isDarkTheme) Color(0xFF2C2C2E) else Color.White,
                                title = {
                                        Text(
                                                text = "Delete Account",
                                                fontWeight = FontWeight.Bold,
                                                color = textColor
                                        )
                                },
                                text = {
                                        Text(
                                                text =
                                                        if (isCurrentAccount) {
                                                                "Delete \"$displayName\" from this device? You will return to the main login screen."
                                                        } else {
                                                                "Delete \"$displayName\" from this device?"
                                                        },
                                                color = secondaryTextColor
                                        )
                                },
                                confirmButton = {
                                        TextButton(
                                                onClick = {
                                                        val publicKey = account.publicKey
                                                        accountToDelete = null
                                                        allAccounts =
                                                                allAccounts.filterNot {
                                                                        it.publicKey == publicKey
                                                                }
                                                        scope.launch {
                                                                accountsSectionExpanded = false
                                                                drawerState.close()
                                                                onDeleteAccountFromSidebar(publicKey)
                                                        }
                                                }
                                        ) { Text("Delete", color = Color(0xFFFF3B30)) }
                                },
                                dismissButton = {
                                        TextButton(onClick = { accountToDelete = null }) {
                                                Text("Cancel", color = PrimaryBlue)
                                        }
                                }
                        )
                }
        } // Close Box
}

@Composable
private fun DeviceResolveDialog(
        isDarkTheme: Boolean,
        device: DeviceEntry,
        action: DeviceResolveAction,
        onDismiss: () -> Unit,
        onConfirm: () -> Unit
) {
        val containerColor = if (isDarkTheme) Color(0xFF2C2C2E) else Color.White
        val borderColor = if (isDarkTheme) Color(0xFF3A3A3C) else Color(0xFFE8E8ED)
        val textColor = if (isDarkTheme) Color.White else Color.Black
        val secondaryTextColor = if (isDarkTheme) Color(0xFF8E8E93) else Color(0xFF666666)
        val isAccept = action == DeviceResolveAction.ACCEPT
        val confirmColor = if (isAccept) PrimaryBlue else Color(0xFFFF3B30)

        val composition by rememberLottieComposition(
                LottieCompositionSpec.RawRes(
                        if (isAccept) R.raw.saved else R.raw.device_confirm
                )
        )
        val progress by animateLottieCompositionAsState(
                composition = composition,
                iterations = LottieConstants.IterateForever
        )
        val deviceLabel = buildString {
                append(device.deviceName.ifBlank { "Unknown device" })
                if (device.deviceOs.isNotBlank()) {
                        append(" • ")
                        append(device.deviceOs)
                }
        }

        Dialog(
                onDismissRequest = onDismiss,
                properties = DialogProperties(usePlatformDefaultWidth = false)
        ) {
                Surface(
                        modifier =
                                Modifier.fillMaxWidth()
                                        .padding(horizontal = 24.dp)
                                        .widthIn(max = 380.dp),
                        color = containerColor,
                        shape = RoundedCornerShape(22.dp),
                        border = BorderStroke(1.dp, borderColor)
                ) {
                        Column(
                                modifier = Modifier.padding(horizontal = 18.dp, vertical = 18.dp),
                                horizontalAlignment = Alignment.CenterHorizontally
                        ) {
                                Box(
                                        modifier =
                                                Modifier.size(96.dp),
                                        contentAlignment = Alignment.Center
                                ) {
                                        LottieAnimation(
                                                composition = composition,
                                                progress = { progress },
                                                modifier = Modifier.size(78.dp)
                                        )
                                }

                                Spacer(modifier = Modifier.height(14.dp))

                                Text(
                                        text = if (isAccept) "Approve new device?" else "Decline this login?",
                                        fontWeight = FontWeight.Bold,
                                        color = textColor,
                                        fontSize = 19.sp,
                                        textAlign = TextAlign.Center,
                                        modifier = Modifier.fillMaxWidth()
                                )

                                Spacer(modifier = Modifier.height(8.dp))

                                Text(
                                        text =
                                                if (isAccept) {
                                                        "Allow \"$deviceLabel\" to access your account?"
                                                } else {
                                                        "Block login from \"$deviceLabel\"?"
                                                },
                                        color = secondaryTextColor,
                                        textAlign = TextAlign.Center,
                                        lineHeight = 19.sp,
                                        maxLines = 3,
                                        overflow = TextOverflow.Ellipsis,
                                        modifier = Modifier.fillMaxWidth()
                                )

                                Spacer(modifier = Modifier.height(14.dp))

                                Row(
                                        modifier = Modifier.fillMaxWidth(),
                                        horizontalArrangement = Arrangement.spacedBy(10.dp)
                                ) {
                                        OutlinedButton(
                                                onClick = onDismiss,
                                                modifier = Modifier.weight(1f).height(42.dp),
                                                shape = RoundedCornerShape(12.dp),
                                                border = BorderStroke(
                                                        width = 1.dp,
                                                        color = if (isDarkTheme) Color(0xFF4A4F60) else Color(0xFFD9D9DE)
                                                )
                                        ) {
                                                Text("Cancel", color = secondaryTextColor)
                                        }
                                        Button(
                                                onClick = onConfirm,
                                                modifier = Modifier.weight(1f).height(42.dp),
                                                shape = RoundedCornerShape(12.dp),
                                                colors = ButtonDefaults.buttonColors(
                                                        containerColor = confirmColor,
                                                        contentColor = Color.White
                                                )
                                        ) {
                                                Text(if (isAccept) "Approve" else "Decline login")
                                        }
                                }
                        }
                }
        }
}

/**
 * 🚀 Shimmer skeleton для списка чатов — показывается пока данные грузятся Имитирует 10 строк
 * диалогов: аватар + 2 строки текста
 */
@Composable
private fun ChatsListSkeleton(isDarkTheme: Boolean) {
        val backgroundColor = if (isDarkTheme) Color(0xFF1A1A1A) else Color(0xFFF2F2F7)
        val shimmerBase = if (isDarkTheme) Color(0xFF2C2C2E) else Color(0xFFE5E5EA)
        val shimmerHighlight = if (isDarkTheme) Color(0xFF48484A) else Color(0xFFFFFFFF)

        BoxWithConstraints(modifier = Modifier.fillMaxSize().background(backgroundColor)) {
                val density = LocalDensity.current
                val maxWidthPx = with(density) { maxWidth.toPx() }.coerceAtLeast(1f)
                val gradientWidthPx = with(density) { 280.dp.toPx() }

                val transition = rememberInfiniteTransition(label = "shimmer")
                val shimmerX by transition.animateFloat(
                        initialValue = -gradientWidthPx,
                        targetValue = maxWidthPx + gradientWidthPx,
                        animationSpec = infiniteRepeatable(
                                animation = tween(durationMillis = 1400, easing = LinearEasing),
                                repeatMode = RepeatMode.Restart
                        ),
                        label = "shimmerX"
                )

                val shimmerBrush = Brush.linearGradient(
                        colorStops = arrayOf(
                                0f to shimmerBase,
                                0.4f to shimmerHighlight,
                                0.6f to shimmerHighlight,
                                1f to shimmerBase
                        ),
                        start = Offset(shimmerX - gradientWidthPx / 2f, 0f),
                        end = Offset(shimmerX + gradientWidthPx / 2f, 0f)
                )

                val nameWidths = remember {
                        floatArrayOf(0.38f, 0.52f, 0.44f, 0.61f, 0.35f, 0.48f, 0.56f, 0.41f, 0.63f, 0.39f)
                }
                val msgWidths = remember {
                        floatArrayOf(0.72f, 0.55f, 0.82f, 0.64f, 0.78f, 0.51f, 0.69f, 0.87f, 0.60f, 0.74f)
                }

                LazyColumn(
                        modifier = Modifier.fillMaxSize(),
                        userScrollEnabled = false
                ) {
                        items(10) { index ->
                                SkeletonDialogItem(
                                        shimmerBrush = shimmerBrush,
                                        nameWidth = nameWidths[index],
                                        messageWidth = msgWidths[index],
                                        isDarkTheme = isDarkTheme
                                )
                        }
                }
        }
}

@Composable
private fun SkeletonDialogItem(shimmerBrush: Brush, nameWidth: Float, messageWidth: Float, isDarkTheme: Boolean) {
        val dividerColor = if (isDarkTheme) Color(0xFF38383A) else Color(0xFFE5E5EA)

        Row(
                modifier =
                        Modifier.fillMaxWidth()
                                .padding(
                                        horizontal = TELEGRAM_DIALOG_AVATAR_START,
                                        vertical = TELEGRAM_DIALOG_VERTICAL_PADDING
                                ),
                verticalAlignment = Alignment.CenterVertically
        ) {
                // Avatar placeholder
                Box(
                        modifier =
                                Modifier.size(TELEGRAM_DIALOG_AVATAR_SIZE)
                                        .clip(CircleShape)
                                        .background(shimmerBrush)
                )

                Spacer(modifier = Modifier.width(TELEGRAM_DIALOG_AVATAR_GAP))

                Column(modifier = Modifier.weight(1f), verticalArrangement = Arrangement.spacedBy(7.dp)) {
                        // Name + time row
                        Row(
                                modifier = Modifier.fillMaxWidth(),
                                horizontalArrangement = Arrangement.SpaceBetween,
                                verticalAlignment = Alignment.CenterVertically
                        ) {
                                Box(
                                        modifier =
                                                Modifier.fillMaxWidth(nameWidth)
                                                        .height(15.dp)
                                                        .clip(RoundedCornerShape(6.dp))
                                                        .background(shimmerBrush)
                                )
                                Box(
                                        modifier =
                                                Modifier.width(34.dp)
                                                        .height(11.dp)
                                                        .clip(RoundedCornerShape(4.dp))
                                                        .background(shimmerBrush)
                                )
                        }
                        // Message preview placeholder
                        Box(
                                modifier =
                                        Modifier.fillMaxWidth(messageWidth)
                                                .height(13.dp)
                                                .clip(RoundedCornerShape(5.dp))
                                                .background(shimmerBrush)
                        )
                }
        }
        Divider(
                color = dividerColor,
                thickness = 0.5.dp,
                modifier = Modifier.padding(start = TELEGRAM_DIALOG_TEXT_START)
        )
}

@Composable
private fun EmptyChatsState(isDarkTheme: Boolean, modifier: Modifier = Modifier) {
        val secondaryTextColor = if (isDarkTheme) Color(0xFF8E8E93) else Color(0xFF666666)
        val backgroundColor = if (isDarkTheme) Color(0xFF1A1A1A) else Color(0xFFF2F2F7)

        // Lottie animation
        val composition by rememberLottieComposition(LottieCompositionSpec.RawRes(R.raw.letter))
        val progress by animateLottieCompositionAsState(composition = composition, iterations = 1)

        Column(
                modifier = modifier.fillMaxSize().background(backgroundColor),
                horizontalAlignment = Alignment.CenterHorizontally,
                verticalArrangement = Arrangement.Center
        ) {
                // Lottie animation
                LottieAnimation(
                        composition = composition,
                        progress = { progress },
                        modifier = Modifier.size(150.dp)
                )

                Spacer(modifier = Modifier.height(24.dp))

                Text(
                        text = "No conversations yet",
                        fontSize = 18.sp,
                        fontWeight = FontWeight.SemiBold,
                        color = secondaryTextColor,
                        textAlign = TextAlign.Center
                )

                Spacer(modifier = Modifier.height(8.dp))

                Text(
                        text = "Start a new conversation to get started",
                        fontSize = 15.sp,
                        color = secondaryTextColor,
                        textAlign = TextAlign.Center
                )
        }
}

/** Элемент меню в боковом drawer */
@Composable
fun DrawerMenuItem(
        icon: androidx.compose.ui.graphics.vector.ImageVector,
        text: String,
        isDarkTheme: Boolean,
        isDestructive: Boolean = false,
        onClick: () -> Unit
) {
        val textColor =
                if (isDestructive) {
                        Color(0xFFFF3B30)
                } else {
                        if (isDarkTheme) Color.White else Color.Black
                }

        val backgroundColor = if (isDarkTheme) Color(0xFF2C2C2E) else Color(0xFFF2F2F7)

        Row(
                modifier =
                        Modifier.fillMaxWidth()
                                .padding(horizontal = 16.dp, vertical = 4.dp)
                                .clip(RoundedCornerShape(12.dp))
                                .background(backgroundColor)
                                .clickable(onClick = onClick)
                                .padding(horizontal = 16.dp, vertical = 14.dp),
                verticalAlignment = Alignment.CenterVertically
        ) {
                Icon(
                        imageVector = icon,
                        contentDescription = null,
                        tint = textColor.copy(alpha = 0.6f),
                        modifier = Modifier.size(24.dp)
                )

                Spacer(modifier = Modifier.width(16.dp))

                Text(
                        text = text,
                        fontSize = 16.sp,
                        color = textColor,
                        fontWeight = FontWeight.Medium
                )
        }
}

/**
 * 🔥 Swipeable wrapper для DialogItem (Pin + Leave/Block + Delete). Свайп влево показывает действия
 * (как в React Native версии)
 */
@Composable
fun SwipeableDialogItem(
        dialog: DialogUiModel,
        isDarkTheme: Boolean,
        isTyping: Boolean = false,
        typingDisplayName: String = "",
        typingSenderPublicKey: String = "",
        isVoicePlaybackActive: Boolean = false,
        isBlocked: Boolean = false,
        isGroupChat: Boolean = false,
        isSavedMessages: Boolean = false,
        swipeEnabled: Boolean = true,
        isMuted: Boolean = false,
        avatarRepository: com.rosetta.messenger.repository.AvatarRepository? = null,
        isDrawerOpen: Boolean = false,
        isSwipedOpen: Boolean = false,
        isSelected: Boolean = false,
        syncInProgress: Boolean = false,
        onSwipeStarted: () -> Unit = {},
        onSwipeClosed: () -> Unit = {},
        onClick: () -> Unit,
        onLongClick: () -> Unit = {},
        onDelete: () -> Unit = {},
        onLeave: () -> Unit = {},
        onBlock: () -> Unit = {},
        onUnblock: () -> Unit = {},
        isPinned: Boolean = false,
        onPin: () -> Unit = {}
) {
        val targetBackgroundColor =
                if (isSelected) {
                        if (isDarkTheme) Color(0xFF1A3A5C) else Color(0xFFD6EAFF)
                } else if (isPinned) {
                        if (isDarkTheme) Color(0xFF232323) else Color(0xFFE8E8ED)
                } else {
                        if (isDarkTheme) Color(0xFF1A1A1A) else Color(0xFFF2F2F7)
                }
        var previousTheme by remember { mutableStateOf(isDarkTheme) }
        val themeJustChanged = previousTheme != isDarkTheme
        SideEffect { previousTheme = isDarkTheme }
        val backgroundColor by
                animateColorAsState(
                        targetValue = targetBackgroundColor,
                        animationSpec =
                                if (themeJustChanged) snap()
                                else tween(durationMillis = 260, easing = FastOutSlowInEasing),
                        label = "pinnedBackground"
                )
        var offsetX by remember { mutableStateOf(0f) }
        // 📌 3 кнопки: Pin + Leave/Block + Delete (для SavedMessages: Pin + Delete)
        val buttonCount =
                if (!swipeEnabled) 0
                else if (isSavedMessages) 2
                else 3
        val swipeWidthDp = (buttonCount * 80).dp
        val density = androidx.compose.ui.platform.LocalDensity.current
        val swipeWidthPx = with(density) { swipeWidthDp.toPx() }

        // Фиксированная высота элемента (как в DialogItem)
        val itemHeight = TELEGRAM_DIALOG_ROW_HEIGHT

        // Close when another item starts swiping (like Telegram)
        LaunchedEffect(isSwipedOpen) {
                if (!isSwipedOpen && offsetX != 0f) {
                        offsetX = 0f
                }
        }

        // Telegram-style easing
        val telegramEasing = CubicBezierEasing(0.25f, 0.1f, 0.25f, 1.0f)
        val animatedOffsetX by
                animateFloatAsState(
                        targetValue = offsetX,
                        animationSpec = tween(durationMillis = 160, easing = telegramEasing),
                        label = "swipeOffset"
                )

        Box(
                modifier =
                        Modifier.fillMaxWidth()
                                .height(itemHeight)
                                .background(backgroundColor)
                                .clipToBounds()
        ) {
                // 1. КНОПКИ - позиционированы справа, всегда видны при свайпе
                if (swipeEnabled) {
                Row(
                        modifier =
                                Modifier.align(Alignment.CenterEnd)
                                        .height(itemHeight)
                                        .width(swipeWidthDp)
                ) {
                        // 📌 Кнопка Pin/Unpin
                        Box(
                                modifier =
                                        Modifier.width(80.dp)
                                                .fillMaxHeight()
                                                .background(Color(0xFFFF9500)) // iOS orange
                                                .clickable {
                                                        onPin()
                                                        offsetX = 0f
                                                        onSwipeClosed()
                                                },
                                contentAlignment = Alignment.Center
                        ) {
                                Column(
                                        horizontalAlignment = Alignment.CenterHorizontally,
                                        verticalArrangement = Arrangement.Center
                                ) {
                                        Icon(
                                                painter =
                                                        if (isPinned) TelegramIcons.Unpin
                                                        else TelegramIcons.Pin,
                                                contentDescription =
                                                        if (isPinned) "Unpin" else "Pin",
                                                tint = Color.White,
                                                modifier = Modifier.size(22.dp)
                                        )
                                        Spacer(modifier = Modifier.height(4.dp))
                                        Text(
                                                text = if (isPinned) "Unpin" else "Pin",
                                                color = Color.White,
                                                fontSize = 12.sp,
                                                fontWeight = FontWeight.SemiBold
                                        )
                                }
                        }

                        // Кнопка Leave (для группы) или Block/Unblock (для личных чатов)
                        if (!isSavedMessages) {
                                val middleActionColor =
                                        if (isGroupChat) Color(0xFFFF6B6B)
                                        else if (isBlocked) Color(0xFF4CAF50)
                                        else Color(0xFFFF6B6B)
                                val middleActionIcon =
                                        if (isGroupChat) TelegramIcons.Leave
                                        else if (isBlocked) TelegramIcons.Unlock
                                        else TelegramIcons.Block
                                val middleActionTitle =
                                        if (isGroupChat) "Leave"
                                        else if (isBlocked) "Unblock"
                                        else "Block"
                                Box(
                                        modifier =
                                                Modifier.width(80.dp)
                                                        .fillMaxHeight()
                                                        .background(middleActionColor)
                                                        .clickable {
                                                                if (isGroupChat) onLeave()
                                                                else if (isBlocked) onUnblock()
                                                                else onBlock()
                                                                offsetX = 0f
                                                                onSwipeClosed()
                                                        },
                                        contentAlignment = Alignment.Center
                                ) {
                                        Column(
                                                horizontalAlignment = Alignment.CenterHorizontally,
                                                verticalArrangement = Arrangement.Center
                                        ) {
                                                Icon(
                                                        painter = middleActionIcon,
                                                        contentDescription = middleActionTitle,
                                                        tint = Color.White,
                                                        modifier = Modifier.size(22.dp)
                                                )
                                                Spacer(modifier = Modifier.height(4.dp))
                                                Text(
                                                        text = middleActionTitle,
                                                        color = Color.White,
                                                        fontSize = 12.sp,
                                                        fontWeight = FontWeight.SemiBold
                                                )
                                        }
                                }
                        }

                        // Кнопка Delete
                        Box(
                                modifier =
                                        Modifier.width(80.dp)
                                                .fillMaxHeight()
                                                .background(PrimaryBlue)
                                                .clickable {
                                                        offsetX = 0f
                                                        onSwipeClosed()
                                                        onDelete()
                                                },
                                contentAlignment = Alignment.Center
                        ) {
                                Column(
                                        horizontalAlignment = Alignment.CenterHorizontally,
                                        verticalArrangement = Arrangement.Center
                                ) {
                                        Icon(
                                                painter = TelegramIcons.Delete,
                                                contentDescription = "Delete",
                                                tint = Color.White,
                                                modifier = Modifier.size(22.dp)
                                        )
                                        Spacer(modifier = Modifier.height(4.dp))
                                        Text(
                                                text = "Delete",
                                                color = Color.White,
                                                fontSize = 12.sp,
                                                fontWeight = FontWeight.SemiBold
                                        )
                                }
                        }
                }
                }

                // 2. КОНТЕНТ - поверх кнопок, сдвигается при свайпе
                // 🔥 rememberUpdatedState чтобы pointerInput всегда вызывал актуальные значения
                val currentOnClick by rememberUpdatedState(onClick)
                val currentOnLongClick by rememberUpdatedState(onLongClick)
                val currentIsDrawerOpen by rememberUpdatedState(isDrawerOpen)
                val currentSwipeEnabled by rememberUpdatedState(swipeEnabled)
                val currentSwipeWidthPx by rememberUpdatedState(swipeWidthPx)
                val currentOnSwipeStarted by rememberUpdatedState(onSwipeStarted)
                val currentOnSwipeClosed by rememberUpdatedState(onSwipeClosed)
                Column(
                        modifier =
                                Modifier.fillMaxSize()
                                        .offset { IntOffset(animatedOffsetX.toInt(), 0) }
                                        .background(backgroundColor)
                                        .pointerInput(Unit) {
                                                val velocityTracker = VelocityTracker()
                                                val touchSlop = viewConfiguration.touchSlop
                                                val longPressTimeoutMs = viewConfiguration.longPressTimeoutMillis

                                                awaitEachGesture {
                                                        val down =
                                                                awaitFirstDown(
                                                                        requireUnconsumed = false
                                                                )

                                                        // Don't handle swipes when drawer is open
                                                        if (currentIsDrawerOpen) return@awaitEachGesture

                                                        velocityTracker.resetTracking()
                                                        var totalDragX = 0f
                                                        var totalDragY = 0f
                                                        var claimed = false

                                                        // Phase 1: Determine gesture type (tap / long-press / drag)
                                                        // Wait up to longPressTimeout; if no up or slop → long press
                                                        var gestureType = "unknown"

                                                        val result = withTimeoutOrNull(longPressTimeoutMs) {
                                                                while (true) {
                                                                        val event = awaitPointerEvent()
                                                                        val change =
                                                                                event.changes.firstOrNull {
                                                                                        it.id == down.id
                                                                                }
                                                                        if (change == null) {
                                                                                gestureType = "cancelled"
                                                                                return@withTimeoutOrNull Unit
                                                                        }
                                                                        if (change.changedToUpIgnoreConsumed()) {
                                                                                change.consume()
                                                                                gestureType = "tap"
                                                                                return@withTimeoutOrNull Unit
                                                                        }
                                                                        val delta = change.positionChange()
                                                                        totalDragX += delta.x
                                                                        totalDragY += delta.y
                                                                        val dist = kotlin.math.sqrt(
                                                                                totalDragX * totalDragX +
                                                                                        totalDragY * totalDragY
                                                                        )
                                                                        if (dist >= touchSlop) {
                                                                                gestureType = "drag"
                                                                                return@withTimeoutOrNull Unit
                                                                        }
                                                                }
                                                                @Suppress("UNREACHABLE_CODE")
                                                                Unit
                                                        }

                                                        // Timeout → check if finger lifted during the race window
                                                        if (result == null) {
                                                                // Grace period: check if up event arrived just as timeout fired
                                                                withTimeoutOrNull(32L) {
                                                                        while (true) {
                                                                                val event = awaitPointerEvent()
                                                                                val change = event.changes.firstOrNull { it.id == down.id }
                                                                                if (change == null) {
                                                                                        gestureType = "cancelled"
                                                                                        return@withTimeoutOrNull Unit
                                                                                }
                                                                                if (change.changedToUpIgnoreConsumed()) {
                                                                                        change.consume()
                                                                                        gestureType = "tap"
                                                                                        return@withTimeoutOrNull Unit
                                                                                }
                                                                                // Still moving/holding — it's a real long press
                                                                                break
                                                                        }
                                                                        Unit
                                                                }
                                                                if (gestureType == "unknown") gestureType = "longpress"
                                                        }

                                                        when (gestureType) {
                                                                "tap" -> {
                                                                        currentOnClick()
                                                                        return@awaitEachGesture
                                                                }
                                                                "cancelled" -> return@awaitEachGesture
                                                                "longpress" -> {
                                                                        currentOnLongClick()
                                                                        // Consume remaining events until finger lifts
                                                                        while (true) {
                                                                                val event = awaitPointerEvent()
                                                                                val change =
                                                                                        event.changes.firstOrNull {
                                                                                                it.id == down.id
                                                                                        } ?: break
                                                                                change.consume()
                                                                                if (change.changedToUpIgnoreConsumed()) break
                                                                        }
                                                                        return@awaitEachGesture
                                                                }
                                                                "drag" -> {
                                                                        // Determine drag direction
                                                                        val dominated =
                                                                                kotlin.math.abs(totalDragX) >
                                                                                        kotlin.math.abs(totalDragY) * 2.0f

                                                                        when {
                                                                                // Horizontal left swipe — reveal action buttons
                                                                                currentSwipeEnabled && dominated && totalDragX < 0 -> {
                                                                                        claimed = true
                                                                                        currentOnSwipeStarted()
                                                                                }
                                                                                // Horizontal right swipe with buttons open — close them
                                                                                dominated && totalDragX > 0 && offsetX != 0f -> {
                                                                                        claimed = true
                                                                                }
                                                                                // Right swipe with buttons closed — let drawer handle
                                                                                totalDragX > 0 && offsetX == 0f ->
                                                                                        return@awaitEachGesture
                                                                                // Vertical/diagonal — close buttons if open, let LazyColumn scroll
                                                                                else -> {
                                                                                        if (offsetX != 0f) {
                                                                                                offsetX = 0f
                                                                                                currentOnSwipeClosed()
                                                                                        }
                                                                                        return@awaitEachGesture
                                                                                }
                                                                        }
                                                                }
                                                        }

                                                        // Phase 2: Continue tracking drag
                                                        while (true) {
                                                                val event = awaitPointerEvent()
                                                                val change =
                                                                        event.changes.firstOrNull {
                                                                                it.id == down.id
                                                                        }
                                                                                ?: break
                                                                if (change.changedToUpIgnoreConsumed()) break

                                                                val delta = change.positionChange()
                                                                val curSwipeWidthPx = currentSwipeWidthPx
                                                                val newOffset = offsetX + delta.x
                                                                offsetX = newOffset.coerceIn(-curSwipeWidthPx, 0f)
                                                                velocityTracker.addPosition(
                                                                        change.uptimeMillis,
                                                                        change.position
                                                                )
                                                                change.consume()
                                                        }

                                                        // Phase 3: Snap animation
                                                        if (claimed) {
                                                                val curSwipeWidthPx = currentSwipeWidthPx
                                                                val velocity =
                                                                        velocityTracker
                                                                                .calculateVelocity()
                                                                                .x
                                                                when {
                                                                        velocity > 150f -> {
                                                                                offsetX = 0f
                                                                                currentOnSwipeClosed()
                                                                        }
                                                                        velocity < -300f -> {
                                                                                offsetX = -curSwipeWidthPx
                                                                        }
                                                                        kotlin.math.abs(offsetX) >
                                                                                curSwipeWidthPx / 2 -> {
                                                                                offsetX = -curSwipeWidthPx
                                                                        }
                                                                        else -> {
                                                                                offsetX = 0f
                                                                                currentOnSwipeClosed()
                                                                        }
                                                                }
                                                        }
                                                }
                                        }
                ) {
                        DialogItemContent(
                                dialog = dialog,
                                isDarkTheme = isDarkTheme,
                                isTyping = isTyping,
                                typingDisplayName = typingDisplayName,
                                typingSenderPublicKey = typingSenderPublicKey,
                                isVoicePlaybackActive = isVoicePlaybackActive,
                                isPinned = isPinned,
                                isBlocked = isBlocked,
                                isMuted = isMuted,
                                syncInProgress = syncInProgress,
                                avatarRepository = avatarRepository,
                                onClick = null // Tap handled by parent pointerInput
                        )
                }
        }
}

/** Элемент диалога из базы данных - ОПТИМИЗИРОВАННЫЙ (без сепаратора для SwipeableDialogItem) */
@Composable
fun DialogItemContent(
        dialog: DialogUiModel,
        isDarkTheme: Boolean,
        isTyping: Boolean = false,
        typingDisplayName: String = "",
        typingSenderPublicKey: String = "",
        isVoicePlaybackActive: Boolean = false,
        isPinned: Boolean = false,
        isBlocked: Boolean = false,
        isMuted: Boolean = false,
        syncInProgress: Boolean = false,
        avatarRepository: com.rosetta.messenger.repository.AvatarRepository? = null,
        onClick: (() -> Unit)? = null
) {
        // 🔥 ОПТИМИЗАЦИЯ: Кешируем цвета и строки
        val textColor = remember(isDarkTheme) { if (isDarkTheme) Color.White else Color.Black }
        val secondaryTextColor =
                remember(isDarkTheme) { if (isDarkTheme) Color(0xFF8E8E93) else Color(0xFF666666) }
        val visibleUnreadCount = if (syncInProgress) 0 else dialog.unreadCount

        val isGroupDialog = remember(dialog.opponentKey) { isGroupDialogKey(dialog.opponentKey) }

        // 📁 Для Saved Messages показываем специальное имя
        // 🔥 Как в Архиве: title > username > "DELETED"
        val displayName =
                remember(
                        dialog.opponentTitle,
                        dialog.opponentUsername,
                        dialog.opponentKey,
                        dialog.isSavedMessages
                ) {
                        if (dialog.isSavedMessages) {
                                "Saved Messages"
                        } else if (dialog.opponentTitle.isNotEmpty() &&
                                        dialog.opponentTitle != dialog.opponentKey &&
                                        dialog.opponentTitle != dialog.opponentKey.take(7) &&
                                        dialog.opponentTitle != dialog.opponentKey.take(8)
                        ) {
                                // 🔥 Показываем title как основное имя (как в десктопной версии)
                                // Обрезаем до 15 символов как в Архиве
                                if (dialog.opponentTitle.length > 15) {
                                        dialog.opponentTitle.take(15) + "..."
                                } else {
                                        dialog.opponentTitle
                                }
                        } else if (dialog.opponentUsername.isNotEmpty()) {
                                // Username только если нет title
                                "@${dialog.opponentUsername}"
                        } else {
                                // 🔥 Как в Архиве - если нет информации, показываем часть ключа
                                dialog.opponentKey.take(7)
                        }
                }

        Row(
                modifier =
                        Modifier.fillMaxWidth()
                                .then(
                                        if (onClick != null) Modifier.clickable(onClick = onClick)
                                        else Modifier
                                )
                                .padding(
                                        horizontal = TELEGRAM_DIALOG_AVATAR_START,
                                        vertical = TELEGRAM_DIALOG_VERTICAL_PADDING
                                ),
                verticalAlignment = Alignment.CenterVertically
        ) {
                // Avatar container with online indicator
                Box(modifier = Modifier.size(TELEGRAM_DIALOG_AVATAR_SIZE)) {
                        // Avatar
                        if (dialog.isSavedMessages) {
                                Box(
                                        modifier =
                                                Modifier.fillMaxSize()
                                                        .clip(CircleShape)
                                                        .background(Color(0xFF228BE6)),
                                        contentAlignment = Alignment.Center
                                ) {
                                        Icon(
                                                painter = painterResource(R.drawable.bookmark_outlined),
                                                contentDescription = null,
                                                tint = Color.White,
                                                modifier = Modifier.size(24.dp)
                                        )
                                }
                        } else {
                                // 🔥 Формируем displayName для инициалов в placeholder
                                val avatarDisplayName =
                                        remember(
                                                dialog.opponentTitle,
                                                dialog.opponentKey,
                                                dialog.opponentUsername
                                        ) {
                                                when {
                                                        dialog.opponentTitle.isNotEmpty() &&
                                                                dialog.opponentTitle !=
                                                                        dialog.opponentKey &&
                                                                !dialog.opponentTitle.startsWith(
                                                                        dialog.opponentKey.take(7)
                                                                ) -> dialog.opponentTitle
                                                        dialog.opponentUsername.isNotEmpty() ->
                                                                dialog.opponentUsername
                                                        else -> null
                                                }
                                        }
                                com.rosetta.messenger.ui.components.AvatarImage(
                                        publicKey = dialog.opponentKey,
                                        avatarRepository = avatarRepository,
                                        size = TELEGRAM_DIALOG_AVATAR_SIZE,
                                        isDarkTheme = isDarkTheme,
                                        displayName = avatarDisplayName,
                                        enableBlurPrewarm = true
                                )
                        }

                        // Online indicator - зелёный кружок с белой обводкой
                        if (dialog.isOnline == 1) {
                                Box(
                                        modifier =
                                                Modifier.size(18.dp)
                                                        .align(Alignment.BottomEnd)
                                                        .offset(x = (-2).dp, y = (-2).dp)
                                                        .clip(CircleShape)
                                                        .background(
                                                                if (isDarkTheme) Color(0xFF1C1C1E)
                                                                else Color.White
                                                        )
                                                        .padding(3.dp)
                                                        .clip(CircleShape)
                                                        .background(
                                                                Color(0xFF34C759)
                                                        ) // iOS зелёный цвет
                                )
                        }
                }

                Spacer(modifier = Modifier.width(TELEGRAM_DIALOG_AVATAR_GAP))

                // Name and last message
                Column(modifier = Modifier.weight(1f)) {
                        Row(
                                modifier = Modifier.fillMaxWidth().heightIn(min = 22.dp),
                                horizontalArrangement = Arrangement.SpaceBetween,
                                verticalAlignment = Alignment.CenterVertically
                        ) {
                                Row(
                                        modifier = Modifier.weight(1f).heightIn(min = 22.dp),
                                        verticalAlignment = Alignment.CenterVertically
                                ) {
                                        AppleEmojiText(
                                                text = displayName,
                                                fontWeight = FontWeight.SemiBold,
                                                fontSize = 16.sp,
                                                color = textColor,
                                                maxLines = 1,
                                                overflow = android.text.TextUtils.TruncateAt.END,
                                                enableLinks = false,
                                                minHeightMultiplier = 1f
                                        )
                                        if (isGroupDialog) {
                                                Spacer(modifier = Modifier.width(5.dp))
                                                Icon(
                                                        imageVector = TablerIcons.Users,
                                                        contentDescription = null,
                                                        tint = secondaryTextColor.copy(alpha = 0.9f),
                                                        modifier = Modifier.size(14.dp)
                                                )
                                        }
                                        val isOfficialByKey = MessageRepository.isSystemAccount(dialog.opponentKey)
                                        if (dialog.verified > 0 || isOfficialByKey) {
                                                Spacer(modifier = Modifier.width(4.dp))
                                                VerifiedBadge(
                                                        verified = if (dialog.verified > 0) dialog.verified else 1,
                                                        size = 16,
                                                        modifier = Modifier,
                                                        isDarkTheme = isDarkTheme,
                                                        badgeTint = PrimaryBlue
                                                )
                                        }
                                        // 🔒 Красная иконка замочка для заблокированных пользователей
                                        if (isBlocked) {
                                                Spacer(modifier = Modifier.width(4.dp))
                                                Icon(
                                                        painter = TelegramIcons.Secret,
                                                        contentDescription = "Blocked",
                                                        tint = Color(0xFFFF3B30),
                                                        modifier = Modifier.size(14.dp)
                                                )
                                        }
                                        if (isMuted) {
                                                Spacer(modifier = Modifier.width(4.dp))
                                                Icon(
                                                        painter = TelegramIcons.Mute,
                                                        contentDescription = "Muted",
                                                        tint = secondaryTextColor,
                                                        modifier = Modifier.size(14.dp)
                                                )
                                        }
                                }

                                Row(
                                        modifier = Modifier.heightIn(min = 16.dp),
                                        verticalAlignment = Alignment.CenterVertically,
                                        horizontalArrangement = Arrangement.End
                                ) {
                                        // Скрываем статус доставки при черновике и во время синхронизации.
                                        if (dialog.draftText.isNullOrEmpty() && !syncInProgress) {
                                        // �📁 Для Saved Messages ВСЕГДА показываем синие двойные
                                        // галочки (прочитано)
                                        if (dialog.isSavedMessages) {
                                                Box(
                                                        modifier = Modifier.width(20.dp).height(16.dp)
                                                ) {
                                                        Icon(
                                                                painter = TelegramIcons.Done,
                                                                contentDescription = null,
                                                                tint = PrimaryBlue,
                                                                modifier =
                                                                        Modifier.size(16.dp)
                                                                                .align(
                                                                                        Alignment.CenterStart
                                                                                )
                                                        )
                                                        Icon(
                                                                painter = TelegramIcons.Done,
                                                                contentDescription = null,
                                                                tint = PrimaryBlue,
                                                                modifier =
                                                                        Modifier.size(16.dp)
                                                                                .align(
                                                                                        Alignment.CenterStart
                                                                                )
                                                                                .offset(x = 5.dp)
                                                        )
                                                }
                                                Spacer(modifier = Modifier.width(4.dp))
                                        } else if (dialog.lastMessageFromMe == 1) {
                                                // Показываем статус только для исходящих сообщений
                                                // (кроме Saved Messages)
                                                // Показываем READ только при реальном read-флаге
                                                // последнего исходящего сообщения.
                                                val isReadByOpponent =
                                                        when {
                                                                dialog.lastMessageDelivered == 3 -> true
                                                                dialog.lastMessageDelivered != 1 -> false
                                                                else -> dialog.lastMessageRead == 1
                                                        }

                                                when {
                                                        isReadByOpponent -> {
                                                                // READ - две синие галочки
                                                                Box(
                                                                        modifier =
                                                                                Modifier.width(20.dp)
                                                                                        .height(16.dp)
                                                                ) {
                                                                        Icon(
                                                                                painter =
                                                                                        TelegramIcons.Done,
                                                                                contentDescription =
                                                                                        null,
                                                                                tint = PrimaryBlue,
                                                                                modifier =
                                                                                        Modifier.size(
                                                                                                        16.dp
                                                                                                )
                                                                                                .align(
                                                                                                        Alignment.CenterStart
                                                                                                )
                                                                        )
                                                                        Icon(
                                                                                painter =
                                                                                        TelegramIcons.Done,
                                                                                contentDescription =
                                                                                        null,
                                                                                tint = PrimaryBlue,
                                                                                modifier =
                                                                                        Modifier.size(
                                                                                                        16.dp
                                                                                                )
                                                                                                .align(
                                                                                                        Alignment.CenterStart
                                                                                                )
                                                                                                .offset(
                                                                                                        x =
                                                                                                                5.dp
                                                                                                )
                                                                        )
                                                                }
                                                                Spacer(
                                                                        modifier =
                                                                                Modifier.width(4.dp)
                                                                )
                                                        }
                                                        dialog.lastMessageDelivered == 2 -> {
                                                                // ERROR - не показываем статус рядом с временем,
                                                                // error badge показывается внизу справа (как в Telegram)
                                                        }
                                                        dialog.lastMessageDelivered == 1 -> {
                                                                // DELIVERED - одна серая галочка
                                                                Icon(
                                                                        painter =
                                                                                TelegramIcons.Done,
                                                                        contentDescription = null,
                                                                        tint =
                                                                                secondaryTextColor
                                                                                        .copy(
                                                                                                alpha =
                                                                                                        0.6f
                                                                                        ),
                                                                        modifier =
                                                                                Modifier.size(16.dp)
                                                                )
                                                                Spacer(
                                                                        modifier =
                                                                                Modifier.width(4.dp)
                                                                )
                                                        }
                                                        else -> {
                                                                // SENDING (0) - часики
                                                                Icon(
                                                                        painter =
                                                                                TelegramIcons.Clock,
                                                                        contentDescription =
                                                                                "Sending",
                                                                        tint =
                                                                                secondaryTextColor
                                                                                        .copy(
                                                                                                alpha =
                                                                                                        0.6f
                                                                                        ),
                                                                        modifier =
                                                                                Modifier.size(16.dp)
                                                                )
                                                                Spacer(
                                                                        modifier =
                                                                                Modifier.width(4.dp)
                                                                )
                                                        }
                                                }
                                        }
                                        } // 📝 end if (draftText.isNullOrEmpty && !syncInProgress)

                                        val formattedTime =
                                                remember(dialog.lastMessageTimestamp) {
                                                        formatTime(
                                                                Date(dialog.lastMessageTimestamp)
                                                        )
                                                }
                                        Text(
                                                text = formattedTime,
                                                fontSize = 13.sp,
                                                lineHeight = 13.sp,
                                                color =
                                                        if (visibleUnreadCount > 0) PrimaryBlue
                                                        else secondaryTextColor,
                                                modifier = Modifier.align(Alignment.CenterVertically)
                                        )
                                }
                        }

                        Spacer(modifier = Modifier.height(4.dp))

                        Row(
                                modifier = Modifier.fillMaxWidth(),
                                horizontalArrangement = Arrangement.SpaceBetween,
                                verticalAlignment = Alignment.CenterVertically
                        ) {
                                // Stable weighted box prevents layout jitter on typing transition
                                Box(
                                        modifier = Modifier.weight(1f).heightIn(min = 20.dp),
                                        contentAlignment = Alignment.CenterStart
                                ) {
                                        val subtitleMode =
                                                remember(
                                                        isVoicePlaybackActive,
                                                        isTyping,
                                                        dialog.draftText
                                                ) {
                                                        when {
                                                                isVoicePlaybackActive -> "voice"
                                                                isTyping -> "typing"
                                                                !dialog.draftText.isNullOrEmpty() -> "draft"
                                                                else -> "message"
                                                        }
                                                }
                                        Crossfade(
                                                targetState = subtitleMode,
                                                animationSpec = tween(150),
                                                label = "chatSubtitle"
                                        ) { mode ->
                                                if (mode == "voice") {
                                                        VoicePlaybackIndicatorSmall(
                                                                isDarkTheme = isDarkTheme
                                                        )
                                                } else if (mode == "typing") {
                                                        TypingIndicatorSmall(
                                                                isDarkTheme = isDarkTheme,
                                                                typingDisplayName = typingDisplayName,
                                                                typingSenderPublicKey = typingSenderPublicKey
                                                        )
                                                } else if (mode == "draft") {
                                                        Row(verticalAlignment = Alignment.CenterVertically) {
                                                                Text(
                                                                        text = "Draft: ",
                                                                        fontSize = 14.sp,
                                                                        color = Color(0xFFFF3B30),
                                                                        fontWeight = FontWeight.Normal,
                                                                        maxLines = 1
                                                                )
                                                                AppleEmojiText(
                                                                        text = dialog.draftText.orEmpty(),
                                                                        modifier = Modifier.weight(1f),
                                                                        fontSize = 14.sp,
                                                                        color = secondaryTextColor,
                                                                        fontWeight = FontWeight.Normal,
                                                                        maxLines = 1,
                                                                        overflow = android.text.TextUtils.TruncateAt.END,
                                                                        enableLinks = false,
                                                                        minHeightMultiplier = 1f
                                                                )
                                                        }
                                                } else {
                                                        val baseDisplayText =
                                                                when {
                                                                        dialog.lastMessageAttachmentType ==
                                                                                "Photo" -> "Photo"
                                                                        dialog.lastMessageAttachmentType ==
                                                                                "File" -> "File"
                                                                        dialog.lastMessageAttachmentType ==
                                                                                "Avatar" -> "Avatar"
                                                                        dialog.lastMessageAttachmentType ==
                                                                                "Call" -> "Call"
                                                                        dialog.lastMessageAttachmentType ==
                                                                                "Voice message" -> "Voice message"
                                                                        dialog.lastMessageAttachmentType ==
                                                                                "Forwarded" ->
                                                                                "Forwarded message"
                                                                        dialog.lastMessage.isEmpty() ->
                                                                                "No messages"
                                                                        else -> dialog.lastMessage
                                                                }
                                                        val senderPrefix =
                                                                dialog.lastMessageSenderPrefix
                                                                        .orEmpty()
                                                                        .trim()
                                                        val showSenderPrefix =
                                                                isGroupDialog &&
                                                                        senderPrefix.isNotEmpty() &&
                                                                        baseDisplayText != "No messages"
                                                        val senderPrefixColor =
                                                                remember(
                                                                        showSenderPrefix,
                                                                        senderPrefix,
                                                                        dialog.lastMessageSenderKey,
                                                                        isDarkTheme
                                                                ) {
                                                                        when {
                                                                                !showSenderPrefix ->
                                                                                        secondaryTextColor
                                                                                senderPrefix.equals(
                                                                                        "You",
                                                                                        ignoreCase = true
                                                                                ) -> PrimaryBlue
                                                                                else -> {
                                                                                        val colorSeed =
                                                                                                dialog.lastMessageSenderKey
                                                                                                        ?.trim()
                                                                                                        .orEmpty()
                                                                                        val resolvedSeed =
                                                                                                if (colorSeed.isNotEmpty()) {
                                                                                                        colorSeed
                                                                                                } else {
                                                                                                        senderPrefix
                                                                                                }
                                                                                        getAvatarColor(
                                                                                                resolvedSeed,
                                                                                                isDarkTheme
                                                                                        )
                                                                                                .textColor
                                                                                }
                                                                        }
                                                                }

                                                        if (showSenderPrefix) {
                                                                Row(
                                                                        modifier =
                                                                                Modifier.fillMaxWidth(),
                                                                        verticalAlignment =
                                                                                Alignment.CenterVertically
                                                                ) {
                                                                        AppleEmojiText(
                                                                                text = "$senderPrefix:",
                                                                                fontSize = 14.sp,
                                                                                color = senderPrefixColor,
                                                                                fontWeight = FontWeight.Medium,
                                                                                maxLines = 1,
                                                                                overflow =
                                                                                        android.text.TextUtils.TruncateAt.END,
                                                                                modifier =
                                                                                        Modifier.widthIn(
                                                                                                max = 120.dp
                                                                                        ),
                                                                                enableLinks = false
                                                                        )
                                                                        Spacer(
                                                                                modifier =
                                                                                        Modifier.width(4.dp)
                                                                        )
                                                                        AppleEmojiText(
                                                                                text =
                                                                                        baseDisplayText,
                                                                                fontSize = 14.sp,
                                                                                color =
                                                                                        if (visibleUnreadCount >
                                                                                                        0
                                                                                        )
                                                                                                textColor.copy(
                                                                                                        alpha =
                                                                                                                0.85f
                                                                                                )
                                                                                        else
                                                                                                secondaryTextColor,
                                                                                fontWeight =
                                                                                        if (visibleUnreadCount >
                                                                                                        0
                                                                                        )
                                                                                                FontWeight.Medium
                                                                                        else
                                                                                                FontWeight.Normal,
                                                                                maxLines = 1,
                                                                                overflow =
                                                                                        android.text.TextUtils.TruncateAt.END,
                                                                                modifier =
                                                                                        Modifier.weight(
                                                                                                1f
                                                                                        ),
                                                                                enableLinks = false
                                                                        )
                                                                }
                                                        } else {
                                                                AppleEmojiText(
                                                                        text = baseDisplayText,
                                                                        fontSize = 14.sp,
                                                                        color =
                                                                                if (visibleUnreadCount > 0)
                                                                                        textColor.copy(alpha = 0.85f)
                                                                                else secondaryTextColor,
                                                                        fontWeight =
                                                                                if (visibleUnreadCount > 0)
                                                                                        FontWeight.Medium
                                                                                else FontWeight.Normal,
                                                                        maxLines = 1,
                                                                        overflow = android.text.TextUtils.TruncateAt.END,
                                                                        modifier = Modifier.fillMaxWidth(),
                                                                        enableLinks = false
                                                                )
                                                        }
                                                }
                                        }
                                }

                                // Error badge (Telegram-style) — красный кружок с "!" вместо unread badge
                                if (dialog.lastMessageFromMe == 1 && dialog.lastMessageDelivered == 2) {
                                        Spacer(modifier = Modifier.width(8.dp))
                                        Box(
                                                modifier =
                                                        Modifier.size(16.dp)
                                                                .clip(CircleShape)
                                                                .background(Color(0xFFE53935)),
                                                contentAlignment = Alignment.Center
                                        ) {
                                                Text(
                                                        text = "!",
                                                        fontSize = 10.sp,
                                                        fontWeight = FontWeight.Bold,
                                                        color = Color.White,
                                                        lineHeight = 10.sp,
                                                        maxLines = 1
                                                )
                                        }
                                }

                                // Unread badge
                                if (visibleUnreadCount > 0) {
                                        Spacer(modifier = Modifier.width(8.dp))
                                        val unreadText =
                                                remember(visibleUnreadCount) {
                                                        when {
                                                                visibleUnreadCount > 999 -> "999+"
                                                                visibleUnreadCount > 99 -> "99+"
                                                                else ->
                                                                        visibleUnreadCount
                                                                                .toString()
                                                        }
                                                }
                                        Box(
                                                modifier =
                                                        Modifier.height(22.dp)
                                                                .widthIn(min = 22.dp)
                                                                .clip(RoundedCornerShape(11.dp))
                                                                .background(PrimaryBlue)
                                                                .padding(horizontal = 6.dp),
                                                contentAlignment = Alignment.Center
                                        ) {
                                                Text(
                                                        text = unreadText,
                                                        fontSize = 12.sp,
                                                        fontWeight = FontWeight.Bold,
                                                        color = Color.White,
                                                        maxLines = 1
                                                )
                                        }
                                }

                                // 📌 Pin icon with smooth in/out animation
                                AnimatedVisibility(
                                        visible = isPinned,
                                        enter =
                                                fadeIn(animationSpec = tween(170)) +
                                                        scaleIn(
                                                                initialScale = 0.72f,
                                                                animationSpec =
                                                                        spring(
                                                                                dampingRatio =
                                                                                        Spring.DampingRatioLowBouncy,
                                                                                stiffness =
                                                                                        Spring.StiffnessMedium
                                                                        )
                                                        ),
                                        exit =
                                                fadeOut(animationSpec = tween(130)) +
                                                        scaleOut(
                                                                targetScale = 0.72f,
                                                                animationSpec = tween(130)
                                                        )
                                ) {
                                        Row(verticalAlignment = Alignment.CenterVertically) {
                                                Spacer(modifier = Modifier.width(6.dp))
                                                Icon(
                                                        painter = TelegramIcons.Pin,
                                                        contentDescription = "Pinned",
                                                        tint = secondaryTextColor.copy(alpha = 0.5f),
                                                        modifier = Modifier.size(16.dp)
                                                )
                                        }
                                }
                        }
                }
        }
}

/**
 * Telegram-style typing indicator for chat list — 3 bouncing Canvas circles
 * with sequential wave animation (scale + vertical offset + opacity).
 */
@Composable
fun TypingIndicatorSmall(
        isDarkTheme: Boolean,
        typingDisplayName: String = "",
        typingSenderPublicKey: String = ""
) {
        val typingColor = if (isDarkTheme) PrimaryBlue else Color(0xFF34C759)
        val senderTypingColor =
                remember(typingSenderPublicKey, isDarkTheme) {
                        if (typingSenderPublicKey.isBlank() || !isDarkTheme) {
                                typingColor
                        } else {
                                getAvatarColor(typingSenderPublicKey, isDarkTheme).textColor
                        }
                }
        val normalizedDisplayName = remember(typingDisplayName) { typingDisplayName.trim() }
        val infiniteTransition = rememberInfiniteTransition(label = "typing")

        // Each dot animates 0→1→0 in a 1200 ms cycle, staggered by 150 ms
        val dotProgresses = List(3) { index ->
                infiniteTransition.animateFloat(
                        initialValue = 0f,
                        targetValue = 1f,
                        animationSpec = infiniteRepeatable(
                                animation = keyframes {
                                        durationMillis = 1200
                                        0f at 0 with LinearEasing
                                        1f at 300 with FastOutSlowInEasing
                                        0f at 600 with FastOutSlowInEasing
                                        0f at 1200 with LinearEasing
                                },
                                repeatMode = RepeatMode.Restart,
                                initialStartOffset = StartOffset(index * 150)
                        ),
                        label = "dot$index"
                )
        }

        Row(
                modifier = Modifier.heightIn(min = 18.dp),
                verticalAlignment = Alignment.CenterVertically
        ) {
                if (normalizedDisplayName.isBlank()) {
                        AppleEmojiText(
                                text = "typing",
                                fontSize = 14.sp,
                                color = typingColor,
                                fontWeight = FontWeight.Medium,
                                enableLinks = false,
                                minHeightMultiplier = 1f
                        )
                } else {
                        AppleEmojiText(
                                text = "$normalizedDisplayName ",
                                fontSize = 14.sp,
                                color = senderTypingColor,
                                fontWeight = FontWeight.Medium,
                                maxLines = 1,
                                overflow = android.text.TextUtils.TruncateAt.END,
                                modifier = Modifier.widthIn(max = 180.dp),
                                enableLinks = false,
                                minHeightMultiplier = 1f
                        )
                        AppleEmojiText(
                                text = "typing",
                                fontSize = 14.sp,
                                color = typingColor,
                                fontWeight = FontWeight.Medium,
                                enableLinks = false,
                                minHeightMultiplier = 1f
                        )
                }
                Spacer(modifier = Modifier.width(2.dp))

                // Fixed-size canvas — big enough for bounce, never changes layout
                Canvas(modifier = Modifier.size(width = 18.dp, height = 14.dp)) {
                        val dotRadius = 1.5.dp.toPx()
                        val dotSpacing = 2.5.dp.toPx()
                        val maxBounce = 2.dp.toPx()
                        val centerY = size.height / 2f
                        for (i in 0..2) {
                                val p = dotProgresses[i].value
                                val bounce = kotlin.math.sin(p * Math.PI).toFloat()
                                val cx = dotRadius + i * (dotRadius * 2 + dotSpacing)
                                val cy = centerY - bounce * maxBounce
                                val alpha = 0.4f + bounce * 0.6f
                                drawCircle(
                                        color = typingColor.copy(alpha = alpha),
                                        radius = dotRadius,
                                        center = Offset(cx, cy)
                                )
                        }
                }
        }
}

@Composable
private fun VoicePlaybackIndicatorSmall(
        isDarkTheme: Boolean
) {
        val accentColor = if (isDarkTheme) PrimaryBlue else Color(0xFF2481CC)
        val transition = rememberInfiniteTransition(label = "voicePlaybackIndicator")
        val levels = List(3) { index ->
                transition.animateFloat(
                        initialValue = 0f,
                        targetValue = 1f,
                        animationSpec = infiniteRepeatable(
                                animation = keyframes {
                                        durationMillis = 900
                                        0f at 0
                                        1f at 280
                                        0.2f at 580
                                        0f at 900
                                },
                                repeatMode = RepeatMode.Restart,
                                initialStartOffset = StartOffset(index * 130)
                        ),
                        label = "voiceBar$index"
                ).value
        }

        Row(
                modifier = Modifier.heightIn(min = 18.dp),
                verticalAlignment = Alignment.CenterVertically
        ) {
                Canvas(modifier = Modifier.size(width = 14.dp, height = 12.dp)) {
                        val barWidth = 2.dp.toPx()
                        val gap = 2.dp.toPx()
                        val baseY = size.height
                        repeat(3) { index ->
                                val x = index * (barWidth + gap)
                                val progress = levels[index].coerceIn(0f, 1f)
                                val minH = 3.dp.toPx()
                                val maxH = 10.dp.toPx()
                                val height = minH + (maxH - minH) * progress
                                drawRoundRect(
                                        color = accentColor.copy(alpha = 0.6f + progress * 0.4f),
                                        topLeft = Offset(x, baseY - height),
                                        size = androidx.compose.ui.geometry.Size(barWidth, height),
                                        cornerRadius =
                                                androidx.compose.ui.geometry.CornerRadius(
                                                        x = barWidth,
                                                        y = barWidth
                                                )
                                )
                        }
                }
                Spacer(modifier = Modifier.width(5.dp))
                AppleEmojiText(
                        text = "Listening",
                        fontSize = 14.sp,
                        color = accentColor,
                        fontWeight = FontWeight.Medium,
                        maxLines = 1,
                        overflow = android.text.TextUtils.TruncateAt.END,
                        enableLinks = false,
                        minHeightMultiplier = 1f
                )
        }
}

fun formatVoiceSpeedLabel(speed: Float): String {
        val normalized = (speed * 10f).roundToInt() / 10f
        return if (kotlin.math.abs(normalized - normalized.toInt().toFloat()) < 0.01f) {
                "${normalized.toInt()}x"
        } else {
                "${normalized}x"
        }
}

@Composable
fun VoiceTopMiniPlayer(
        title: String,
        isDarkTheme: Boolean,
        isPlaying: Boolean,
        speed: Float,
        onTogglePlay: () -> Unit,
        onCycleSpeed: () -> Unit,
        onClose: () -> Unit
) {
        // Match overall screen surface aesthetic — neutral elevated surface, no blue accent
        val containerColor = if (isDarkTheme) Color(0xFF1C1C1E) else Color.White
        val dividerColor = if (isDarkTheme) Color(0xFF2A2A2C) else Color(0xFFE5E5EA)
        val primaryIconColor = if (isDarkTheme) Color.White else Color(0xFF1C1C1E)
        val textColor = if (isDarkTheme) Color.White else Color(0xFF1C1C1E)
        val secondaryColor = if (isDarkTheme) Color(0xFF8E8E93) else Color(0xFF8E8E93)

        Column(modifier = Modifier.fillMaxWidth().background(containerColor)) {
                Row(
                        modifier = Modifier.fillMaxWidth()
                                .height(40.dp)
                                .padding(horizontal = 8.dp),
                        verticalAlignment = Alignment.CenterVertically
                ) {
                        IconButton(
                                onClick = onTogglePlay,
                                modifier = Modifier.size(32.dp)
                        ) {
                                Icon(
                                        imageVector =
                                                if (isPlaying) Icons.Default.Pause
                                                else Icons.Default.PlayArrow,
                                        contentDescription = if (isPlaying) "Pause voice" else "Play voice",
                                        tint = primaryIconColor,
                                        modifier = Modifier.size(22.dp)
                                )
                        }

                        Spacer(modifier = Modifier.width(4.dp))

                        AppleEmojiText(
                                text = title,
                                fontSize = 14.sp,
                                color = textColor,
                                fontWeight = FontWeight.SemiBold,
                                maxLines = 1,
                                overflow = android.text.TextUtils.TruncateAt.END,
                                modifier = Modifier.weight(1f),
                                enableLinks = false,
                                minHeightMultiplier = 1f
                        )

                        Spacer(modifier = Modifier.width(8.dp))

                        Box(
                                modifier = Modifier.clip(RoundedCornerShape(8.dp))
                                        .border(1.dp, secondaryColor.copy(alpha = 0.4f), RoundedCornerShape(8.dp))
                                        .clickable { onCycleSpeed() }
                                        .padding(horizontal = 8.dp, vertical = 3.dp),
                                contentAlignment = Alignment.Center
                        ) {
                                Text(
                                        text = formatVoiceSpeedLabel(speed),
                                        color = secondaryColor,
                                        fontSize = 12.sp,
                                        fontWeight = FontWeight.SemiBold
                                )
                        }

                        Spacer(modifier = Modifier.width(4.dp))

                        IconButton(
                                onClick = onClose,
                                modifier = Modifier.size(32.dp)
                        ) {
                                Icon(
                                        imageVector = Icons.Default.Close,
                                        contentDescription = "Close voice",
                                        tint = secondaryColor,
                                        modifier = Modifier.size(20.dp)
                                )
                        }
                }
                Box(modifier = Modifier.fillMaxWidth().height(0.5.dp).background(dividerColor))
        }
}

@Composable
private fun SwipeBackContainer(
        onBack: () -> Unit,
        modifier: Modifier = Modifier,
        content: @Composable BoxScope.() -> Unit
) {
        Box(
                modifier =
                        modifier.fillMaxSize().pointerInput(onBack) {
                                val velocityTracker = VelocityTracker()
                                awaitEachGesture {
                                        val down = awaitFirstDown(requireUnconsumed = false)
                                        velocityTracker.resetTracking()
                                        velocityTracker.addPosition(down.uptimeMillis, down.position)
                                        var totalDragX = 0f
                                        var totalDragY = 0f
                                        var claimed = false
                                        val touchSlop = viewConfiguration.touchSlop * 0.6f

                                        while (true) {
                                                val event = awaitPointerEvent()
                                                val change =
                                                        event.changes.firstOrNull { it.id == down.id }
                                                                        ?: break
                                                if (change.changedToUpIgnoreConsumed()) break

                                                val delta = change.positionChange()
                                                totalDragX += delta.x
                                                totalDragY += delta.y
                                                velocityTracker.addPosition(
                                                        change.uptimeMillis,
                                                        change.position
                                                )

                                                if (!claimed) {
                                                        val distance =
                                                                kotlin.math.sqrt(
                                                                        totalDragX * totalDragX +
                                                                                totalDragY * totalDragY
                                                                )
                                                        if (distance < touchSlop) continue
                                                        if (
                                                                totalDragX > 0 &&
                                                                        kotlin.math.abs(totalDragX) >
                                                                                kotlin.math.abs(totalDragY) * 1.2f
                                                        ) {
                                                                claimed = true
                                                                change.consume()
                                                        } else {
                                                                break
                                                        }
                                                } else {
                                                        change.consume()
                                                }
                                        }

                                        if (claimed) {
                                                val velocityX = velocityTracker.calculateVelocity().x
                                                val screenWidth = size.width.toFloat()
                                                if (
                                                        totalDragX > screenWidth * 0.08f ||
                                                                velocityX > 200f
                                                ) {
                                                        onBack()
                                                }
                                        }
                                }
                        }
        ) {
                content()
        }
}

@Composable
private fun CallsRouteContent(
        isDarkTheme: Boolean,
        accountPublicKey: String,
        avatarRepository: AvatarRepository?,
        onUserSelect: (com.rosetta.messenger.network.SearchUser) -> Unit,
        onStartCall: (com.rosetta.messenger.network.SearchUser) -> Unit,
        onStartNewCall: () -> Unit,
        onBack: () -> Unit
) {
        SwipeBackContainer(onBack = onBack) {
                CallsHistoryScreen(
                        isDarkTheme = isDarkTheme,
                        accountPublicKey = accountPublicKey,
                        avatarRepository = avatarRepository,
                        onOpenChat = onUserSelect,
                        onStartCall = onStartCall,
                        onStartNewCall = onStartNewCall,
                        modifier = Modifier.fillMaxSize()
                )
        }
}

@Composable
private fun RequestsRouteContent(
        requests: List<DialogUiModel>,
        isDarkTheme: Boolean,
        avatarRepository: AvatarRepository?,
        blockedUsers: Set<String>,
        pinnedChats: Set<String>,
        isDrawerOpen: Boolean,
        onTogglePin: (String) -> Unit,
        onDeleteDialog: (String) -> Unit,
        onBlockUser: (String) -> Unit,
        onUnblockUser: (String) -> Unit,
        onRequestClick: (DialogUiModel) -> Unit,
        onBack: () -> Unit
) {
        SwipeBackContainer(onBack = onBack) {
                RequestsScreen(
                        requests = requests,
                        isDarkTheme = isDarkTheme,
                        onRequestClick = onRequestClick,
                        avatarRepository = avatarRepository,
                        blockedUsers = blockedUsers,
                        pinnedChats = pinnedChats,
                        isDrawerOpen = isDrawerOpen,
                        onTogglePin = onTogglePin,
                        onDeleteDialog = onDeleteDialog,
                        onBlockUser = onBlockUser,
                        onUnblockUser = onUnblockUser
                )
        }
}

@Composable
private fun FileDownloadsScreen(
        downloads: List<com.rosetta.messenger.network.FileDownloadState>,
        isDarkTheme: Boolean,
        modifier: Modifier = Modifier
) {
        val background = if (isDarkTheme) Color(0xFF1A1A1A) else Color(0xFFF2F2F7)
        val card = if (isDarkTheme) Color(0xFF212123) else Color.White
        val primaryText = if (isDarkTheme) Color.White else Color(0xFF111111)
        val secondaryText = if (isDarkTheme) Color(0xFF9B9B9F) else Color(0xFF6E6E73)
        val divider = if (isDarkTheme) Color(0xFF2F2F31) else Color(0xFFE7E7EC)

        if (downloads.isEmpty()) {
                Box(
                        modifier = modifier.background(background),
                        contentAlignment = Alignment.Center
                ) {
                        Column(horizontalAlignment = Alignment.CenterHorizontally) {
                                Icon(
                                        imageVector = TablerIcons.Download,
                                        contentDescription = null,
                                        tint = secondaryText,
                                        modifier = Modifier.size(34.dp)
                                )
                                Spacer(modifier = Modifier.height(10.dp))
                                Text(
                                        text = "No active file downloads",
                                        color = primaryText,
                                        fontSize = 16.sp,
                                        fontWeight = FontWeight.Medium
                                )
                                Spacer(modifier = Modifier.height(4.dp))
                                Text(
                                        text = "New file downloads will appear here.",
                                        color = secondaryText,
                                        fontSize = 13.sp
                                )
                        }
                }
                return
        }

        LazyColumn(
                modifier = modifier.background(background),
                contentPadding = PaddingValues(horizontal = 12.dp, vertical = 10.dp),
                verticalArrangement = Arrangement.spacedBy(8.dp)
        ) {
                items(items = downloads, key = { it.attachmentId }) { item ->
                        Surface(
                                color = card,
                                shape = RoundedCornerShape(14.dp),
                                tonalElevation = 0.dp
                        ) {
                                Column(modifier = Modifier.fillMaxWidth().padding(12.dp)) {
                                        Row(
                                                verticalAlignment = Alignment.CenterVertically
                                        ) {
                                                Box(
                                                        modifier = Modifier
                                                                .size(34.dp)
                                                                .clip(CircleShape)
                                                                .background(
                                                                        if (isDarkTheme) Color(0xFF2B4E6E)
                                                                        else Color(0xFFDCEEFF)
                                                                ),
                                                        contentAlignment = Alignment.Center
                                                ) {
                                                        Icon(
                                                                imageVector = TablerIcons.Download,
                                                                contentDescription = null,
                                                                tint = if (isDarkTheme) Color(0xFF8FC6FF) else Color(0xFF228BE6),
                                                                modifier = Modifier.size(18.dp)
                                                        )
                                                }
                                                Spacer(modifier = Modifier.width(10.dp))
                                                Column(modifier = Modifier.weight(1f)) {
                                                        Text(
                                                                text = item.fileName.ifBlank { "Unknown file" },
                                                                color = primaryText,
                                                                fontSize = 15.sp,
                                                                maxLines = 1,
                                                                overflow = TextOverflow.Ellipsis
                                                        )
                                                        Spacer(modifier = Modifier.height(2.dp))
                                                        Text(
                                                                text = formatDownloadStatusText(item),
                                                                color = secondaryText,
                                                                fontSize = 12.sp
                                                        )
                                                }
                                        }
                                        Spacer(modifier = Modifier.height(10.dp))
                                        LinearProgressIndicator(
                                                progress = item.progress.coerceIn(0f, 1f),
                                                modifier = Modifier
                                                        .fillMaxWidth()
                                                        .height(4.dp)
                                                        .clip(RoundedCornerShape(50)),
                                                color = if (isDarkTheme) Color(0xFF4DA6FF) else Color(0xFF228BE6),
                                                trackColor = if (isDarkTheme) Color(0xFF3A3A3D) else Color(0xFFD8D8DE)
                                        )
                                        Spacer(modifier = Modifier.height(8.dp))
                                        Divider(color = divider, thickness = 0.5.dp)
                                        Spacer(modifier = Modifier.height(6.dp))
                                        Text(
                                                text = item.savedPath.ifBlank { "Storage path unavailable" },
                                                color = secondaryText,
                                                fontSize = 11.sp,
                                                maxLines = 1,
                                                overflow = TextOverflow.Ellipsis
                                        )
                                }
                        }
                }
        }
}

private fun formatDownloadStatusText(
        item: com.rosetta.messenger.network.FileDownloadState
): String {
        val percent = (item.progress.coerceIn(0f, 1f) * 100).toInt().coerceIn(0, 100)
        return when (item.status) {
                com.rosetta.messenger.network.FileDownloadStatus.QUEUED -> "Queued"
                com.rosetta.messenger.network.FileDownloadStatus.DOWNLOADING -> "Downloading $percent%"
                com.rosetta.messenger.network.FileDownloadStatus.PAUSED -> "Paused $percent%"
                com.rosetta.messenger.network.FileDownloadStatus.DECRYPTING -> "Decrypting"
                com.rosetta.messenger.network.FileDownloadStatus.DONE -> "Completed"
                com.rosetta.messenger.network.FileDownloadStatus.ERROR -> "Download failed"
        }
}

/** 🎨 Enhanced Drawer Menu Item - пункт меню в стиле Telegram */
@Composable
fun DrawerMenuItemEnhanced(
        icon: androidx.compose.ui.graphics.vector.ImageVector,
        text: String,
        iconColor: Color,
        textColor: Color,
        badge: String? = null,
        badgeColor: Color = Color(0xFFE53935),
        onClick: () -> Unit
) {
        Row(
                modifier =
                        Modifier.fillMaxWidth()
                                .height(48.dp)
                                .clickable(onClick = onClick)
                                .padding(start = 19.dp, end = 16.dp),
                verticalAlignment = Alignment.CenterVertically
        ) {
                Icon(
                        imageVector = icon,
                        contentDescription = null,
                        tint = iconColor,
                        modifier = Modifier.size(24.dp)
                )

                Spacer(modifier = Modifier.width(29.dp))

                Text(
                        text = text,
                        fontSize = 15.sp,
                        fontWeight = FontWeight.Medium,
                        color = textColor,
                        modifier = Modifier.weight(1f)
                )

                badge?.let {
                        Box(
                                modifier =
                                        Modifier
                                                .defaultMinSize(minWidth = 22.dp, minHeight = 22.dp)
                                                .background(
                                                        color = badgeColor,
                                                        shape = CircleShape
                                                ),
                                contentAlignment = Alignment.Center
                        ) {
                                Text(
                                        text = it,
                                        fontSize = 12.sp,
                                        fontWeight = FontWeight.Bold,
                                        color = Color.White,
                                        lineHeight = 12.sp,
                                        modifier = Modifier.padding(horizontal = 5.dp, vertical = 3.dp)
                                )
                        }
                }
        }
}

/** 🎨 Enhanced Drawer Menu Item (Painter variant) - для XML drawable иконок */
@Composable
fun DrawerMenuItemEnhanced(
        painter: Painter,
        text: String,
        iconColor: Color,
        textColor: Color,
        badge: String? = null,
        badgeColor: Color = Color(0xFFE53935),
        onClick: () -> Unit
) {
        Row(
                modifier =
                        Modifier.fillMaxWidth()
                                .height(48.dp)
                                .clickable(onClick = onClick)
                                .padding(start = 19.dp, end = 16.dp),
                verticalAlignment = Alignment.CenterVertically
        ) {
                Icon(
                        painter = painter,
                        contentDescription = null,
                        tint = iconColor,
                        modifier = Modifier.size(24.dp)
                )

                Spacer(modifier = Modifier.width(29.dp))

                Text(
                        text = text,
                        fontSize = 15.sp,
                        fontWeight = FontWeight.Medium,
                        color = textColor,
                        modifier = Modifier.weight(1f)
                )

                badge?.let {
                        Box(
                                modifier =
                                        Modifier
                                                .defaultMinSize(minWidth = 22.dp, minHeight = 22.dp)
                                                .background(
                                                        color = badgeColor,
                                                        shape = CircleShape
                                                ),
                                contentAlignment = Alignment.Center
                        ) {
                                Text(
                                        text = it,
                                        fontSize = 12.sp,
                                        fontWeight = FontWeight.Bold,
                                        color = Color.White,
                                        lineHeight = 12.sp,
                                        modifier = Modifier.padding(horizontal = 5.dp, vertical = 3.dp)
                                )
                        }
                }
        }
}

/** 📏 Drawer Divider - разделитель между секциями */
@Composable
fun DrawerDivider(isDarkTheme: Boolean) {
        Spacer(modifier = Modifier.height(8.dp))
        Divider(
                modifier = Modifier.fillMaxWidth(),
                color = if (isDarkTheme) Color(0xFF2A2A2A) else Color(0xFFC8C8CC),
                thickness = 0.5.dp
        )
        Spacer(modifier = Modifier.height(8.dp))
}

/** 🔔 FCM Logs Section - отображение логов отправки FCM токена */
@Composable
fun FcmLogsSection(logs: List<String>, isDarkTheme: Boolean, onClearLogs: () -> Unit) {
        val backgroundColor = if (isDarkTheme) Color(0xFF2C2C2E) else Color(0xFFF8F9FA)
        val textColor = if (isDarkTheme) Color(0xFFE0E0E0) else Color(0xFF1A1A1A)
        val accentColor = if (isDarkTheme) Color(0xFF4A90D9) else Color(0xFF2979FF)

        var expanded by remember { mutableStateOf(true) }

        Column(modifier = Modifier.fillMaxWidth().background(backgroundColor)) {
                // Header
                Row(
                        modifier =
                                Modifier.fillMaxWidth()
                                        .clickable { expanded = !expanded }
                                        .padding(horizontal = 16.dp, vertical = 12.dp),
                        verticalAlignment = Alignment.CenterVertically
                ) {
                        Icon(
                                imageVector =
                                        if (expanded) TablerIcons.ChevronDown
                                        else TablerIcons.ChevronRight,
                                contentDescription = null,
                                tint = accentColor,
                                modifier = Modifier.size(24.dp)
                        )

                        Spacer(modifier = Modifier.width(12.dp))

                        Text(
                                text = "🔔 FCM Token Status",
                                fontSize = 16.sp,
                                fontWeight = FontWeight.Bold,
                                color = textColor,
                                modifier = Modifier.weight(1f)
                        )

                        // Clear button
                        if (logs.isNotEmpty()) {
                                TextButton(
                                        onClick = onClearLogs,
                                        contentPadding =
                                                PaddingValues(horizontal = 8.dp, vertical = 4.dp)
                                ) { Text(text = "Clear", fontSize = 13.sp, color = accentColor) }
                        }
                }

                // Logs content
                AnimatedVisibility(
                        visible = expanded,
                        enter = expandVertically() + fadeIn(),
                        exit = shrinkVertically() + fadeOut()
                ) {
                        Column(
                                modifier =
                                        Modifier.fillMaxWidth()
                                                .padding(horizontal = 16.dp, vertical = 8.dp)
                                                .background(
                                                        color =
                                                                if (isDarkTheme) Color(0xFF1A1A1A)
                                                                else Color.White,
                                                        shape = RoundedCornerShape(8.dp)
                                                )
                                                .padding(12.dp)
                        ) {
                                if (logs.isEmpty()) {
                                        Text(
                                                text = "No FCM logs yet...",
                                                fontSize = 14.sp,
                                                color =
                                                        if (isDarkTheme) Color(0xFF8E8E8E)
                                                        else Color(0xFF999999),
                                                fontFamily = FontFamily.Monospace
                                        )
                                } else {
                                        logs.take(10).forEach { log ->
                                                Text(
                                                        text = log,
                                                        fontSize = 12.sp,
                                                        color = textColor,
                                                        fontFamily = FontFamily.Monospace,
                                                        lineHeight = 18.sp,
                                                        modifier = Modifier.padding(vertical = 2.dp)
                                                )
                                        }

                                        if (logs.size > 10) {
                                                Spacer(modifier = Modifier.height(4.dp))
                                                Text(
                                                        text = "... и ещё ${logs.size - 10} логов",
                                                        fontSize = 11.sp,
                                                        color =
                                                                if (isDarkTheme) Color(0xFF8E8E8E)
                                                                else Color(0xFF999999),
                                                        fontStyle =
                                                                androidx.compose.ui.text.font
                                                                        .FontStyle.Italic
                                                )
                                        }
                                }
                        }
                }

                Spacer(modifier = Modifier.height(8.dp))
        }
}
