package com.rosetta.messenger.ui.chats

import android.content.Context
import android.view.inputmethod.InputMethodManager
import androidx.activity.compose.BackHandler
import androidx.compose.animation.*
import androidx.compose.animation.core.*
import androidx.compose.foundation.*
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.lazy.grid.items
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.BasicTextField
import com.rosetta.messenger.ui.icons.TelegramIcons
import compose.icons.TablerIcons
import compose.icons.tablericons.*
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Verified
import androidx.compose.material.icons.filled.InsertDriveFile
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.drawWithContent
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.platform.LocalHapticFeedback
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.foundation.gestures.detectHorizontalDragGestures
import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.res.painterResource
import com.rosetta.messenger.repository.AvatarRepository
import com.rosetta.messenger.ui.components.AvatarImage
import com.rosetta.messenger.ui.components.VerifiedBadge
import com.rosetta.messenger.database.RosettaDatabase
import com.rosetta.messenger.database.MessageSearchIndexEntity
import com.rosetta.messenger.network.AttachmentType
import com.rosetta.messenger.network.MessageAttachment
import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.hilt.navigation.compose.hiltViewModel
import com.airbnb.lottie.compose.*
import com.rosetta.messenger.R
import com.rosetta.messenger.data.AccountManager
import com.rosetta.messenger.data.MessageRepository
import com.rosetta.messenger.data.RecentSearchesManager
import com.rosetta.messenger.data.isPlaceholderAccountName
import com.rosetta.messenger.network.ProtocolState
import com.rosetta.messenger.network.SearchUser
import com.rosetta.messenger.ui.onboarding.PrimaryBlue as AppPrimaryBlue
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.sync.withPermit
import kotlinx.coroutines.withContext
import org.json.JSONArray
import java.io.File
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
import java.util.concurrent.ConcurrentHashMap
import com.rosetta.messenger.crypto.CryptoManager
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.withStyle

// Primary Blue color
private val PrimaryBlue = Color(0xFF54A9EB)

/** Вкладки поиска как в Telegram */
private enum class SearchTab(val title: String) {
    CHATS("Chats"),
    MESSAGES("Messages"),
    MEDIA("Media"),
    DOWNLOADS("Downloads"),
    FILES("Files")
}

/** Отдельная страница поиска пользователей Хедер на всю ширину с полем ввода */
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun SearchScreen(
        privateKeyHash: String,
        currentUserPublicKey: String,
        accountManager: AccountManager,
        messageRepository: MessageRepository,
        isDarkTheme: Boolean,
        protocolState: ProtocolState,
        onBackClick: () -> Unit,
        onUserSelect: (SearchUser) -> Unit,
        onNavigateToCrashLogs: () -> Unit = {},
        onNavigateToConnectionLogs: () -> Unit = {}
) {
    // Context и View для мгновенного закрытия клавиатуры
    val context = LocalContext.current
    val view = LocalView.current
    val focusManager = LocalFocusManager.current
    if (!view.isInEditMode) {
        DisposableEffect(isDarkTheme) {
            val window = (view.context as android.app.Activity).window
            val insetsController = androidx.core.view.WindowCompat.getInsetsController(window, view)
            insetsController.isAppearanceLightStatusBars = false
            window.statusBarColor = android.graphics.Color.TRANSPARENT
            onDispose {
                // Restore white status bar icons for chat list header
                insetsController.isAppearanceLightStatusBars = false
            }
        }
    }

    // 🔥 Функция мгновенного закрытия клавиатуры
    val hideKeyboardInstantly: () -> Unit = {
        val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
        imm.hideSoftInputFromWindow(view.windowToken, 0)
        focusManager.clearFocus()
    }

    // Цвета ТОЧНО как в ChatsListScreen - remember для избежания пересоздания
    val backgroundColor =
            remember(isDarkTheme) { if (isDarkTheme) Color(0xFF1A1A1A) else Color(0xFFFFFFFF) }
    val textColor = remember(isDarkTheme) { if (isDarkTheme) Color.White else Color(0xFF1a1a1a) }
    val secondaryTextColor =
            remember(isDarkTheme) { if (isDarkTheme) Color(0xFFB0B0B0) else Color(0xFF6c757d) }

    // 🔥 ОПТИМИЗАЦИЯ: Отложенный рендеринг контента для плавной анимации перехода
    var isContentReady by remember { mutableStateOf(false) }

    // Search ViewModel - правильное создание через viewModel()
    val searchViewModel: SearchUsersViewModel = hiltViewModel()
    val searchQuery by searchViewModel.searchQuery.collectAsState()
    val searchResults by searchViewModel.searchResults.collectAsState()
    val isSearching by searchViewModel.isSearching.collectAsState()
    var ownAccountName by remember(currentUserPublicKey) { mutableStateOf("") }
    var ownAccountUsername by remember(currentUserPublicKey) { mutableStateOf("") }

    // Easter egg: navigate to CrashLogs when typing "rosettadev1"
    LaunchedEffect(searchQuery) {
        if (searchQuery.trim().equals("rosettadev1", ignoreCase = true)) {
            searchViewModel.clearSearchQuery()
            onNavigateToCrashLogs()
            return@LaunchedEffect
        }
        if (searchQuery.trim().equals("rosettadev2", ignoreCase = true)) {
            searchViewModel.clearSearchQuery()
            onNavigateToConnectionLogs()
        }
    }

    // Always reset query/results when leaving Search screen (back/swipe/navigation).
    DisposableEffect(Unit) { onDispose { searchViewModel.clearSearchQuery() } }

    // Keep private key hash in sync with active account.
    LaunchedEffect(privateKeyHash) {
        searchViewModel.setPrivateKeyHash(privateKeyHash)
    }

    // Keep own account metadata for local "Saved Messages" search fallback.
    LaunchedEffect(currentUserPublicKey) {
        if (currentUserPublicKey.isBlank()) {
            ownAccountName = ""
            ownAccountUsername = ""
            return@LaunchedEffect
        }

        val account = accountManager.getAccount(currentUserPublicKey)
        ownAccountName = account?.name?.trim().orEmpty()
        ownAccountUsername = account?.username?.trim().orEmpty()
    }

    // Recent users - отложенная подписка
    val recentUsers by RecentSearchesManager.recentUsers.collectAsState()

    // AvatarRepository для загрузки аватаров
    val avatarRepository = remember(currentUserPublicKey) {
        if (currentUserPublicKey.isNotBlank()) {
            val database = RosettaDatabase.getDatabase(context)
            AvatarRepository(
                context = context,
                avatarDao = database.avatarDao(),
                currentPublicKey = currentUserPublicKey
            )
        } else {
            null
        }
    }

    // 🔥 ОПТИМИЗАЦИЯ: Lottie загружается асинхронно и не блокирует первый кадр
    val searchLottieComposition by
            rememberLottieComposition(LottieCompositionSpec.RawRes(R.raw.search))

    // Focus requester для автофокуса
    val focusRequester = remember { FocusRequester() }

    // Fullscreen image viewer state — lifted to top level for true fullscreen overlay
    var showImageViewer by remember { mutableStateOf(false) }
    var imageViewerInitialIndex by remember { mutableStateOf(0) }
    var imageViewerImages by remember { mutableStateOf<List<com.rosetta.messenger.ui.chats.components.ViewableImage>>(emptyList()) }
    var imageViewerPrivateKey by remember { mutableStateOf("") }

    // 🔥 Обработка системного жеста Back
    BackHandler {
        if (showImageViewer) {
            showImageViewer = false
            return@BackHandler
        }
        hideKeyboardInstantly()
        searchViewModel.clearSearchQuery()
        onBackClick()
    }

    // 🔥 ОПТИМИЗАЦИЯ: Все тяжелые операции выполняем после первого кадра
    LaunchedEffect(Unit) {
        // Даем анимации перехода завершиться
        kotlinx.coroutines.delay(50)
        isContentReady = true

        // Устанавливаем аккаунт для RecentSearchesManager
        if (currentUserPublicKey.isNotEmpty()) {
            RecentSearchesManager.setAccount(currentUserPublicKey)
        }

        // Автофокус с небольшой задержкой
        kotlinx.coroutines.delay(100)
        try {
            focusRequester.requestFocus()
        } catch (e: Exception) {
            // Игнорируем ошибки фокуса
        }
    }

    Box(modifier = Modifier.fillMaxSize()) {
    val hideKbScrollConnection = remember { HideKeyboardNestedScroll(view, focusManager) }
    Scaffold(
            modifier = Modifier.nestedScroll(hideKbScrollConnection),
            topBar = {
                // Хедер как в Telegram: стрелка назад + поле ввода
                Surface(
                        modifier = Modifier.fillMaxWidth(),
                        color = backgroundColor
                ) {
                    Row(
                            modifier =
                                    Modifier.fillMaxWidth()
                                            .statusBarsPadding()
                                            .height(56.dp)
                                            .padding(start = 4.dp, end = 4.dp),
                            verticalAlignment = Alignment.CenterVertically
                    ) {
                        // Кнопка назад
                        IconButton(
                                onClick = {
                                    hideKeyboardInstantly()
                                    searchViewModel.clearSearchQuery()
                                    onBackClick()
                                }
                        ) {
                            Icon(
                                    painter = TelegramIcons.ArrowBack,
                                    contentDescription = "Back",
                                    tint = textColor.copy(alpha = 0.7f)
                            )
                        }

                        // Чистое поле ввода без подчёркивания
                        BasicTextField(
                                value = searchQuery,
                                onValueChange = { searchViewModel.onSearchQueryChange(it) },
                                textStyle = androidx.compose.ui.text.TextStyle(
                                        fontSize = 18.sp,
                                        fontWeight = FontWeight.Normal,
                                        color = textColor
                                ),
                                cursorBrush = androidx.compose.ui.graphics.SolidColor(PrimaryBlue),
                                singleLine = true,
                                enabled = protocolState == ProtocolState.AUTHENTICATED,
                                modifier = Modifier
                                        .weight(1f)
                                        .focusRequester(focusRequester),
                                decorationBox = { innerTextField ->
                                    Box(
                                            modifier = Modifier.fillMaxHeight(),
                                            contentAlignment = Alignment.CenterStart
                                    ) {
                                        if (searchQuery.isEmpty()) {
                                            Text(
                                                    "Search",
                                                    color = secondaryTextColor.copy(alpha = 0.5f),
                                                    fontSize = 18.sp,
                                                    fontWeight = FontWeight.Normal
                                            )
                                        }
                                        innerTextField()
                                    }
                                }
                        )

                        // Кнопка очистки
                        AnimatedVisibility(
                                visible = searchQuery.isNotEmpty(),
                                enter = fadeIn(tween(150)) + scaleIn(tween(150)),
                                exit = fadeOut(tween(150)) + scaleOut(tween(150))
                        ) {
                            IconButton(onClick = { searchViewModel.clearSearchQuery() }) {
                                Icon(
                                        painter = TelegramIcons.Close,
                                        contentDescription = "Clear",
                                        tint = secondaryTextColor.copy(alpha = 0.5f),
                                        modifier = Modifier.size(20.dp)
                                )
                            }
                        }
                    }
                }
            },
            containerColor = backgroundColor
    ) { paddingValues ->
        // ─── Состояние вкладок ───
        var selectedTab by remember { mutableStateOf(SearchTab.CHATS) }

        Column(
                modifier =
                        Modifier.fillMaxSize()
                                .padding(paddingValues)
                                .drawWithContent {
                                    if (isContentReady) {
                                        drawContent()
                                    }
                                }
        ) {
            // ═══════ Tab Row как в Telegram ═══════
            ScrollableTabRow(
                    selectedTabIndex = SearchTab.entries.indexOf(selectedTab),
                    containerColor = backgroundColor,
                    contentColor = PrimaryBlue,
                    edgePadding = 12.dp,
                    divider = {
                        Divider(
                                color = if (isDarkTheme) Color(0xFF2A2A2A) else Color(0xFFE0E0E0),
                                thickness = 0.5.dp
                        )
                    }
            ) {
                SearchTab.entries.forEach { tab ->
                    Tab(
                            selected = selectedTab == tab,
                            onClick = { selectedTab = tab },
                            text = {
                                Text(
                                        text = tab.title,
                                        fontSize = 14.sp,
                                        fontWeight =
                                                if (selectedTab == tab) FontWeight.SemiBold
                                                else FontWeight.Normal,
                                        maxLines = 1
                                )
                            },
                            selectedContentColor = PrimaryBlue,
                            unselectedContentColor = secondaryTextColor
                    )
                }
            }

            // ═══════ Tab Content ═══════
            when (selectedTab) {
                SearchTab.CHATS -> {
                    ChatsTabContent(
                            searchQuery = searchQuery,
                            searchResults = searchResults,
                            isSearching = isSearching,
                            recentUsers = recentUsers,
                            currentUserPublicKey = currentUserPublicKey,
                            ownAccountName = ownAccountName,
                            ownAccountUsername = ownAccountUsername,
                            isDarkTheme = isDarkTheme,
                            textColor = textColor,
                            secondaryTextColor = secondaryTextColor,
                            avatarRepository = avatarRepository,
                            searchLottieComposition = searchLottieComposition,
                            hideKeyboardInstantly = hideKeyboardInstantly,
                            onUserSelect = onUserSelect
                    )
                }
                SearchTab.MESSAGES -> {
                    MessagesTabContent(
                            searchQuery = searchQuery,
                            currentUserPublicKey = currentUserPublicKey,
                            messageRepository = messageRepository,
                            isDarkTheme = isDarkTheme,
                            textColor = textColor,
                            secondaryTextColor = secondaryTextColor,
                            avatarRepository = avatarRepository,
                            searchLottieComposition = searchLottieComposition,
                            onUserSelect = onUserSelect
                    )
                }
                SearchTab.MEDIA -> {
                    MediaTabContent(
                            currentUserPublicKey = currentUserPublicKey,
                            messageRepository = messageRepository,
                            isDarkTheme = isDarkTheme,
                            textColor = textColor,
                            secondaryTextColor = secondaryTextColor,
                            onOpenImageViewer = { images, index, privateKey ->
                                imageViewerImages = images
                                imageViewerInitialIndex = index
                                imageViewerPrivateKey = privateKey
                                showImageViewer = true
                            }
                    )
                }
                SearchTab.DOWNLOADS -> {
                    DownloadsTabContent(
                            isDarkTheme = isDarkTheme,
                            textColor = textColor,
                            secondaryTextColor = secondaryTextColor
                    )
                }
                SearchTab.FILES -> {
                    FilesTabContent(
                            currentUserPublicKey = currentUserPublicKey,
                            isDarkTheme = isDarkTheme,
                            textColor = textColor,
                            secondaryTextColor = secondaryTextColor
                    )
                }
            }
        }
    } // End Scaffold

    // Fullscreen image viewer overlay — rendered OUTSIDE Scaffold for true fullscreen
    if (showImageViewer && imageViewerImages.isNotEmpty()) {
        com.rosetta.messenger.ui.chats.components.ImageViewerScreen(
                images = imageViewerImages,
                initialIndex = imageViewerInitialIndex.coerceIn(0, imageViewerImages.lastIndex),
                privateKey = imageViewerPrivateKey,
                onDismiss = {
                    showImageViewer = false
                    imageViewerImages = emptyList()
                },
                isDarkTheme = isDarkTheme
        )
    }
    } // End outer Box
}

// ═══════════════════════════════════════════════════════════
// 💬 CHATS TAB — existing search logic
// ═══════════════════════════════════════════════════════════

@Composable
private fun ChatsTabContent(
        searchQuery: String,
        searchResults: List<SearchUser>,
        isSearching: Boolean,
        recentUsers: List<SearchUser>,
        currentUserPublicKey: String,
        ownAccountName: String,
        ownAccountUsername: String,
        isDarkTheme: Boolean,
        textColor: Color,
        secondaryTextColor: Color,
        avatarRepository: AvatarRepository?,
        searchLottieComposition: com.airbnb.lottie.LottieComposition?,
        hideKeyboardInstantly: () -> Unit,
        onUserSelect: (SearchUser) -> Unit
) {
    val context = LocalContext.current
    val dividerColor = remember(isDarkTheme) {
        if (isDarkTheme) Color(0xFF2A2A2A) else Color(0xFFE8E8E8)
    }
    val suggestionsPrefs = remember(currentUserPublicKey) {
        context.getSharedPreferences("search_suggestions", Context.MODE_PRIVATE)
    }
    val hiddenSuggestionsKey = remember(currentUserPublicKey) {
        "hidden_frequent_${currentUserPublicKey}"
    }

    // ─── Загрузка частых контактов из БД (top dialogs) ───
    var frequentContacts by remember { mutableStateOf<List<FrequentContact>>(emptyList()) }
    var hiddenSuggestionKeys by remember(currentUserPublicKey) { mutableStateOf<Set<String>>(emptySet()) }
    var frequentSuggestionToRemove by remember { mutableStateOf<FrequentContact?>(null) }

    LaunchedEffect(currentUserPublicKey) {
        hiddenSuggestionKeys =
            suggestionsPrefs.getStringSet(hiddenSuggestionsKey, emptySet())?.toSet() ?: emptySet()
    }

    LaunchedEffect(currentUserPublicKey) {
        if (currentUserPublicKey.isBlank()) return@LaunchedEffect
        withContext(Dispatchers.IO) {
            try {
                val db = RosettaDatabase.getDatabase(context)
                val dialogs = db.dialogDao().getDialogsPaged(currentUserPublicKey, 15, 0)
                frequentContacts = dialogs
                        .filter {
                            it.opponentKey != currentUserPublicKey &&
                            !it.opponentKey.startsWith("#group:") &&
                            !it.opponentKey.startsWith("group:") &&
                            it.opponentKey != "0x000000000000000000000000000000000000000001" &&
                            it.opponentKey != "0x000000000000000000000000000000000000000002"
                        }
                        .map { dialog ->
                            FrequentContact(
                                    publicKey = dialog.opponentKey,
                                    name = dialog.opponentTitle.ifBlank {
                                        dialog.opponentKey.take(6) + "…"
                                    },
                                    username = dialog.opponentUsername,
                                    verified = dialog.verified,
                                    isOnline = dialog.isOnline == 1
                            )
                        }
            } catch (_: Exception) { }
        }
    }
    val visibleFrequentContacts = remember(frequentContacts, hiddenSuggestionKeys) {
        frequentContacts.filterNot { hiddenSuggestionKeys.contains(it.publicKey) }
    }
    fun removeFrequentSuggestion(publicKey: String) {
        val updated = (hiddenSuggestionKeys + publicKey).toSet()
        hiddenSuggestionKeys = updated
        suggestionsPrefs.edit().putStringSet(hiddenSuggestionsKey, updated).apply()
    }

    Box(modifier = Modifier.fillMaxSize()) {
        if (searchQuery.isEmpty()) {
            // ═══ Idle state: frequent contacts + recent searches ═══
            LazyColumn(
                    modifier = Modifier.fillMaxSize().imePadding()
            ) {
                // ─── Горизонтальный ряд частых контактов (как в Telegram) ───
                if (visibleFrequentContacts.isNotEmpty()) {
                    item {
                        FrequentContactsRow(
                                contacts = visibleFrequentContacts,
                                avatarRepository = avatarRepository,
                                isDarkTheme = isDarkTheme,
                                textColor = textColor,
                                onClick = { contact ->
                                    hideKeyboardInstantly()
                                    val user = SearchUser(
                                            title = contact.name,
                                            username = contact.username,
                                            publicKey = contact.publicKey,
                                            verified = 0,
                                            online = 0
                                    )
                                    RecentSearchesManager.addUser(user)
                                    onUserSelect(user)
                                },
                                onLongPress = { contact ->
                                    frequentSuggestionToRemove = contact
                                }
                        )
                    }

                    // Сепаратор после частых контактов
                    item {
                        Divider(
                                color = dividerColor,
                                thickness = 0.5.dp,
                                modifier = Modifier.padding(start = 16.dp)
                        )
                    }
                }

                // ─── Recent header (only when there are recents) ───
                if (recentUsers.isNotEmpty()) {
                    item {
                        Row(
                                modifier = Modifier
                                        .fillMaxWidth()
                                        .padding(horizontal = 16.dp)
                                        .padding(top = 14.dp, bottom = 6.dp),
                                horizontalArrangement = Arrangement.SpaceBetween,
                                verticalAlignment = Alignment.CenterVertically
                        ) {
                            Text(
                                    "Recent",
                                    fontSize = 15.sp,
                                    fontWeight = FontWeight.SemiBold,
                                    color = PrimaryBlue
                            )
                            Text(
                                    "Clear All",
                                    fontSize = 13.sp,
                                    fontWeight = FontWeight.Normal,
                                    color = PrimaryBlue,
                                    modifier = Modifier.clickable { RecentSearchesManager.clearAll() }
                            )
                        }
                    }
                }

                // ─── Recent users list (only actually searched users) ───
                if (recentUsers.isNotEmpty()) {
                    items(recentUsers, key = { it.publicKey }) { user ->
                        RecentUserItem(
                                user = user,
                                isDarkTheme = isDarkTheme,
                                textColor = textColor,
                                secondaryTextColor = secondaryTextColor,
                                avatarRepository = avatarRepository,
                                onClick = {
                                    hideKeyboardInstantly()
                                    RecentSearchesManager.addUser(user)
                                    onUserSelect(user)
                                },
                                onRemove = { RecentSearchesManager.removeUser(user.publicKey) }
                        )
                        // Сепаратор между элементами
                        Divider(
                                color = dividerColor,
                                thickness = 0.5.dp,
                                modifier = Modifier.padding(start = 76.dp)
                        )
                    }
                } else {
                    // Empty state when no recent searches — Lottie search animation
                    item {
                        Column(
                                modifier = Modifier
                                        .fillMaxWidth()
                                        .padding(top = 48.dp),
                                horizontalAlignment = Alignment.CenterHorizontally
                        ) {
                            if (searchLottieComposition != null) {
                                val lottieProgress by animateLottieCompositionAsState(
                                        composition = searchLottieComposition,
                                        iterations = LottieConstants.IterateForever
                                )
                                LottieAnimation(
                                        composition = searchLottieComposition,
                                        progress = { lottieProgress },
                                        modifier = Modifier.size(100.dp)
                                )
                            }
                            Spacer(modifier = Modifier.height(12.dp))
                            Text(
                                    text = "Search for chats and users",
                                    fontSize = 14.sp,
                                    color = secondaryTextColor
                            )
                        }
                    }
                }
            }
        } else if (isSearching) {
            // ═══ Skeleton loading while searching ═══
            SearchSkeleton(isDarkTheme = isDarkTheme)
        } else {
            // ═══ Search results ═══
            val normalizedQuery = searchQuery.trim().removePrefix("@").lowercase()
            val compactQuery = normalizedQuery.replace(Regex("\\s+"), " ").trim()
            val normalizedPublicKey = currentUserPublicKey.lowercase()
            val normalizedUsername = ownAccountUsername.removePrefix("@").trim().lowercase()
            val normalizedName = ownAccountName.trim().lowercase()
            val hasValidOwnName =
                    ownAccountName.isNotBlank() && !isPlaceholderAccountName(ownAccountName)
            val savedMessagesAliases =
                    listOf(
                            "saved",
                            "saved message",
                            "saved messages",
                            "savedmessages",
                            "bookmarks",
                            "bookmark",
                            "избранное",
                            "сохраненное",
                            "сохранённое",
                            "сохраненные",
                            "сохранённые"
                    )
            val isSavedAliasSearch =
                    compactQuery.length >= 3 &&
                            savedMessagesAliases.any { alias ->
                                alias.startsWith(compactQuery) || compactQuery.startsWith(alias)
                            }
            val isSavedMessagesSearch =
                    normalizedQuery.isNotEmpty() &&
                            (isSavedAliasSearch ||
                                    normalizedPublicKey == normalizedQuery ||
                                    normalizedPublicKey.startsWith(normalizedQuery) ||
                                    normalizedPublicKey.take(8) == normalizedQuery ||
                                    normalizedPublicKey.takeLast(8) == normalizedQuery ||
                                    (normalizedUsername.isNotEmpty() &&
                                            normalizedUsername.startsWith(normalizedQuery)) ||
                                    (hasValidOwnName &&
                                            normalizedName.startsWith(normalizedQuery)))

            val resultsWithSavedMessages =
                    if (isSavedMessagesSearch &&
                                    searchResults.none { it.publicKey == currentUserPublicKey }
                    ) {
                        listOf(
                                SearchUser(
                                        title = "Saved Messages",
                                        username = "",
                                        publicKey = currentUserPublicKey,
                                        verified = 0,
                                        online = 1
                                )
                        ) + searchResults.filter { it.publicKey != currentUserPublicKey }
                    } else {
                        searchResults
                    }

            SearchResultsList(
                    searchResults = resultsWithSavedMessages,
                    isSearching = false,
                    currentUserPublicKey = currentUserPublicKey,
                    isDarkTheme = isDarkTheme,
                    preloadedComposition = searchLottieComposition,
                    avatarRepository = avatarRepository,
                    onUserClick = { user ->
                        hideKeyboardInstantly()
                        if (user.publicKey != currentUserPublicKey) {
                            RecentSearchesManager.addUser(user)
                        }
                        onUserSelect(user)
                    }
            )
        }
        frequentSuggestionToRemove?.let { contact ->
            val scrimColor = if (isDarkTheme) Color.Black.copy(alpha = 0.42f) else Color.Black.copy(alpha = 0.24f)
            val popupColor = if (isDarkTheme) Color(0xFF2C2C2E) else Color.White
            val popupSecondaryText = if (isDarkTheme) Color(0xFFAEAEB2) else Color(0xFF6D6D72)

            Box(
                modifier =
                    Modifier
                        .matchParentSize()
                        .background(scrimColor)
                        .clickable(
                            indication = null,
                            interactionSource = remember { MutableInteractionSource() }
                        ) { frequentSuggestionToRemove = null }
            )

            Surface(
                modifier =
                    Modifier
                        .align(Alignment.BottomCenter)
                        .imePadding()
                        .padding(start = 20.dp, end = 20.dp, bottom = 14.dp),
                color = popupColor,
                shape = RoundedCornerShape(18.dp),
                tonalElevation = 0.dp,
                shadowElevation = 0.dp
            ) {
                Column(
                    modifier = Modifier.padding(horizontal = 18.dp, vertical = 16.dp)
                ) {
                    Text(
                        text = "Remove suggestion",
                        color = textColor,
                        fontWeight = FontWeight.Bold,
                        fontSize = 17.sp
                    )
                    Spacer(modifier = Modifier.height(8.dp))
                    Text(
                        text = "Are you sure you want to remove ${contact.name} from suggestions?",
                        color = popupSecondaryText,
                        fontSize = 16.sp,
                        lineHeight = 22.sp
                    )
                    Spacer(modifier = Modifier.height(12.dp))
                    Row(
                        modifier = Modifier.fillMaxWidth(),
                        horizontalArrangement = Arrangement.End
                    ) {
                        TextButton(onClick = { frequentSuggestionToRemove = null }) {
                            Text("Cancel", color = AppPrimaryBlue, fontSize = 17.sp)
                        }
                        TextButton(
                            onClick = {
                                removeFrequentSuggestion(contact.publicKey)
                                frequentSuggestionToRemove = null
                            }
                        ) {
                            Text("Remove", color = Color(0xFFFF5A5F), fontSize = 17.sp)
                        }
                    }
                }
            }
        }
    }
}

// ═══════════════════════════════════════════════════════════
// 👥 FREQUENT CONTACTS ROW (horizontal, like Telegram)
// ═══════════════════════════════════════════════════════════

private data class FrequentContact(
        val publicKey: String,
        val name: String,
        val username: String,
        val verified: Int = 0,
        val isOnline: Boolean = false
)

@Composable
@OptIn(ExperimentalFoundationApi::class)
private fun FrequentContactsRow(
        contacts: List<FrequentContact>,
        avatarRepository: AvatarRepository?,
        isDarkTheme: Boolean,
        textColor: Color,
        onClick: (FrequentContact) -> Unit,
        onLongPress: (FrequentContact) -> Unit
) {
    val haptic = LocalHapticFeedback.current
    LazyRow(
            modifier = Modifier
                    .fillMaxWidth()
                    .padding(vertical = 12.dp),
            contentPadding = PaddingValues(horizontal = 12.dp),
            horizontalArrangement = Arrangement.spacedBy(4.dp)
    ) {
        items(contacts, key = { it.publicKey }) { contact ->
            Column(
                    modifier = Modifier
                            .width(72.dp)
                            .combinedClickable(
                                indication = null,
                                interactionSource = remember { MutableInteractionSource() },
                                onClick = { onClick(contact) },
                                onLongClick = {
                                    haptic.performHapticFeedback(HapticFeedbackType.LongPress)
                                    onLongPress(contact)
                                }
                            )
                            .padding(vertical = 4.dp),
                    horizontalAlignment = Alignment.CenterHorizontally
            ) {
                Box(contentAlignment = Alignment.BottomEnd) {
                    AvatarImage(
                            publicKey = contact.publicKey,
                            avatarRepository = avatarRepository,
                            size = 54.dp,
                            isDarkTheme = isDarkTheme,
                            showOnlineIndicator = false,
                            isOnline = false,
                            displayName = contact.name
                    )
                    if (contact.isOnline) {
                        Box(
                                modifier = Modifier
                                        .size(16.dp)
                                        .offset(x = 1.dp, y = 1.dp)
                                        .background(
                                                if (isDarkTheme) Color(0xFF1A1A1A) else Color.White,
                                                CircleShape
                                        )
                                        .padding(2.5.dp)
                                        .background(Color(0xFF4CAF50), CircleShape)
                        )
                    }
                }
                Spacer(modifier = Modifier.height(6.dp))
                Row(
                        verticalAlignment = Alignment.CenterVertically,
                        horizontalArrangement = Arrangement.Center
                ) {
                    Text(
                            text = contact.name.split(" ").firstOrNull() ?: contact.name,
                            fontSize = 12.sp,
                            color = textColor,
                            maxLines = 1,
                            overflow = TextOverflow.Ellipsis,
                            fontWeight = FontWeight.Normal,
                            modifier = if (contact.verified != 0) Modifier.widthIn(max = 52.dp) else Modifier
                    )
                    if (contact.verified != 0) {
                        Spacer(modifier = Modifier.width(2.dp))
                        VerifiedBadge(
                                verified = contact.verified,
                                size = 12
                        )
                    }
                }
            }
        }
    }
}

// ═══════════════════════════════════════════════════════════
// 💀 SEARCH SKELETON (shimmer loading)
// ═══════════════════════════════════════════════════════════

@Composable
private fun SearchSkeleton(isDarkTheme: Boolean) {
    val shimmerColor = if (isDarkTheme) Color(0xFF2A2A2A) else Color(0xFFE8E8E8)
    val highlightColor = if (isDarkTheme) Color(0xFF3A3A3A) else Color(0xFFF5F5F5)

    val transition = rememberInfiniteTransition(label = "shimmer")
    val translateAnim by transition.animateFloat(
            initialValue = 0f,
            targetValue = 1000f,
            animationSpec = infiniteRepeatable(
                    animation = tween(durationMillis = 1200, easing = LinearEasing),
                    repeatMode = RepeatMode.Restart
            ),
            label = "shimmer_translate"
    )

    val shimmerBrush = androidx.compose.ui.graphics.Brush.linearGradient(
            colors = listOf(shimmerColor, highlightColor, shimmerColor),
            start = androidx.compose.ui.geometry.Offset(translateAnim - 200f, 0f),
            end = androidx.compose.ui.geometry.Offset(translateAnim, 0f)
    )

    Column(modifier = Modifier.fillMaxSize()) {
        repeat(8) {
            Row(
                    modifier = Modifier
                            .fillMaxWidth()
                            .padding(horizontal = 16.dp, vertical = 12.dp),
                    verticalAlignment = Alignment.CenterVertically
            ) {
                // Skeleton avatar
                Box(
                        modifier = Modifier
                                .size(48.dp)
                                .clip(CircleShape)
                                .background(shimmerBrush)
                )
                Spacer(modifier = Modifier.width(12.dp))
                Column(modifier = Modifier.weight(1f)) {
                    // Skeleton name
                    Box(
                            modifier = Modifier
                                    .fillMaxWidth(fraction = if (it % 2 == 0) 0.6f else 0.45f)
                                    .height(14.dp)
                                    .clip(RoundedCornerShape(4.dp))
                                    .background(shimmerBrush)
                    )
                    Spacer(modifier = Modifier.height(8.dp))
                    // Skeleton subtitle
                    Box(
                            modifier = Modifier
                                    .fillMaxWidth(fraction = if (it % 2 == 0) 0.35f else 0.5f)
                                    .height(12.dp)
                                    .clip(RoundedCornerShape(4.dp))
                                    .background(shimmerBrush)
                    )
                }
            }
        }
    }
}

// ═══════════════════════════════════════════════════════════
// 💬 MESSAGES TAB — search through decrypted message text
// ═══════════════════════════════════════════════════════════

/** A single message search result */
private data class MessageSearchResult(
        val messageId: String,
        val dialogKey: String,
        val opponentKey: String,
        val opponentTitle: String,
        val opponentUsername: String,
        val plainText: String,
        val timestamp: Long,
        val fromMe: Boolean,
        val verified: Int = 0
)

/**
 * Optimized message search: loads messages in batches, decrypts plainMessage
 * fields in parallel (Semaphore-limited), filters client-side, and caches
 * decrypted text to avoid re-decryption on subsequent queries.
 */
@Composable
private fun MessagesTabContent(
        searchQuery: String,
        currentUserPublicKey: String,
        messageRepository: MessageRepository,
        isDarkTheme: Boolean,
        textColor: Color,
        secondaryTextColor: Color,
        avatarRepository: AvatarRepository?,
        searchLottieComposition: com.airbnb.lottie.LottieComposition?,
        onUserSelect: (SearchUser) -> Unit
) {
    val context = LocalContext.current
    var results by remember { mutableStateOf<List<MessageSearchResult>>(emptyList()) }
    var isSearching by remember { mutableStateOf(false) }
    val dividerColor = remember(isDarkTheme) {
        if (isDarkTheme) Color(0xFF2A2A2A) else Color(0xFFE8E8E8)
    }

    // Persistent decryption cache: messageId → plaintext (survives re-queries)
    val decryptCache = remember(currentUserPublicKey) { ConcurrentHashMap<String, String>(512) }
    // Cache for dialog metadata: opponentKey → (title, username, verified)
    val dialogCache =
            remember(currentUserPublicKey) { ConcurrentHashMap<String, Triple<String, String, Int>>() }

    val dateFormat = remember { SimpleDateFormat("dd MMM, HH:mm", Locale.getDefault()) }

    // Debounced search: waits 600ms after typing stops, then searches
    LaunchedEffect(searchQuery, currentUserPublicKey) {
        results = emptyList()
        if (searchQuery.length < 2 || currentUserPublicKey.isBlank()) {
            isSearching = false
            return@LaunchedEffect
        }
        isSearching = true
        // Debounce
        kotlinx.coroutines.delay(600)

        withContext(Dispatchers.IO) {
            try {
                val db = RosettaDatabase.getDatabase(context)
                val privateKey = messageRepository.getCurrentPrivateKey().orEmpty()
                if (privateKey.isBlank()) {
                    isSearching = false
                    return@withContext
                }

                // Pre-warm PBKDF2 cache for this password
                CryptoManager.getPbkdf2Key(privateKey)

                // Load dialog metadata once
                if (dialogCache.isEmpty()) {
                    val dialogs = db.dialogDao().getDialogsPaged(currentUserPublicKey, 500, 0)
                    for (d in dialogs) {
                        dialogCache[d.opponentKey] = Triple(d.opponentTitle, d.opponentUsername, d.verified)
                    }
                }

                val queryLower = searchQuery.trim().lowercase()
                val maxResults = 50   // Don't return more than 50 matches
                val batchSize = 200
                val indexDao = db.messageSearchIndexDao()

                fun toUiResult(item: MessageSearchIndexEntity): MessageSearchResult {
                    val normalized = item.opponentKey.trim()
                    val meta = dialogCache[normalized]
                    return MessageSearchResult(
                            messageId = item.messageId,
                            dialogKey = item.dialogKey,
                            opponentKey = normalized,
                            opponentTitle = meta?.first.orEmpty(),
                            opponentUsername = meta?.second.orEmpty(),
                            plainText = item.plainText,
                            timestamp = item.timestamp,
                            fromMe = item.fromMe == 1,
                            verified = meta?.third ?: 0
                    )
                }

                var indexed = indexDao.search(currentUserPublicKey, queryLower, maxResults, 0)
                var indexingPasses = 0
                while (indexed.size < maxResults && indexingPasses < 15) {
                    val unindexed = indexDao.getUnindexedMessages(currentUserPublicKey, batchSize)
                    if (unindexed.isEmpty()) break

                    val rows = ArrayList<MessageSearchIndexEntity>(unindexed.size)
                    unindexed.forEach { msg ->
                        val plain =
                                decryptCache[msg.messageId]
                                        ?: try {
                                            CryptoManager.decryptWithPassword(msg.plainMessage, privateKey)
                                        } catch (_: Exception) {
                                            null
                                        }.orEmpty()
                        if (plain.isNotEmpty()) {
                            decryptCache[msg.messageId] = plain
                        }
                        val opponent = if (msg.fromMe == 1) msg.toPublicKey else msg.fromPublicKey
                        rows.add(
                                MessageSearchIndexEntity(
                                        account = currentUserPublicKey,
                                        messageId = msg.messageId,
                                        dialogKey = msg.dialogKey,
                                        opponentKey = opponent.trim(),
                                        timestamp = msg.timestamp,
                                        fromMe = msg.fromMe,
                                        plainText = plain,
                                        plainTextNormalized = plain.lowercase()
                                )
                        )
                    }
                    if (rows.isNotEmpty()) {
                        indexDao.upsert(rows)
                    }
                    indexingPasses++
                    indexed = indexDao.search(currentUserPublicKey, queryLower, maxResults, 0)
                }

                results = indexed.map(::toUiResult)
            } catch (_: Exception) {
                results = emptyList()
            }
            isSearching = false
        }
    }

    Box(modifier = Modifier.fillMaxSize()) {
        when {
            searchQuery.length < 2 -> {
                // Idle state — prompt to type
                Column(
                        modifier = Modifier
                                .fillMaxSize()
                                .imePadding(),
                        horizontalAlignment = Alignment.CenterHorizontally,
                        verticalArrangement = Arrangement.Center
                ) {
                    if (searchLottieComposition != null) {
                        val progress by animateLottieCompositionAsState(
                                composition = searchLottieComposition,
                                iterations = 1,
                                isPlaying = true,
                                restartOnPlay = false
                        )
                        LottieAnimation(
                                composition = searchLottieComposition,
                                progress = { progress },
                                modifier = Modifier.size(100.dp)
                        )
                    }
                    Spacer(modifier = Modifier.height(16.dp))
                    Text(
                            text = "Search in messages",
                            fontSize = 17.sp,
                            fontWeight = FontWeight.Medium,
                            color = textColor
                    )
                    Spacer(modifier = Modifier.height(6.dp))
                    Text(
                            text = "Type at least 2 characters",
                            fontSize = 14.sp,
                            color = secondaryTextColor
                    )
                }
            }
            isSearching -> {
                MessageSearchSkeleton(isDarkTheme = isDarkTheme)
            }
            results.isEmpty() -> {
                // No results
                Column(
                        modifier = Modifier
                                .fillMaxSize()
                                .imePadding(),
                        horizontalAlignment = Alignment.CenterHorizontally,
                        verticalArrangement = Arrangement.Center
                ) {
                    Icon(
                            painter = painterResource(R.drawable.search_files_filled),
                            contentDescription = null,
                            tint = secondaryTextColor.copy(alpha = 0.4f),
                            modifier = Modifier.size(48.dp)
                    )
                    Spacer(modifier = Modifier.height(16.dp))
                    Text(
                            text = "No messages found",
                            fontSize = 17.sp,
                            fontWeight = FontWeight.Medium,
                            color = textColor.copy(alpha = 0.8f)
                    )
                    Spacer(modifier = Modifier.height(4.dp))
                    Text(
                            text = "Try a different search term",
                            fontSize = 14.sp,
                            color = secondaryTextColor
                    )
                }
            }
            else -> {
                LazyColumn(
                        modifier = Modifier.fillMaxSize().imePadding(),
                        contentPadding = PaddingValues(vertical = 4.dp)
                ) {
                    items(results, key = { it.messageId }) { result ->
                        MessageSearchResultItem(
                                result = result,
                                searchQuery = searchQuery,
                                dateFormat = dateFormat,
                                currentUserPublicKey = currentUserPublicKey,
                                isDarkTheme = isDarkTheme,
                                textColor = textColor,
                                secondaryTextColor = secondaryTextColor,
                                avatarRepository = avatarRepository,
                                onClick = {
                                    val user = SearchUser(
                                            title = result.opponentTitle,
                                            username = result.opponentUsername,
                                            publicKey = result.opponentKey,
                                            verified = result.verified,
                                            online = 0
                                    )
                                    onUserSelect(user)
                                }
                        )
                        Divider(
                                color = dividerColor,
                                thickness = 0.5.dp,
                                modifier = Modifier.padding(start = 76.dp)
                        )
                    }
                }
            }
        }
    }
}

@Composable
private fun MessageSearchSkeleton(isDarkTheme: Boolean) {
    val shimmerColor = if (isDarkTheme) Color(0xFF2A2A2A) else Color(0xFFE8E8E8)
    val highlightColor = if (isDarkTheme) Color(0xFF3A3A3A) else Color(0xFFF5F5F5)
    val dividerColor = if (isDarkTheme) Color(0xFF2A2A2A) else Color(0xFFE8E8E8)

    val transition = rememberInfiniteTransition(label = "message_search_shimmer")
    val translateAnim by transition.animateFloat(
            initialValue = 0f,
            targetValue = 1000f,
            animationSpec = infiniteRepeatable(
                    animation = tween(durationMillis = 1200, easing = LinearEasing),
                    repeatMode = RepeatMode.Restart
            ),
            label = "message_search_shimmer_translate"
    )

    val shimmerBrush = androidx.compose.ui.graphics.Brush.linearGradient(
            colors = listOf(shimmerColor, highlightColor, shimmerColor),
            start = androidx.compose.ui.geometry.Offset(translateAnim - 200f, 0f),
            end = androidx.compose.ui.geometry.Offset(translateAnim, 0f)
    )

    LazyColumn(
            modifier = Modifier.fillMaxSize().imePadding(),
            contentPadding = PaddingValues(vertical = 4.dp)
    ) {
        items(8) { index ->
            Row(
                    modifier = Modifier
                            .fillMaxWidth()
                            .padding(horizontal = 16.dp, vertical = 10.dp),
                    verticalAlignment = Alignment.CenterVertically
            ) {
                Box(
                        modifier =
                                Modifier.size(48.dp)
                                        .clip(CircleShape)
                                        .background(shimmerBrush)
                )

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

                Column(modifier = Modifier.weight(1f)) {
                    Row(
                            modifier = Modifier.fillMaxWidth(),
                            horizontalArrangement = Arrangement.SpaceBetween,
                            verticalAlignment = Alignment.CenterVertically
                    ) {
                        Box(
                                modifier =
                                        Modifier.fillMaxWidth(
                                                        fraction = if (index % 2 == 0) 0.48f else 0.62f
                                                )
                                                .height(14.dp)
                                                .clip(RoundedCornerShape(4.dp))
                                                .background(shimmerBrush)
                        )
                        Spacer(modifier = Modifier.width(10.dp))
                        Box(
                                modifier =
                                        Modifier.width(if (index % 2 == 0) 58.dp else 50.dp)
                                                .height(12.dp)
                                                .clip(RoundedCornerShape(4.dp))
                                                .background(shimmerBrush)
                        )
                    }

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

                    Box(
                            modifier =
                                    Modifier.fillMaxWidth(
                                                    fraction = if (index % 2 == 0) 0.86f else 0.74f
                                            )
                                            .height(12.dp)
                                            .clip(RoundedCornerShape(4.dp))
                                            .background(shimmerBrush)
                    )
                    Spacer(modifier = Modifier.height(6.dp))
                    Box(
                            modifier =
                                    Modifier.fillMaxWidth(
                                                    fraction = if (index % 2 == 0) 0.67f else 0.79f
                                            )
                                            .height(12.dp)
                                            .clip(RoundedCornerShape(4.dp))
                                            .background(shimmerBrush)
                    )
                }
            }

            Divider(
                    color = dividerColor,
                    thickness = 0.5.dp,
                    modifier = Modifier.padding(start = 76.dp)
            )
        }
    }
}

@Composable
private fun MessageSearchResultItem(
        result: MessageSearchResult,
        searchQuery: String,
        dateFormat: SimpleDateFormat,
        currentUserPublicKey: String,
        isDarkTheme: Boolean,
        textColor: Color,
        secondaryTextColor: Color,
        avatarRepository: AvatarRepository?,
        onClick: () -> Unit
) {
    val isGroup = result.opponentKey.startsWith("#group:") || result.opponentKey.startsWith("group:")
    val displayName = when {
        result.opponentKey == currentUserPublicKey -> "Saved Messages"
        result.opponentTitle.isNotBlank() -> result.opponentTitle
        result.opponentUsername.isNotBlank() -> result.opponentUsername
        else -> result.opponentKey.take(8) + "..."
    }

    // Build highlighted snippet: show text around the match
    val snippet = remember(result.plainText, searchQuery) {
        buildMessageSnippet(result.plainText, searchQuery)
    }

    Row(
            modifier = Modifier
                    .fillMaxWidth()
                    .clickable(onClick = onClick)
                    .padding(horizontal = 16.dp, vertical = 10.dp),
            verticalAlignment = Alignment.CenterVertically
    ) {
        AvatarImage(
                publicKey = result.opponentKey,
                avatarRepository = avatarRepository,
                size = 48.dp,
                isDarkTheme = isDarkTheme,
                showOnlineIndicator = false,
                isOnline = false,
                displayName = displayName
        )

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

        Column(modifier = Modifier.weight(1f)) {
            // Top line: name + date
            Row(
                    modifier = Modifier.fillMaxWidth(),
                    horizontalArrangement = Arrangement.SpaceBetween,
                    verticalAlignment = Alignment.CenterVertically
            ) {
                Row(
                        verticalAlignment = Alignment.CenterVertically,
                        modifier = Modifier.weight(1f, fill = false)
                ) {
                    Text(
                            text = displayName,
                            fontSize = 16.sp,
                            fontWeight = FontWeight.Medium,
                            color = textColor,
                            maxLines = 1,
                            overflow = TextOverflow.Ellipsis
                    )
                    if (result.verified != 0) {
                        Spacer(modifier = Modifier.width(4.dp))
                        VerifiedBadge(verified = result.verified, size = 16, isDarkTheme = isDarkTheme)
                    }
                }
                Spacer(modifier = Modifier.width(8.dp))
                Text(
                        text = dateFormat.format(Date(result.timestamp)),
                        fontSize = 13.sp,
                        color = secondaryTextColor,
                        maxLines = 1
                )
            }

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

            // Bottom line: message snippet with highlighted match
            val annotated = remember(snippet, searchQuery) {
                buildHighlightedText(snippet, searchQuery, secondaryTextColor, PrimaryBlue)
            }
            Text(
                    text = annotated,
                    fontSize = 14.sp,
                    maxLines = 2,
                    overflow = TextOverflow.Ellipsis
            )
        }
    }
}

/** Extract a snippet around the first match, ~80 chars context */
private fun buildMessageSnippet(text: String, query: String): String {
    val lower = text.lowercase()
    val queryLower = query.trim().lowercase()
    val idx = lower.indexOf(queryLower)
    if (idx < 0) return text.take(100)

    val start = (idx - 30).coerceAtLeast(0)
    val end = (idx + queryLower.length + 50).coerceAtMost(text.length)
    val prefix = if (start > 0) "..." else ""
    val suffix = if (end < text.length) "..." else ""
    return prefix + text.substring(start, end).replace('\n', ' ') + suffix
}

/** Build AnnotatedString with the query highlighted in blue */
private fun buildHighlightedText(
        text: String,
        query: String,
        baseColor: Color,
        highlightColor: Color
) = buildAnnotatedString {
    val lower = text.lowercase()
    val queryLower = query.trim().lowercase()
    var cursor = 0

    while (cursor < text.length) {
        val matchIdx = lower.indexOf(queryLower, cursor)
        if (matchIdx < 0) {
            withStyle(SpanStyle(color = baseColor)) {
                append(text.substring(cursor))
            }
            break
        }
        if (matchIdx > cursor) {
            withStyle(SpanStyle(color = baseColor)) {
                append(text.substring(cursor, matchIdx))
            }
        }
        withStyle(SpanStyle(color = highlightColor, fontWeight = FontWeight.SemiBold)) {
            append(text.substring(matchIdx, matchIdx + queryLower.length))
        }
        cursor = matchIdx + queryLower.length
    }
}

// ═══════════════════════════════════════════════════════════
// 🖼️ MEDIA TAB — grid of images from all chats
// ═══════════════════════════════════════════════════════════

/** Parsed media item for the grid display */
private data class MediaItem(
        val messageId: String,
        val attachmentId: String,
        val timestamp: Long,
        val preview: String,       // blurhash or "UUID::blurhash"
        val chachaKey: String,     // encrypted key for decryption
        val senderPublicKey: String,
        val width: Int,
        val height: Int
)

@Composable
private fun MediaTabContent(
        currentUserPublicKey: String,
        messageRepository: MessageRepository,
        isDarkTheme: Boolean,
        textColor: Color,
        secondaryTextColor: Color,
        onOpenImageViewer: (images: List<com.rosetta.messenger.ui.chats.components.ViewableImage>, initialIndex: Int, privateKey: String) -> Unit = { _, _, _ -> }
) {
    val context = LocalContext.current
    var mediaItems by remember { mutableStateOf<List<MediaItem>>(emptyList()) }
    var isLoading by remember { mutableStateOf(true) }

    val privateKey = remember {
        messageRepository.getCurrentPrivateKey().orEmpty()
    }

    val viewerImages = remember(mediaItems) {
        mediaItems.map { item ->
            com.rosetta.messenger.ui.chats.components.ViewableImage(
                    attachmentId = item.attachmentId,
                    preview = item.preview,
                    blob = "",
                    chachaKey = item.chachaKey,
                    senderPublicKey = item.senderPublicKey,
                    senderName = "",
                    timestamp = Date(item.timestamp),
                    width = item.width,
                    height = item.height
            )
        }
    }

    LaunchedEffect(currentUserPublicKey) {
        if (currentUserPublicKey.isBlank()) {
            isLoading = false
            return@LaunchedEffect
        }
        isLoading = true
        withContext(Dispatchers.IO) {
            try {
                val db = RosettaDatabase.getDatabase(context)
                val messages = db.messageDao().getMessagesWithMedia(currentUserPublicKey, 200, 0)
                val items = mutableListOf<MediaItem>()
                for (msg in messages) {
                    try {
                        val arr = JSONArray(msg.attachments)
                        for (i in 0 until arr.length()) {
                            val obj = arr.getJSONObject(i)
                            val type = obj.optInt("type", -1)
                            if (type == AttachmentType.IMAGE.value) {
                                val attId = obj.optString("id", "")
                                if (attId.isNotBlank()) {
                                    items.add(
                                            MediaItem(
                                                    messageId = msg.messageId,
                                                    attachmentId = attId,
                                                    timestamp = msg.timestamp,
                                                    preview = obj.optString("preview", ""),
                                                    chachaKey = msg.chachaKey,
                                                    senderPublicKey = msg.fromPublicKey,
                                                    width = obj.optInt("width", 100),
                                                    height = obj.optInt("height", 100)
                                            )
                                    )
                                }
                            }
                        }
                    } catch (_: Exception) { }
                }
                mediaItems = items
            } catch (_: Exception) { }
        }
        isLoading = false
    }

    Box(modifier = Modifier.fillMaxSize()) {
        if (isLoading) {
            Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
                CircularProgressIndicator(color = PrimaryBlue, modifier = Modifier.size(32.dp))
            }
        } else if (mediaItems.isEmpty()) {
            EmptyTabPlaceholder(
                    iconRes = R.drawable.search_media_filled,
                    title = "No media yet",
                    subtitle = "Photos and videos will appear here",
                    isDarkTheme = isDarkTheme,
                    textColor = textColor,
                    secondaryTextColor = secondaryTextColor
            )
        } else {
            LazyVerticalGrid(
                    columns = GridCells.Fixed(3),
                    modifier = Modifier.fillMaxSize(),
                    contentPadding = PaddingValues(2.dp),
                    horizontalArrangement = Arrangement.spacedBy(2.dp),
                    verticalArrangement = Arrangement.spacedBy(2.dp)
            ) {
                items(mediaItems, key = { it.attachmentId }) { item ->
                    val index = mediaItems.indexOf(item)
                    MediaGridItem(
                            item = item,
                            isDarkTheme = isDarkTheme,
                            currentUserPublicKey = currentUserPublicKey,
                            privateKey = privateKey,
                            onClick = {
                                val idx = if (index >= 0) index else 0
                                onOpenImageViewer(viewerImages, idx, privateKey)
                            }
                    )
                }
            }
        }

    }
}

@Composable
private fun MediaGridItem(
        item: MediaItem,
        isDarkTheme: Boolean,
        currentUserPublicKey: String,
        privateKey: String,
        onClick: () -> Unit = {}
) {
    val context = LocalContext.current
    val cacheKey = "img_${item.attachmentId}"

    // Start with cached bitmap if available
    var imageBitmap by remember(item.attachmentId) {
        mutableStateOf(com.rosetta.messenger.ui.chats.components.ImageBitmapCache.get(cacheKey))
    }

    // Decode blurhash for placeholder
    val blurhashBitmap = remember(item.preview) {
        val preview = com.rosetta.messenger.ui.chats.components.getPreview(item.preview)
        if (preview.isNotBlank()) {
            try { com.vanniktech.blurhash.BlurHash.decode(preview, 32, 32) }
            catch (_: Exception) { null }
        } else null
    }

    // Load the actual image
    LaunchedEffect(item.attachmentId) {
        if (imageBitmap != null) return@LaunchedEffect

        // Check cache again (may have loaded between remember and LaunchedEffect)
        com.rosetta.messenger.ui.chats.components.ImageBitmapCache.get(cacheKey)?.let {
            imageBitmap = it
            return@LaunchedEffect
        }

        com.rosetta.messenger.ui.chats.components.ImageLoadSemaphore.semaphore.withPermit {
            withContext(Dispatchers.IO) {
                try {
                    // 1. Try loading from local file (AttachmentFileManager)
                    val localBlob = com.rosetta.messenger.utils.AttachmentFileManager.readAttachment(
                            context, item.attachmentId, currentUserPublicKey, privateKey
                    )
                    if (localBlob != null) {
                        val bmp = com.rosetta.messenger.ui.chats.components.base64ToBitmap(localBlob)
                        if (bmp != null) {
                            com.rosetta.messenger.ui.chats.components.ImageBitmapCache.put(cacheKey, bmp)
                            imageBitmap = bmp
                            return@withContext
                        }
                    }

                    // 2. Try CDN download if we have a download tag
                    val downloadTag = com.rosetta.messenger.ui.chats.components.getDownloadTag(item.preview)
                    if (downloadTag.isNotEmpty() && item.chachaKey.isNotBlank() && privateKey.isNotBlank()) {
                        val bmp = com.rosetta.messenger.ui.chats.components.downloadAndDecryptImage(
                                attachmentId = item.attachmentId,
                                downloadTag = downloadTag,
                                chachaKey = item.chachaKey,
                                privateKey = privateKey,
                                cacheKey = cacheKey,
                                context = context,
                                senderPublicKey = item.senderPublicKey,
                                recipientPrivateKey = privateKey
                        )
                        if (bmp != null) {
                            imageBitmap = bmp
                        }
                    }
                } catch (_: Exception) { }
            }
        }
    }

    Box(
            modifier = Modifier
                    .aspectRatio(1f)
                    .background(if (isDarkTheme) Color(0xFF2A2A2A) else Color(0xFFE8E8E8))
                    .clip(RoundedCornerShape(2.dp))
                    .clickable(onClick = onClick),
            contentAlignment = Alignment.Center
    ) {
        when {
            imageBitmap != null -> {
                Image(
                        bitmap = imageBitmap!!.asImageBitmap(),
                        contentDescription = null,
                        modifier = Modifier.fillMaxSize(),
                        contentScale = ContentScale.Crop
                )
            }
            blurhashBitmap != null -> {
                Image(
                        bitmap = blurhashBitmap.asImageBitmap(),
                        contentDescription = null,
                        modifier = Modifier.fillMaxSize(),
                        contentScale = ContentScale.Crop
                )
            }
            else -> {
                Icon(
                        painter = painterResource(R.drawable.search_media_filled),
                        contentDescription = null,
                        tint = if (isDarkTheme) Color(0xFF555555) else Color(0xFFCCCCCC),
                        modifier = Modifier.size(28.dp)
                )
            }
        }
    }
}

// ═══════════════════════════════════════════════════════════
// 📥 DOWNLOADS TAB — files in rosetta_downloads dir
// ═══════════════════════════════════════════════════════════

private data class DownloadedFile(
        val file: File,
        val name: String,
        val size: Long,
        val lastModified: Long
)

@Composable
private fun DownloadsTabContent(
        isDarkTheme: Boolean,
        textColor: Color,
        secondaryTextColor: Color
) {
    val context = LocalContext.current
    var files by remember { mutableStateOf<List<DownloadedFile>>(emptyList()) }
    var isLoading by remember { mutableStateOf(true) }

    LaunchedEffect(Unit) {
        isLoading = true
        withContext(Dispatchers.IO) {
            try {
                val downloadsDir = File(context.filesDir, "rosetta_downloads")
                if (downloadsDir.exists()) {
                    files = downloadsDir.listFiles()
                            ?.filter { it.isFile }
                            ?.sortedByDescending { it.lastModified() }
                            ?.map { DownloadedFile(
                                    file = it,
                                    name = it.name,
                                    size = it.length(),
                                    lastModified = it.lastModified()
                            ) } ?: emptyList()
                }
            } catch (_: Exception) { }
        }
        isLoading = false
    }

    if (isLoading) {
        Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
            CircularProgressIndicator(color = PrimaryBlue, modifier = Modifier.size(32.dp))
        }
    } else if (files.isEmpty()) {
        EmptyTabPlaceholder(
                iconRes = R.drawable.msg_download,
                title = "No downloads yet",
                subtitle = "Downloaded files will appear here",
                isDarkTheme = isDarkTheme,
                textColor = textColor,
                secondaryTextColor = secondaryTextColor
        )
    } else {
        LazyColumn(
                modifier = Modifier.fillMaxSize().imePadding(),
                contentPadding = PaddingValues(vertical = 4.dp)
        ) {
            items(files, key = { it.name }) { downloadedFile ->
                DownloadFileItem(
                        downloadedFile = downloadedFile,
                        isDarkTheme = isDarkTheme,
                        textColor = textColor,
                        secondaryTextColor = secondaryTextColor,
                        onClick = {
                            openDownloadedFile(context, downloadedFile.file)
                        }
                )
            }
        }
    }
}

@Composable
private fun DownloadFileItem(
        downloadedFile: DownloadedFile,
        isDarkTheme: Boolean,
        textColor: Color,
        secondaryTextColor: Color,
        onClick: () -> Unit
) {
    val ext = downloadedFile.name.substringAfterLast('.', "").uppercase()
    val iconColor = getFileIconColor(ext)
    val dateFormat = remember { SimpleDateFormat("dd MMM yyyy", Locale.getDefault()) }

    Row(
            modifier = Modifier
                    .fillMaxWidth()
                    .clickable(onClick = onClick)
                    .padding(horizontal = 16.dp, vertical = 10.dp),
            verticalAlignment = Alignment.CenterVertically
    ) {
        // File icon circle
        Box(
                modifier = Modifier
                        .size(40.dp)
                        .clip(CircleShape)
                        .background(iconColor),
                contentAlignment = Alignment.Center
        ) {
            Icon(
                    imageVector = Icons.Default.InsertDriveFile,
                    contentDescription = null,
                    tint = Color.White,
                    modifier = Modifier.size(20.dp)
            )
        }

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

        Column(modifier = Modifier.weight(1f)) {
            Text(
                    text = downloadedFile.name,
                    fontSize = 15.sp,
                    fontWeight = FontWeight.Normal,
                    color = textColor,
                    maxLines = 1,
                    overflow = TextOverflow.Ellipsis
            )
            Spacer(modifier = Modifier.height(2.dp))
            Text(
                    text = "${formatFileSizeSearch(downloadedFile.size)} · ${dateFormat.format(Date(downloadedFile.lastModified))}",
                    fontSize = 13.sp,
                    color = secondaryTextColor
            )
        }
    }
}

// ═══════════════════════════════════════════════════════════
// 📁 FILES TAB — file attachments from DB
// ═══════════════════════════════════════════════════════════

private data class FileItem(
        val messageId: String,
        val timestamp: Long,
        val fileName: String,
        val fileSize: Long,
        val attachmentId: String
)

@Composable
private fun FilesTabContent(
        currentUserPublicKey: String,
        isDarkTheme: Boolean,
        textColor: Color,
        secondaryTextColor: Color
) {
    val context = LocalContext.current
    var fileItems by remember { mutableStateOf<List<FileItem>>(emptyList()) }
    var isLoading by remember { mutableStateOf(true) }

    LaunchedEffect(currentUserPublicKey) {
        if (currentUserPublicKey.isBlank()) {
            isLoading = false
            return@LaunchedEffect
        }
        isLoading = true
        withContext(Dispatchers.IO) {
            try {
                val db = RosettaDatabase.getDatabase(context)
                val messages = db.messageDao().getMessagesWithFiles(currentUserPublicKey, 200, 0)
                val items = mutableListOf<FileItem>()
                for (msg in messages) {
                    try {
                        val arr = JSONArray(msg.attachments)
                        for (i in 0 until arr.length()) {
                            val obj = arr.getJSONObject(i)
                            val type = obj.optInt("type", -1)
                            if (type == AttachmentType.FILE.value) {
                                val preview = obj.optString("preview", "")
                                val parsed = parseFilePreviewSearch(preview)
                                items.add(
                                        FileItem(
                                                messageId = msg.messageId,
                                                timestamp = msg.timestamp,
                                                fileName = parsed.second,
                                                fileSize = parsed.first,
                                                attachmentId = obj.optString("id", "")
                                        )
                                )
                            }
                        }
                    } catch (_: Exception) { }
                }
                fileItems = items
            } catch (_: Exception) { }
        }
        isLoading = false
    }

    if (isLoading) {
        Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
            CircularProgressIndicator(color = PrimaryBlue, modifier = Modifier.size(32.dp))
        }
    } else if (fileItems.isEmpty()) {
        EmptyTabPlaceholder(
                iconRes = R.drawable.search_files_filled,
                title = "No files yet",
                subtitle = "Shared files will appear here",
                isDarkTheme = isDarkTheme,
                textColor = textColor,
                secondaryTextColor = secondaryTextColor
        )
    } else {
        val dateFormat = remember { SimpleDateFormat("dd MMM yyyy", Locale.getDefault()) }
        LazyColumn(
                modifier = Modifier.fillMaxSize().imePadding(),
                contentPadding = PaddingValues(vertical = 4.dp)
        ) {
            items(fileItems, key = { "${it.messageId}_${it.attachmentId}" }) { item ->
                FileListItem(
                        item = item,
                        dateFormat = dateFormat,
                        isDarkTheme = isDarkTheme,
                        textColor = textColor,
                        secondaryTextColor = secondaryTextColor
                )
            }
        }
    }
}

@Composable
private fun FileListItem(
        item: FileItem,
        dateFormat: SimpleDateFormat,
        isDarkTheme: Boolean,
        textColor: Color,
        secondaryTextColor: Color
) {
    val ext = item.fileName.substringAfterLast('.', "").uppercase()
    val iconColor = getFileIconColor(ext)

    Row(
            modifier = Modifier
                    .fillMaxWidth()
                    .padding(horizontal = 16.dp, vertical = 10.dp),
            verticalAlignment = Alignment.CenterVertically
    ) {
        // File icon circle
        Box(
                modifier = Modifier
                        .size(40.dp)
                        .clip(CircleShape)
                        .background(iconColor),
                contentAlignment = Alignment.Center
        ) {
            Icon(
                    imageVector = Icons.Default.InsertDriveFile,
                    contentDescription = null,
                    tint = Color.White,
                    modifier = Modifier.size(20.dp)
            )
        }

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

        Column(modifier = Modifier.weight(1f)) {
            Text(
                    text = item.fileName,
                    fontSize = 15.sp,
                    fontWeight = FontWeight.Normal,
                    color = textColor,
                    maxLines = 1,
                    overflow = TextOverflow.Ellipsis
            )
            Spacer(modifier = Modifier.height(2.dp))
            Text(
                    text = "${formatFileSizeSearch(item.fileSize)} · ${dateFormat.format(Date(item.timestamp))}",
                    fontSize = 13.sp,
                    color = secondaryTextColor
            )
        }
    }
}

// ═══════════════════════════════════════════════════════════
// 🎨 Helpers
// ═══════════════════════════════════════════════════════════

@Composable
private fun EmptyTabPlaceholder(
        iconRes: Int,
        title: String,
        subtitle: String,
        isDarkTheme: Boolean,
        textColor: Color,
        secondaryTextColor: Color
) {
    Column(
            modifier = Modifier.fillMaxSize().padding(top = 80.dp),
            horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Icon(
                painter = painterResource(iconRes),
                contentDescription = null,
                tint = secondaryTextColor.copy(alpha = 0.4f),
                modifier = Modifier.size(56.dp)
        )
        Spacer(modifier = Modifier.height(16.dp))
        Text(
                text = title,
                fontSize = 17.sp,
                fontWeight = FontWeight.SemiBold,
                color = textColor.copy(alpha = 0.8f)
        )
        Spacer(modifier = Modifier.height(4.dp))
        Text(
                text = subtitle,
                fontSize = 14.sp,
                color = secondaryTextColor
        )
    }
}

private fun getFileIconColor(ext: String): Color {
    return when (ext.uppercase()) {
        "PDF" -> Color(0xFFE53935)
        "DOC", "DOCX" -> Color(0xFF1565C0)
        "XLS", "XLSX" -> Color(0xFF2E7D32)
        "PPT", "PPTX" -> Color(0xFFE65100)
        "ZIP", "RAR", "7Z", "TAR", "GZ" -> Color(0xFF6A1B9A)
        "MP3", "WAV", "OGG", "FLAC", "AAC" -> Color(0xFFEF6C00)
        "MP4", "AVI", "MKV", "MOV", "WEBM" -> Color(0xFF0277BD)
        "JPG", "JPEG", "PNG", "GIF", "WEBP", "SVG" -> Color(0xFF00838F)
        "APK" -> Color(0xFF33691E)
        "TXT" -> Color(0xFF455A64)
        else -> PrimaryBlue
    }
}

private fun formatFileSizeSearch(bytes: Long): String {
    return when {
        bytes < 1024 -> "$bytes B"
        bytes < 1024 * 1024 -> "${bytes / 1024} KB"
        bytes < 1024L * 1024 * 1024 -> String.format("%.1f MB", bytes / (1024.0 * 1024.0))
        else -> String.format("%.1f GB", bytes / (1024.0 * 1024.0 * 1024.0))
    }
}

private val uuidRegexSearch = Regex("^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$")

private fun parseFilePreviewSearch(preview: String): Pair<Long, String> {
    val parts = preview.split("::")
    return when {
        parts.size >= 3 && uuidRegexSearch.matches(parts[0]) -> {
            val size = parts[1].toLongOrNull() ?: 0L
            val name = parts.drop(2).joinToString("::")
            Pair(size, name)
        }
        parts.size >= 2 && !uuidRegexSearch.matches(parts[0]) -> {
            val size = parts[0].toLongOrNull() ?: 0L
            Pair(size, parts.drop(1).joinToString("::"))
        }
        parts.size >= 2 -> {
            Pair(0L, parts.drop(1).joinToString("::"))
        }
        else -> Pair(0L, "File")
    }
}

private fun openDownloadedFile(context: Context, file: File) {
    try {
        val uri = androidx.core.content.FileProvider.getUriForFile(
                context, "${context.packageName}.provider", file
        )
        val ext = file.name.substringAfterLast('.', "").lowercase()
        val mimeType = android.webkit.MimeTypeMap.getSingleton()
                .getMimeTypeFromExtension(ext) ?: "application/octet-stream"
        val intent = android.content.Intent(android.content.Intent.ACTION_VIEW).apply {
            setDataAndType(uri, mimeType)
            addFlags(android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION)
        }
        context.startActivity(intent)
    } catch (e: Exception) {
        android.widget.Toast.makeText(context, "Cannot open file", android.widget.Toast.LENGTH_SHORT).show()
    }
}

@Composable
private fun RecentUserItem(
        user: SearchUser,
        isDarkTheme: Boolean,
        textColor: Color,
        secondaryTextColor: Color,
        avatarRepository: AvatarRepository?,
        onClick: () -> Unit,
        onRemove: (() -> Unit)? = null
) {
    val displayName =
            user.title.ifEmpty { user.username.ifEmpty { user.publicKey.take(8) + "..." } }
    // Используем getInitials из ChatsListScreen
    val initials = getInitials(displayName)

    // Используем getAvatarColor из ChatsListScreen для правильных цветов
    val avatarColors = getAvatarColor(user.publicKey, isDarkTheme)

    Row(
            modifier =
                    Modifier.fillMaxWidth()
                            .clickable(onClick = onClick)
                            .padding(horizontal = 16.dp, vertical = 10.dp),
            verticalAlignment = Alignment.CenterVertically
    ) {
        // Avatar
        AvatarImage(
                publicKey = user.publicKey,
                avatarRepository = avatarRepository,
                size = 48.dp,
                isDarkTheme = isDarkTheme,
                showOnlineIndicator = false,
                isOnline = false,
                displayName = user.title.ifEmpty { user.username }  // 🔥 Для инициалов
        )

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

        // Name and username
        Column(modifier = Modifier.weight(1f)) {
            Row(verticalAlignment = Alignment.CenterVertically) {
                Text(
                        text = displayName,
                        fontSize = 16.sp,
                        fontWeight = FontWeight.Medium,
                        color = textColor,
                        maxLines = 1,
                        overflow = TextOverflow.Ellipsis
                )
                if (user.verified != 0) {
                    Spacer(modifier = Modifier.width(4.dp))
                    VerifiedBadge(
                            verified = user.verified,
                            size = 16
                    )
                }
            }
            if (user.username.isNotEmpty()) {
                Text(
                        text = "@${user.username}",
                        fontSize = 14.sp,
                        color = secondaryTextColor,
                        maxLines = 1,
                        overflow = TextOverflow.Ellipsis
                )
            }
        }

        // Remove button (only when onRemove provided)
        if (onRemove != null) {
            IconButton(onClick = onRemove, modifier = Modifier.size(40.dp)) {
                Icon(
                        painter = TelegramIcons.Close,
                        contentDescription = "Remove",
                        tint = secondaryTextColor.copy(alpha = 0.6f),
                        modifier = Modifier.size(20.dp)
                )
            }
        }
    }
}

/** NestedScrollConnection который скрывает клавиатуру при любом вертикальном скролле */
private class HideKeyboardNestedScroll(
    private val view: android.view.View,
    private val focusManager: androidx.compose.ui.focus.FocusManager
) : 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 (kotlin.math.abs(available.y) > 0.5f) {
            val imm = view.context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
            imm.hideSoftInputFromWindow(view.windowToken, 0)
            focusManager.clearFocus()
        }
        return androidx.compose.ui.geometry.Offset.Zero
    }
}
