package com.rosetta.messenger
// fix
import android.Manifest
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.provider.OpenableColumns
import android.provider.Settings
import android.view.WindowManager
import android.widget.Toast
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.compose.BackHandler
import androidx.compose.animation.*
import androidx.compose.animation.core.tween
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.platform.LocalView
import androidx.core.content.ContextCompat
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.lifecycleScope
import com.google.firebase.FirebaseApp
import com.google.firebase.messaging.FirebaseMessaging
import com.rosetta.messenger.data.AccountManager
import com.rosetta.messenger.data.DecryptedAccount
import com.rosetta.messenger.data.EncryptedAccount
import com.rosetta.messenger.data.PreferencesManager
import com.rosetta.messenger.data.MessageRepository
import com.rosetta.messenger.data.GroupRepository
import com.rosetta.messenger.crypto.CryptoManager
import com.rosetta.messenger.data.RecentSearchesManager
import com.rosetta.messenger.data.isPlaceholderAccountName
import com.rosetta.messenger.data.resolveAccountDisplayName
import com.rosetta.messenger.database.RosettaDatabase
import com.rosetta.messenger.di.IdentityGateway
import com.rosetta.messenger.di.ProtocolGateway
import com.rosetta.messenger.di.SessionCoordinator
import com.rosetta.messenger.network.CallActionResult
import com.rosetta.messenger.network.CallPhase
import com.rosetta.messenger.network.CallManager
import com.rosetta.messenger.network.AttachmentType
import com.rosetta.messenger.network.MessageAttachment
import com.rosetta.messenger.network.ProtocolState
import com.rosetta.messenger.network.SearchUser
import com.rosetta.messenger.repository.AvatarRepository
import com.rosetta.messenger.session.SessionState
import com.rosetta.messenger.ui.auth.AccountInfo
import com.rosetta.messenger.ui.auth.AuthFlow
import com.rosetta.messenger.ui.auth.DeviceConfirmScreen
import com.rosetta.messenger.ui.chats.ChatDetailScreen
import com.rosetta.messenger.ui.chats.ChatsListScreen
import com.rosetta.messenger.ui.chats.VoiceTopMiniPlayer
import com.rosetta.messenger.ui.chats.components.VoicePlaybackCoordinator
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.statusBarsPadding
import androidx.compose.ui.Alignment
import com.rosetta.messenger.ui.chats.ConnectionLogsScreen
import com.rosetta.messenger.ui.chats.GroupInfoScreen
import com.rosetta.messenger.ui.chats.GroupSetupScreen
import com.rosetta.messenger.ui.chats.RequestsListScreen
import com.rosetta.messenger.ui.chats.SearchScreen
import com.rosetta.messenger.ui.chats.calls.CallOverlay
import com.rosetta.messenger.ui.components.OptimizedEmojiCache
import com.rosetta.messenger.ui.components.SwipeBackBackgroundEffect
import com.rosetta.messenger.ui.components.SwipeBackContainer
import com.rosetta.messenger.ui.components.SwipeBackEnterAnimation
import com.rosetta.messenger.ui.crashlogs.CrashLogsScreen
import com.rosetta.messenger.ui.onboarding.OnboardingScreen
import com.rosetta.messenger.ui.settings.BackupScreen
import com.rosetta.messenger.ui.settings.BiometricEnableScreen
import com.rosetta.messenger.ui.settings.NotificationsScreen
import com.rosetta.messenger.ui.settings.OtherProfileScreen
import com.rosetta.messenger.ui.settings.ProfileScreen
import com.rosetta.messenger.ui.settings.SafetyScreen
import com.rosetta.messenger.ui.settings.ThemeScreen
import com.rosetta.messenger.ui.settings.ThemeWallpapers
import com.rosetta.messenger.ui.settings.UpdatesScreen
import com.rosetta.messenger.ui.splash.SplashScreen
import com.rosetta.messenger.ui.theme.RosettaAndroidTheme
import java.text.SimpleDateFormat
import java.io.File
import java.util.Date
import java.util.Locale
import java.util.UUID
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import javax.inject.Inject
import dagger.hilt.android.AndroidEntryPoint

@AndroidEntryPoint
class MainActivity : FragmentActivity() {
    @Inject lateinit var preferencesManager: PreferencesManager
    @Inject lateinit var accountManager: AccountManager
    @Inject lateinit var messageRepository: MessageRepository
    @Inject lateinit var groupRepository: GroupRepository
    @Inject lateinit var protocolGateway: ProtocolGateway
    @Inject lateinit var sessionCoordinator: SessionCoordinator
    @Inject lateinit var identityGateway: IdentityGateway

    private data class SharedPayload(
        val text: String = "",
        val streamUris: List<Uri> = emptyList()
    )
    private var pendingSharedPayload by mutableStateOf<SharedPayload?>(null)

    // Флаг: Activity открыта для ответа на звонок с lock screen — пропускаем auth
    // mutableStateOf чтобы Compose реагировал на изменение (избежать race condition)
    private var openedForCall by mutableStateOf(false)

    companion object {
        private const val TAG = "MainActivity"
        private const val FULL_SCREEN_INTENT_PREFS = "full_screen_intent_prefs"
        private const val FULL_SCREEN_INTENT_PROMPT_SHOWN_KEY = "full_screen_intent_prompt_shown"
        // Process-memory session cache: lets app return without password while process is alive.
        private var cachedDecryptedAccount: DecryptedAccount? = null

        // 🔔 FCM Логи для отображения в UI
        private val _fcmLogs = mutableStateListOf<String>()
        val fcmLogs: List<String>
            get() = _fcmLogs

        fun addFcmLog(message: String) {
            val timestamp = SimpleDateFormat("HH:mm:ss", Locale.getDefault()).format(Date())
            _fcmLogs.add(0, "[$timestamp] $message") // Добавляем в начало списка
            // Ограничиваем количество логов
            if (_fcmLogs.size > 20) {
                _fcmLogs.removeAt(_fcmLogs.size - 1)
            }
        }

            fun clearFcmLogs() {
                _fcmLogs.clear()
            }

        private fun cacheSessionAccount(account: DecryptedAccount?) {
            cachedDecryptedAccount = account
        }

        private fun getCachedSessionAccount(): DecryptedAccount? = cachedDecryptedAccount

        private fun clearCachedSessionAccount() {
            cachedDecryptedAccount = null
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()
        handleCallLockScreen(intent)
        pendingSharedPayload = extractSharedPayload(intent)

        RecentSearchesManager.init(this)

        // 🔥 Инициализируем Protocol runtime для обработки онлайн статусов
        protocolGateway.initialize(this)
        CallManager.initialize(this)
        com.rosetta.messenger.ui.chats.components.AttachmentDownloadDebugLogger.init(this)

        // 🔔 Инициализируем Firebase для push-уведомлений
        initializeFirebase()

        // 🔥 Помечаем что приложение в foreground
        com.rosetta.messenger.push.RosettaFirebaseMessagingService.isAppInForeground = true

        // 📱 Предзагружаем эмодзи в фоне для мгновенного открытия пикера
        // Используем новый оптимизированный кэш
        OptimizedEmojiCache.preload(this)

        setContent { // 🔔 Запрос разрешения на уведомления для Android 13+
            val notificationPermissionLauncher =
                    rememberLauncherForActivityResult(
                            contract = ActivityResultContracts.RequestPermission(),
                            onResult = { isGranted -> }
                    )
            val lifecycleOwner = LocalLifecycleOwner.current
            var canUseFullScreenIntent by remember { mutableStateOf(true) }
            var showFullScreenIntentDialog by remember { mutableStateOf(false) }

            val refreshFullScreenIntentState = remember {
                {
                    if (Build.VERSION.SDK_INT < 34) {
                        canUseFullScreenIntent = true
                        showFullScreenIntentDialog = false
                    } else {
                        val notificationManager =
                            getSystemService(Context.NOTIFICATION_SERVICE) as android.app.NotificationManager
                        val canUse = notificationManager.canUseFullScreenIntent()
                        canUseFullScreenIntent = canUse
                        showFullScreenIntentDialog = !canUse && !wasFullScreenIntentPromptShown()
                    }
                }
            }

            // Запрашиваем разрешение при первом запуске (Android 13+)
            LaunchedEffect(Unit) {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
                    val hasPermission =
                            ContextCompat.checkSelfPermission(
                                    this@MainActivity,
                                    Manifest.permission.POST_NOTIFICATIONS
                            ) == PackageManager.PERMISSION_GRANTED

                    if (!hasPermission) {
                        notificationPermissionLauncher.launch(
                                Manifest.permission.POST_NOTIFICATIONS
                        )
                    }
                }
                refreshFullScreenIntentState()
            }

            DisposableEffect(lifecycleOwner) {
                val observer = LifecycleEventObserver { _, event ->
                    if (event == Lifecycle.Event.ON_RESUME) {
                        refreshFullScreenIntentState()
                    }
                }
                lifecycleOwner.lifecycle.addObserver(observer)
                onDispose {
                    lifecycleOwner.lifecycle.removeObserver(observer)
                }
            }

            val scope = rememberCoroutineScope()
            val themeMode by preferencesManager.themeMode.collectAsState(initial = "dark")
            val systemInDarkTheme = isSystemInDarkTheme()
            val isDarkTheme =
                    when (themeMode) {
                        "light" -> false
                        "dark" -> true
                        "auto" -> systemInDarkTheme
                        else -> true
                    }
            val isLoggedIn by accountManager.isLoggedIn.collectAsState(initial = null)
            val protocolState by protocolGateway.state.collectAsState()
            var showSplash by remember { mutableStateOf(true) }
            var showOnboarding by remember { mutableStateOf(true) }
            var hasExistingAccount by remember { mutableStateOf<Boolean?>(null) }
            var currentAccount by remember { mutableStateOf(getCachedSessionAccount()) }
            val identityState by identityGateway.state.collectAsState()
            val sessionState by sessionCoordinator.sessionState.collectAsState()
            var accountInfoList by remember { mutableStateOf<List<AccountInfo>>(emptyList()) }
            var startCreateAccountFlow by remember { mutableStateOf(false) }
            var preservedMainNavStack by remember { mutableStateOf<List<Screen>>(emptyList()) }
            var preservedMainNavAccountKey by remember { mutableStateOf("") }

            // Check for existing accounts and build AccountInfo list
            LaunchedEffect(Unit) {
                sessionCoordinator.syncFromCachedAccount(currentAccount)
                val accounts = accountManager.getAllAccounts()
                hasExistingAccount = accounts.isNotEmpty()
                val infos = accounts.map { it.toAccountInfo() }
                accountInfoList = infos

                // Reconcile process-cached account name with persisted profile data.
                currentAccount?.let { cached ->
                    val persisted = infos.firstOrNull {
                        it.publicKey.equals(cached.publicKey, ignoreCase = true)
                    }
                    val persistedUsername = persisted?.username?.trim().orEmpty().ifBlank { null }
                    val normalizedCachedName =
                        resolveAccountDisplayName(
                            cached.publicKey,
                            persisted?.name ?: cached.name,
                            persistedUsername
                        )
                    if (normalizedCachedName != cached.name) {
                        val updated = cached.copy(name = normalizedCachedName)
                        currentAccount = updated
                        cacheSessionAccount(updated)
                    }
                }
            }

            LaunchedEffect(identityState.account) {
                val identityAccount = identityState.account ?: return@LaunchedEffect
                if (
                    identityAccount.publicKey != currentAccount?.publicKey ||
                        identityAccount.name != currentAccount?.name
                ) {
                    currentAccount = identityAccount
                    cacheSessionAccount(identityAccount)
                }
            }

            LaunchedEffect(sessionState) {
                val readyAccount = (sessionState as? SessionState.Ready)?.account ?: return@LaunchedEffect
                if (
                    currentAccount?.publicKey != readyAccount.publicKey ||
                        currentAccount?.name != readyAccount.name
                ) {
                    currentAccount = readyAccount
                    cacheSessionAccount(readyAccount)
                }
            }

            LaunchedEffect(currentAccount, isLoggedIn) {
                val account = currentAccount
                when {
                    account != null -> sessionCoordinator.markReady(account, reason = "main_activity_state")
                    isLoggedIn == true ->
                        sessionCoordinator.markAuthInProgress(reason = "main_activity_logged_in_no_account")
                    isLoggedIn == false -> sessionCoordinator.markLoggedOut(reason = "main_activity_logged_out")
                }
            }

            LaunchedEffect(pendingSharedPayload, currentAccount?.publicKey, sessionState) {
                val payload = pendingSharedPayload ?: return@LaunchedEffect
                val account =
                    currentAccount ?: (sessionState as? SessionState.Ready)?.account ?: return@LaunchedEffect

                runCatching {
                    val attachments =
                        withContext(Dispatchers.IO) {
                            payload.streamUris.mapNotNull { sourceUri ->
                                buildSharedAttachment(sourceUri)
                            }
                        }
                    val messageText = payload.text.trim()
                    if (messageText.isBlank() && attachments.isEmpty()) {
                        return@runCatching
                    }

                    messageRepository.initialize(account.publicKey, account.privateKey)
                    messageRepository.sendMessage(
                        toPublicKey = account.publicKey,
                        text = messageText,
                        attachments = attachments
                    )
                }.onSuccess {
                    pendingSharedPayload = null
                    val hadFiles = payload.streamUris.isNotEmpty()
                    Toast.makeText(
                        this@MainActivity,
                        if (hadFiles) {
                            "Shared content saved to Saved Messages"
                        } else {
                            "Shared text saved to Saved Messages"
                        },
                        Toast.LENGTH_SHORT
                    ).show()
                }.onFailure { error ->
                    android.util.Log.e(TAG, "Failed to import shared payload", error)
                }
            }

            // Wait for initial load
            if (hasExistingAccount == null) {
                Box(
                        modifier =
                                Modifier.fillMaxSize()
                                        .background(
                                                if (isDarkTheme) Color(0xFF1B1B1B) else Color.White
                                        )
                )
                return@setContent
            }

            RosettaAndroidTheme(darkTheme = isDarkTheme, animated = true) {
                Surface(
                        modifier = Modifier.fillMaxSize(),
                        color = if (isDarkTheme) Color(0xFF1B1B1B) else Color.White
                ) {
                    if (Build.VERSION.SDK_INT >= 34 && showFullScreenIntentDialog && !canUseFullScreenIntent) {
                        AlertDialog(
                            onDismissRequest = {
                                markFullScreenIntentPromptShown()
                                showFullScreenIntentDialog = false
                            },
                            containerColor = if (isDarkTheme) Color(0xFF1E1E20) else Color.White,
                            title = {
                                Text(
                                    text = "Allow full-screen call alerts?",
                                    color = if (isDarkTheme) Color.White else Color.Black
                                )
                            },
                            text = {
                                Text(
                                    text = "Without this permission incoming calls may show only as a regular notification.",
                                    color = if (isDarkTheme) Color(0xFFB5B5BC) else Color(0xFF5A5A66)
                                )
                            },
                            confirmButton = {
                                TextButton(
                                    onClick = {
                                        markFullScreenIntentPromptShown()
                                        showFullScreenIntentDialog = false
                                        runCatching {
                                            startActivity(
                                                Intent(
                                                    Settings.ACTION_MANAGE_APP_USE_FULL_SCREEN_INTENT,
                                                    Uri.parse("package:$packageName")
                                                )
                                            )
                                        }
                                    }
                                ) {
                                    Text(
                                        text = "Open settings",
                                        color = if (isDarkTheme) Color(0xFF5FA8FF) else Color(0xFF0D8CF4)
                                    )
                                }
                            },
                            dismissButton = {
                                TextButton(
                                    onClick = {
                                        markFullScreenIntentPromptShown()
                                        showFullScreenIntentDialog = false
                                    }
                                ) {
                                    Text(
                                        text = "Not now",
                                        color = if (isDarkTheme) Color(0xFFB5B5BC) else Color(0xFF5A5A66)
                                    )
                                }
                            }
                        )
                    }
                    AnimatedContent(
                            targetState =
                                    when {
                                        showSplash -> "splash"
                                        showOnboarding && hasExistingAccount == false ->
                                                "onboarding"
                                        // При открытии по звонку с lock screen — пропускаем auth
                                        openedForCall && hasExistingAccount == true ->
                                                "main"
                                        // User explicitly entered account creation flow:
                                        // keep auth screen even if intermediate session flags
                                        // briefly oscillate during DataStore updates.
                                        startCreateAccountFlow -> "auth_new"
                                        sessionState is SessionState.LoggedOut &&
                                                hasExistingAccount == false ->
                                                "auth_new"
                                        sessionState is SessionState.LoggedOut &&
                                                hasExistingAccount == true ->
                                                "auth_unlock"
                                        // First-registration race: DataStore may flip
                                        // logged-in marker before currentAccount is ready.
                                        // Keep user in create auth flow instead of jumping
                                        // to main with incomplete session context.
                                        sessionState is SessionState.AuthInProgress &&
                                                hasExistingAccount == false ->
                                                "auth_new"
                                        sessionState is SessionState.AuthInProgress &&
                                                hasExistingAccount == true ->
                                                "auth_unlock"
                                        protocolState ==
                                                ProtocolState.DEVICE_VERIFICATION_REQUIRED ->
                                                "device_confirm"
                                        sessionState is SessionState.Ready -> "main"
                                        else -> "main"
                                    },
                            transitionSpec = {
                                // Новый экран плавно появляется ПОВЕРХ старого.
                                // Старый остаётся видимым (alpha=1) пока новый не готов →
                                // нет белой вспышки от Surface.
                                fadeIn(animationSpec = tween(350)) togetherWith
                                        fadeOut(animationSpec = tween(1, delayMillis = 350))
                            },
                            label = "screenTransition"
                    ) { screen ->
                        when (screen) {
                            "splash" -> {
                                SplashScreen(
                                        isDarkTheme = isDarkTheme,
                                        onSplashComplete = { showSplash = false }
                                )
                            }
                            "onboarding" -> {
                                OnboardingScreen(
                                        isDarkTheme = isDarkTheme,
                                        onThemeToggle = {
                                            scope.launch {
                                                val newMode = if (isDarkTheme) "light" else "dark"
                                                preferencesManager.setThemeMode(newMode)
                                            }
                                        },
                                        onStartMessaging = { showOnboarding = false }
                                )
                            }
                            "auth_new", "auth_unlock" -> {
                                AuthFlow(
                                        isDarkTheme = isDarkTheme,
                                        hasExistingAccount = screen == "auth_unlock",
                                        accounts = accountInfoList,
                                        accountManager = accountManager,
                                        protocolGateway = protocolGateway,
                                        sessionCoordinator = sessionCoordinator,
                                        startInCreateMode = startCreateAccountFlow,
                                        onAuthComplete = { account ->
                                            startCreateAccountFlow = false
                                            val normalizedAccount =
                                                    account?.let { decrypted ->
                                                        val persisted =
                                                                accountInfoList.firstOrNull {
                                                                    it.publicKey.equals(
                                                                            decrypted.publicKey,
                                                                            ignoreCase = true
                                                                    )
                                                                }
                                                        val persistedUsername =
                                                                persisted?.username
                                                                        ?.trim()
                                                                        .orEmpty()
                                                                        .ifBlank { null }
                                                        val normalizedName =
                                                                resolveAccountDisplayName(
                                                                        decrypted.publicKey,
                                                                        persisted?.name
                                                                                ?: decrypted.name,
                                                                        persistedUsername
                                                                )
                                                        if (decrypted.name == normalizedName)
                                                                decrypted
                                                        else decrypted.copy(name = normalizedName)
                                                    }
                                            currentAccount = normalizedAccount
                                            cacheSessionAccount(normalizedAccount)
                                            normalizedAccount?.let {
                                                sessionCoordinator.markReady(
                                                    account = it,
                                                    reason = "auth_complete"
                                                )
                                            } ?: sessionCoordinator.markAuthInProgress(
                                                reason = "auth_complete_no_account"
                                            )
                                            hasExistingAccount = true

                                            // Reload accounts list
                                            scope.launch {
                                                normalizedAccount?.let {
                                                    // Force-refresh account title from persisted
                                                    // profile (name/username) to avoid temporary
                                                    // public-key alias in UI after login.
                                                    val persisted = accountManager.getAccount(it.publicKey)
                                                    val persistedUsername =
                                                            persisted?.username
                                                                    ?.trim()
                                                                    .orEmpty()
                                                                    .ifBlank { null }
                                                    val refreshedName =
                                                            resolveAccountDisplayName(
                                                                    it.publicKey,
                                                                    persisted?.name ?: it.name,
                                                                    persistedUsername
                                                            )
                                                    if (refreshedName != it.name) {
                                                        val updated = it.copy(name = refreshedName)
                                                        currentAccount = updated
                                                        cacheSessionAccount(updated)
                                                    }
                                                }
                                                val accounts = accountManager.getAllAccounts()
                                                accountInfoList = accounts.map { it.toAccountInfo() }
                                            }
                                        },
                                        onLogout = {
                                            startCreateAccountFlow = false
                                            preservedMainNavStack = emptyList()
                                            preservedMainNavAccountKey = ""
                                            // Set currentAccount to null immediately to prevent UI
                                            // lag
                                            currentAccount = null
                                            clearCachedSessionAccount()
                                            sessionCoordinator.markLoggedOut(
                                                reason = "auth_flow_logout"
                                            )
                                            protocolGateway.disconnect()
                                            scope.launch {
                                                accountManager.logout()
                                            }
                                        }
                                )
                            }
                            "main" -> {
                                val resolvedAccount =
                                        currentAccount
                                                ?: (sessionState as? SessionState.Ready)?.account
                                val activeAccountKey = resolvedAccount?.publicKey.orEmpty()
                                MainScreen(
                                        account = resolvedAccount,
                                        initialNavStack =
                                                if (
                                                        activeAccountKey.isNotBlank() &&
                                                                preservedMainNavAccountKey.equals(
                                                                        activeAccountKey,
                                                                        ignoreCase = true
                                                                )
                                                ) {
                                                    preservedMainNavStack
                                                } else {
                                                    emptyList()
                                                },
                                        accountManager = accountManager,
                                        preferencesManager = preferencesManager,
                                        messageRepository = messageRepository,
                                        groupRepository = groupRepository,
                                        protocolGateway = protocolGateway,
                                        identityGateway = identityGateway,
                                        onNavStackChanged = { stack ->
                                            if (activeAccountKey.isNotBlank()) {
                                                preservedMainNavAccountKey = activeAccountKey
                                                preservedMainNavStack = stack
                                            }
                                        },
                                        isDarkTheme = isDarkTheme,
                                        themeMode = themeMode,
                                        onToggleTheme = {
                                            scope.launch {
                                                val newMode = if (isDarkTheme) "light" else "dark"
                                                preferencesManager.setThemeMode(newMode)
                                            }
                                        },
                                        onThemeModeChange = { mode ->
                                            scope.launch { preferencesManager.setThemeMode(mode) }
                                        },
                                        onLogout = {
                                            startCreateAccountFlow = false
                                            preservedMainNavStack = emptyList()
                                            preservedMainNavAccountKey = ""
                                            // Set currentAccount to null immediately to prevent UI
                                            // lag
                                            currentAccount = null
                                            clearCachedSessionAccount()
                                            sessionCoordinator.markLoggedOut(
                                                reason = "main_logout"
                                            )
                                            protocolGateway.disconnect()
                                            scope.launch {
                                                accountManager.logout()
                                            }
                                        },
                                        onDeleteAccount = {
                                            startCreateAccountFlow = false
                                            preservedMainNavStack = emptyList()
                                            preservedMainNavAccountKey = ""
                                            val publicKey = currentAccount?.publicKey ?: return@MainScreen
                                            scope.launch {
                                                try {
                                                    val database = RosettaDatabase.getDatabase(this@MainActivity)
                                                    // 1. Delete all messages
                                                    database.messageDao().deleteAllByAccount(publicKey)
                                                    // 2. Delete all dialogs
                                                    database.dialogDao().deleteAllByAccount(publicKey)
                                                    // 3. Delete blacklist
                                                    database.blacklistDao().deleteAllByAccount(publicKey)
                                                    // 4. Delete avatars from DB
                                                    database.avatarDao().deleteAvatars(publicKey)
                                                    // 5. Delete account from Room DB
                                                    database.accountDao().deleteAccount(publicKey)
                                                    // 6. Disconnect protocol
                                                    protocolGateway.disconnect()
                                                    // 7. Delete account from AccountManager DataStore (removes from accounts list + clears login)
                                                    accountManager.deleteAccount(publicKey)
                                                    // 8. Refresh accounts list
                                                    val accounts = accountManager.getAllAccounts()
                                                    accountInfoList = accounts.map { it.toAccountInfo() }
                                                    hasExistingAccount = accounts.isNotEmpty()
                                                    // 8. Navigate away last
                                                    currentAccount = null
                                                    clearCachedSessionAccount()
                                                    sessionCoordinator.markLoggedOut(
                                                        reason = "delete_current_account"
                                                    )
                                                } catch (e: Exception) {
                                                    android.util.Log.e("DeleteAccount", "Failed to delete account", e)
                                                }
                                            }
                                        },
                                        onAccountInfoUpdated = {
                                            // Reload account list when profile is updated
                                            val accounts = accountManager.getAllAccounts()
                                            accountInfoList = accounts.map { it.toAccountInfo() }
                                        },
                                        onDeleteAccountFromSidebar = { targetPublicKey ->
                                            startCreateAccountFlow = false
                                            scope.launch {
                                                try {
                                                    val database = RosettaDatabase.getDatabase(this@MainActivity)
                                                    // 1. Delete all messages
                                                    database.messageDao().deleteAllByAccount(targetPublicKey)
                                                    // 2. Delete all dialogs
                                                    database.dialogDao().deleteAllByAccount(targetPublicKey)
                                                    // 3. Delete blacklist
                                                    database.blacklistDao().deleteAllByAccount(targetPublicKey)
                                                    // 4. Delete avatars from DB
                                                    database.avatarDao().deleteAvatars(targetPublicKey)
                                                    // 5. Delete account from Room DB
                                                    database.accountDao().deleteAccount(targetPublicKey)
                                                    // 6. Disconnect protocol only if deleting currently open account
                                                    if (currentAccount?.publicKey == targetPublicKey) {
                                                        protocolGateway.disconnect()
                                                    }
                                                    // 7. Delete account from AccountManager DataStore
                                                    accountManager.deleteAccount(targetPublicKey)
                                                    // 8. Refresh accounts list
                                                    val accounts = accountManager.getAllAccounts()
                                                    accountInfoList = accounts.map { it.toAccountInfo() }
                                                    hasExistingAccount = accounts.isNotEmpty()
                                                    // 9. If current account is deleted, return to main login screen
                                                    if (currentAccount?.publicKey == targetPublicKey) {
                                                        preservedMainNavStack = emptyList()
                                                        preservedMainNavAccountKey = ""
                                                        currentAccount = null
                                                        clearCachedSessionAccount()
                                                        sessionCoordinator.markLoggedOut(
                                                            reason = "delete_sidebar_current_account"
                                                        )
                                                    }
                                                } catch (e: Exception) {
                                                    android.util.Log.e("DeleteAccount", "Failed to delete account from sidebar", e)
                                                }
                                            }
                                        },
                                        onSwitchAccount = { targetPublicKey ->
                                            startCreateAccountFlow = false
                                            preservedMainNavStack = emptyList()
                                            preservedMainNavAccountKey = ""
                                            // Save target account before leaving main screen so Unlock
                                            // screen preselects the account the user tapped.
                                            accountManager.setLastLoggedPublicKey(targetPublicKey)

                                            // Switch to another account: logout current, then show unlock.
                                            currentAccount = null
                                            clearCachedSessionAccount()
                                            sessionCoordinator.markLoggedOut(
                                                reason = "switch_account"
                                            )
                                            protocolGateway.disconnect()
                                            scope.launch {
                                                accountManager.logout()
                                            }
                                        },
                                        onAddAccount = {
                                            startCreateAccountFlow = true
                                            preservedMainNavStack = emptyList()
                                            preservedMainNavAccountKey = ""
                                            currentAccount = null
                                            clearCachedSessionAccount()
                                            sessionCoordinator.markLoggedOut(
                                                reason = "add_account"
                                            )
                                            protocolGateway.disconnect()
                                            scope.launch {
                                                accountManager.logout()
                                            }
                                        }
                                )
                            }
                            "device_confirm" -> {
                                DeviceConfirmScreen(
                                        isDarkTheme = isDarkTheme,
                                        protocolGateway = protocolGateway,
                                        onExit = {
                                            preservedMainNavStack = emptyList()
                                            preservedMainNavAccountKey = ""
                                            currentAccount = null
                                            clearCachedSessionAccount()
                                            sessionCoordinator.markLoggedOut(
                                                reason = "device_confirm_exit"
                                            )
                                            protocolGateway.disconnect()
                                            scope.launch {
                                                accountManager.logout()
                                            }
                                        }
                                )
                            }
                        }
                    }
                }
            }
        }
    }

    override fun onNewIntent(intent: Intent) {
        super.onNewIntent(intent)
        setIntent(intent)
        handleCallLockScreen(intent)
        pendingSharedPayload = extractSharedPayload(intent)
    }

    private fun extractSharedPayload(intent: Intent?): SharedPayload? {
        if (intent == null) return null
        val action = intent.action ?: return null
        if (action != Intent.ACTION_SEND && action != Intent.ACTION_SEND_MULTIPLE) return null

        val sharedText =
            (
                intent.getStringExtra(Intent.EXTRA_TEXT)
                    ?: intent.getCharSequenceExtra(Intent.EXTRA_TEXT)?.toString()
                    ?: intent.getStringExtra(Intent.EXTRA_SUBJECT)
                )
                ?.trim()
                .orEmpty()

        val sharedUris =
            when (action) {
                Intent.ACTION_SEND -> {
                    listOfNotNull(getParcelableUriExtra(intent, Intent.EXTRA_STREAM))
                }
                Intent.ACTION_SEND_MULTIPLE -> {
                    getParcelableUriListExtra(intent, Intent.EXTRA_STREAM)
                }
                else -> emptyList()
            }

        if (sharedText.isBlank() && sharedUris.isEmpty()) return null
        return SharedPayload(text = sharedText, streamUris = sharedUris)
    }

    private fun getParcelableUriExtra(intent: Intent, key: String): Uri? {
        return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            intent.getParcelableExtra(key, Uri::class.java)
        } else {
            @Suppress("DEPRECATION")
            intent.getParcelableExtra(key) as? Uri
        }
    }

    private fun getParcelableUriListExtra(intent: Intent, key: String): List<Uri> {
        return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            intent.getParcelableArrayListExtra(key, Uri::class.java)?.filterNotNull().orEmpty()
        } else {
            @Suppress("DEPRECATION")
            intent.getParcelableArrayListExtra<Uri>(key)?.filterNotNull().orEmpty()
        }
    }

    private fun buildSharedAttachment(sourceUri: Uri): MessageAttachment? {
        val cachedUri = copySharedUriToCache(sourceUri) ?: return null
        val mimeType = contentResolver.getType(sourceUri).orEmpty().lowercase(Locale.ROOT)
        val fileName = queryDisplayName(sourceUri) ?: cachedUri.lastPathSegment ?: "shared_file"
        val fileSize = querySize(sourceUri) ?: runCatching { File(cachedUri.path ?: "").length() }.getOrNull() ?: 0L
        val type = if (mimeType.startsWith("image/")) AttachmentType.IMAGE else AttachmentType.FILE
        val preview =
            if (type == AttachmentType.FILE) {
                "${fileSize.coerceAtLeast(0L)}::$fileName"
            } else {
                ""
            }

        return MessageAttachment(
            id = UUID.randomUUID().toString().replace("-", "").take(32),
            blob = "",
            type = type,
            preview = preview,
            localUri = cachedUri.toString()
        )
    }

    private fun copySharedUriToCache(sourceUri: Uri): Uri? {
        return runCatching {
            val sourceName = queryDisplayName(sourceUri).orEmpty()
            val extension =
                sourceName.substringAfterLast('.', "").trim().takeIf { it.isNotBlank() }
            val targetDir = File(cacheDir, "shared_import").apply { mkdirs() }
            val targetFileName =
                buildString {
                    append("shared_")
                    append(System.currentTimeMillis())
                    append('_')
                    append((1000..9999).random())
                    if (extension != null) {
                        append('.')
                        append(extension)
                    }
                }
            val targetFile = File(targetDir, targetFileName)

            contentResolver.openInputStream(sourceUri)?.use { input ->
                targetFile.outputStream().use { output ->
                    input.copyTo(output)
                }
            } ?: return null

            Uri.fromFile(targetFile)
        }.getOrNull()
    }

    private fun queryDisplayName(uri: Uri): String? {
        return runCatching {
            contentResolver.query(uri, arrayOf(OpenableColumns.DISPLAY_NAME), null, null, null)
                ?.use { cursor ->
                    if (cursor.moveToFirst()) {
                        cursor.getString(0)?.trim()?.ifBlank { null }
                    } else {
                        null
                    }
                }
        }.getOrNull()
    }

    private fun querySize(uri: Uri): Long? {
        return runCatching {
            contentResolver.query(uri, arrayOf(OpenableColumns.SIZE), null, null, null)
                ?.use { cursor ->
                    if (cursor.moveToFirst()) {
                        val size = cursor.getLong(0)
                        if (size >= 0L) size else null
                    } else {
                        null
                    }
                }
        }.getOrNull()
    }

    private var callIntentResetJob: kotlinx.coroutines.Job? = null

    /**
     * Обрабатывает переход из call-notification.
     * На lockscreen НЕ поднимаем MainActivity поверх keyguard и НЕ снимаем блокировку.
     */
    private fun handleCallLockScreen(intent: Intent?) {
        val isCallIntent = intent?.getBooleanExtra(
            com.rosetta.messenger.network.CallForegroundService.EXTRA_OPEN_CALL_FROM_NOTIFICATION, false
        ) == true
        if (isCallIntent) {
            val keyguardManager = getSystemService(Context.KEYGUARD_SERVICE) as? android.app.KeyguardManager
            val isDeviceLocked = keyguardManager?.isDeviceLocked == true
            // Если экран заблокирован — не обходим auth и не показываем MainActivity поверх keyguard.
            openedForCall = !isDeviceLocked

            if (openedForCall) {
                callIntentResetJob?.cancel()
                callIntentResetJob = lifecycleScope.launch {
                    com.rosetta.messenger.network.CallManager.state.collect { state ->
                        if (state.phase == com.rosetta.messenger.network.CallPhase.IDLE) {
                            openedForCall = false
                            callIntentResetJob?.cancel()
                            callIntentResetJob = null
                        }
                    }
                }
            }

            // На всякий случай принудительно чистим lock-screen флаги.
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
                setShowWhenLocked(false)
                setTurnScreenOn(false)
            } else {
                @Suppress("DEPRECATION")
                window.clearFlags(
                    android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED or
                        android.view.WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON or
                        android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
                )
            }
        }
    }

    override fun onResume() {
        super.onResume()
        com.rosetta.messenger.push.RosettaFirebaseMessagingService.isAppInForeground = true
        (getSystemService(NOTIFICATION_SERVICE) as android.app.NotificationManager).cancelAll()
        protocolGateway.setAppInForeground(true)
        protocolGateway.reconnectNowIfNeeded("activity_onResume")
    }

    override fun onPause() {
        super.onPause()
        com.rosetta.messenger.push.RosettaFirebaseMessagingService.isAppInForeground = false
        protocolGateway.setAppInForeground(false)
    }

    /** 🔔 Инициализация Firebase Cloud Messaging */
    private fun initializeFirebase() {
        lifecycleScope.launch(Dispatchers.Default) {
            try {
                addFcmLog("🔔 Инициализация Firebase...")
                // Инициализируем Firebase (тяжёлая операция — не на Main)
                FirebaseApp.initializeApp(this@MainActivity)
                addFcmLog("✅ Firebase инициализирован")

                // Получаем FCM токен
                addFcmLog("📲 Запрос FCM токена...")
                FirebaseMessaging.getInstance().token.addOnCompleteListener { task ->
                    if (!task.isSuccessful) {
                        addFcmLog("❌ Ошибка получения токена: ${task.exception?.message}")
                        return@addOnCompleteListener
                    }

                    val token = task.result

                    if (token != null) {
                        val shortToken = "${token.take(12)}...${token.takeLast(8)}"
                        addFcmLog("✅ FCM токен получен: $shortToken")
                        // Сохраняем токен локально
                        saveFcmToken(token)
                        addFcmLog("💾 Токен сохранен локально")
                        if (protocolGateway.isAuthenticated()) {
                            runCatching {
                                        protocolGateway.subscribePushTokenIfAvailable(
                                                forceToken = token
                                        )
                                    }
                                    .onSuccess {
                                        addFcmLog("🔔 Push token отправлен на сервер сразу")
                                    }
                                    .onFailure { error ->
                                        addFcmLog(
                                                "❌ Ошибка отправки push token: ${error.message}"
                                        )
                                    }
                        }
                    } else {
                        addFcmLog("⚠️ Токен пустой")
                    }
                }
            } catch (e: Exception) {
                addFcmLog("❌ Ошибка Firebase: ${e.message}")
            }
        }
    }

    /** Сохранить FCM токен в SharedPreferences */
    private fun saveFcmToken(token: String) {
        val prefs = getSharedPreferences("rosetta_prefs", MODE_PRIVATE)
        prefs.edit().putString("fcm_token", token).apply()
    }

    private fun wasFullScreenIntentPromptShown(): Boolean {
        return getSharedPreferences(FULL_SCREEN_INTENT_PREFS, MODE_PRIVATE)
            .getBoolean(FULL_SCREEN_INTENT_PROMPT_SHOWN_KEY, false)
    }

    private fun markFullScreenIntentPromptShown() {
        getSharedPreferences(FULL_SCREEN_INTENT_PREFS, MODE_PRIVATE)
            .edit()
            .putBoolean(FULL_SCREEN_INTENT_PROMPT_SHOWN_KEY, true)
            .apply()
    }

}

private fun buildInitials(displayName: String): String =
        displayName
                .trim()
                .split(Regex("\\s+"))
                .filter { it.isNotEmpty() }
                .let { words ->
                    when {
                        words.isEmpty() -> "??"
                        words.size == 1 -> words[0].take(2).uppercase()
                        else -> "${words[0].first()}${words[1].first()}".uppercase()
                    }
                }

private fun EncryptedAccount.toAccountInfo(): AccountInfo {
    val displayName = resolveAccountDisplayName(publicKey, name, username)
    return AccountInfo(
            id = publicKey,
            name = displayName,
            username = username ?: "",
            initials = buildInitials(displayName),
            publicKey = publicKey
    )
}

/**
 * Navigation sealed class — replaces ~15 boolean flags with a type-safe navigation stack. ChatsList
 * is always the base layer and is not part of the stack. Each SwipeBackContainer reads a
 * derivedStateOf, so pushing/popping an unrelated screen won't trigger recomposition of other
 * screens.
 */
sealed class Screen {
    data object Profile : Screen()
    data object ProfileFromChat : Screen()
    data object Notifications : Screen()
    data object Requests : Screen()
    data object Search : Screen()
    data object GroupSetup : Screen()
    data class GroupInfo(val group: SearchUser) : Screen()
    data class ChatDetail(val user: SearchUser) : Screen()
    data class OtherProfile(val user: SearchUser) : Screen()
    data object Updates : Screen()
    data object Theme : Screen()
    data object Safety : Screen()
    data object Backup : Screen()
    data object Logs : Screen()
    data object ConnectionLogs : Screen()
    data object CrashLogs : Screen()
    data object Biometric : Screen()
    data object Appearance : Screen()
    data object AppIcon : Screen()
    data object QrScanner : Screen()
    data object MyQr : Screen()
}

@Composable
fun MainScreen(
        account: DecryptedAccount? = null,
        initialNavStack: List<Screen> = emptyList(),
        onNavStackChanged: (List<Screen>) -> Unit = {},
        accountManager: AccountManager,
        preferencesManager: PreferencesManager,
        messageRepository: MessageRepository,
        groupRepository: GroupRepository,
        protocolGateway: ProtocolGateway,
        identityGateway: IdentityGateway,
        isDarkTheme: Boolean = true,
        themeMode: String = "dark",
        onToggleTheme: () -> Unit = {},
        onThemeModeChange: (String) -> Unit = {},
        onLogout: () -> Unit = {},
        onDeleteAccount: () -> Unit = {},
        onAccountInfoUpdated: suspend () -> Unit = {},
        onSwitchAccount: (String) -> Unit = {},
        onDeleteAccountFromSidebar: (String) -> Unit = {},
        onAddAccount: () -> Unit = {}
) {
    val accountPublicKey = account?.publicKey.orEmpty()

    // Reactive state for account name and username
    var accountName by remember(accountPublicKey) {
        mutableStateOf(resolveAccountDisplayName(accountPublicKey, account?.name, null))
    }
    val accountPhone =
            account?.publicKey?.take(16)?.let {
                "+${it.take(1)} ${it.substring(1, 4)} ${it.substring(4, 7)}${it.substring(7)}"
            }
                    .orEmpty()
    val accountPrivateKey = account?.privateKey ?: ""
    val privateKeyHash = account?.privateKeyHash ?: ""

    // Username state - загружается из EncryptedAccount
    // Following desktop version pattern: username is stored locally and loaded on app start
    var accountUsername by remember { mutableStateOf("") }
    var accountVerified by remember(accountPublicKey) { mutableIntStateOf(0) }
    val identitySnapshot by identityGateway.state.collectAsState()
    var reloadTrigger by remember { mutableIntStateOf(0) }

    // Load username AND name from AccountManager (persisted in DataStore)
    val context = LocalContext.current
    val focusManager = LocalFocusManager.current
    val rootView = LocalView.current
    val callScope = rememberCoroutineScope()
    val callUiState by CallManager.state.collectAsState()
    var isCallOverlayExpanded by remember { mutableStateOf(true) }
    var pendingOutgoingCall by remember { mutableStateOf<SearchUser?>(null) }
    var pendingIncomingAccept by remember { mutableStateOf(false) }
    var callPermissionsRequestedOnce by remember { mutableStateOf(false) }
    val isCallScreenVisible =
        callUiState.isVisible &&
            (isCallOverlayExpanded || callUiState.phase == CallPhase.INCOMING)

    val mandatoryCallPermissions = remember {
        listOf(Manifest.permission.RECORD_AUDIO)
    }
    val optionalCallPermissions = remember {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
            listOf(Manifest.permission.BLUETOOTH_CONNECT)
        } else {
            emptyList()
        }
    }
    val permissionsToRequest = remember(mandatoryCallPermissions, optionalCallPermissions) {
        mandatoryCallPermissions + optionalCallPermissions
    }

    val hasMandatoryCallPermissions: () -> Boolean =
        remember(context, mandatoryCallPermissions) {
        {
            mandatoryCallPermissions.all { permission ->
                ContextCompat.checkSelfPermission(context, permission) ==
                    PackageManager.PERMISSION_GRANTED
            }
        }
    }
    val hasOptionalCallPermissions: () -> Boolean =
        remember(context, optionalCallPermissions) {
            {
                optionalCallPermissions.all { permission ->
                    ContextCompat.checkSelfPermission(context, permission) ==
                        PackageManager.PERMISSION_GRANTED
                }
            }
        }

    val showCallError: (CallActionResult) -> Unit = { result ->
        val message =
            when (result) {
                CallActionResult.STARTED -> ""
                CallActionResult.ALREADY_IN_CALL -> "Сначала заверши текущий звонок"
                CallActionResult.NOT_AUTHENTICATED -> "Нет подключения к серверу"
                CallActionResult.ACCOUNT_NOT_BOUND -> "Аккаунт еще не инициализирован"
                CallActionResult.INVALID_TARGET -> "Не удалось определить пользователя для звонка"
                CallActionResult.NOT_INCOMING -> "Входящий звонок не найден"
            }
        if (message.isNotBlank()) {
            Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
        }
    }

    val resolveCallableUser: suspend (SearchUser) -> SearchUser? = resolve@{ user ->
        val publicKey = user.publicKey.trim()
        if (publicKey.isNotBlank()) {
            return@resolve user.copy(publicKey = publicKey)
        }

        val usernameQuery = user.username.trim().trimStart('@')
        if (usernameQuery.isBlank()) {
            return@resolve null
        }

        protocolGateway.getCachedUserByUsername(usernameQuery)?.let { cached ->
            if (cached.publicKey.isNotBlank()) return@resolve cached
        }

        val results = protocolGateway.searchUsers(usernameQuery)
        results.firstOrNull {
            it.publicKey.isNotBlank() &&
                it.username.trim().trimStart('@')
                    .equals(usernameQuery, ignoreCase = true)
        }?.let { return@resolve it }

        return@resolve results.firstOrNull { it.publicKey.isNotBlank() }
    }

    val startOutgoingCallSafely: (SearchUser) -> Unit = { user ->
        callScope.launch {
            val resolved = resolveCallableUser(user)
            if (resolved == null) {
                showCallError(CallActionResult.INVALID_TARGET)
                return@launch
            }
            val result = CallManager.startOutgoingCall(resolved)
            if (result != CallActionResult.STARTED) {
                showCallError(result)
            }
        }
    }

    val acceptIncomingCallSafely: () -> Unit = {
        val result = CallManager.acceptIncomingCall()
        if (result != CallActionResult.STARTED) {
            showCallError(result)
        }
    }

    val callPermissionLauncher =
        rememberLauncherForActivityResult(
            contract = ActivityResultContracts.RequestMultiplePermissions()
        ) { grantedMap ->
            callPermissionsRequestedOnce = true
            val micGranted =
                grantedMap[Manifest.permission.RECORD_AUDIO] == true ||
                    ContextCompat.checkSelfPermission(context, Manifest.permission.RECORD_AUDIO) ==
                        PackageManager.PERMISSION_GRANTED

            val bluetoothGranted =
                if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {
                    true
                } else {
                    grantedMap[Manifest.permission.BLUETOOTH_CONNECT] == true ||
                        ContextCompat.checkSelfPermission(
                            context,
                            Manifest.permission.BLUETOOTH_CONNECT
                        ) == PackageManager.PERMISSION_GRANTED
                }

            if (!micGranted) {
                Toast.makeText(
                    context,
                    "Для звонков нужен доступ к микрофону",
                    Toast.LENGTH_SHORT
                ).show()
            } else {
                pendingOutgoingCall?.let { startOutgoingCallSafely(it) }
                if (pendingIncomingAccept) {
                    acceptIncomingCallSafely()
                }
                if (!bluetoothGranted && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
                    Toast.makeText(
                        context,
                        "Bluetooth недоступен: гарнитура может не работать",
                        Toast.LENGTH_SHORT
                    ).show()
                }
            }
            pendingOutgoingCall = null
            pendingIncomingAccept = false
        }

    val startCallWithPermission: (SearchUser) -> Unit = { user ->
        val shouldRequestPermissions =
            !hasMandatoryCallPermissions() ||
                (!callPermissionsRequestedOnce && !hasOptionalCallPermissions())
        if (!shouldRequestPermissions) {
            startOutgoingCallSafely(user)
        } else {
            pendingOutgoingCall = user
            callPermissionLauncher.launch(permissionsToRequest.toTypedArray())
        }
    }
    val acceptCallWithPermission: () -> Unit = {
        val shouldRequestPermissions =
            !hasMandatoryCallPermissions() ||
                (!callPermissionsRequestedOnce && !hasOptionalCallPermissions())
        if (!shouldRequestPermissions) {
            acceptIncomingCallSafely()
        } else {
            pendingIncomingAccept = true
            callPermissionLauncher.launch(permissionsToRequest.toTypedArray())
        }
    }

    LaunchedEffect(accountPublicKey) {
        CallManager.bindAccount(accountPublicKey)
    }

    // Global account binding for protocol/message repository.
    // Keeps init independent from ChatsList composition timing.
    LaunchedEffect(accountPublicKey, accountPrivateKey) {
        val normalizedPublicKey = accountPublicKey.trim()
        val normalizedPrivateKey = accountPrivateKey.trim()
        if (normalizedPublicKey.isBlank() || normalizedPrivateKey.isBlank()) return@LaunchedEffect
        protocolGateway.initializeAccount(normalizedPublicKey, normalizedPrivateKey)
    }

    LaunchedEffect(callUiState.isVisible) {
        if (callUiState.isVisible) {
            isCallOverlayExpanded = true
        } else {
            isCallOverlayExpanded = false
        }
    }

    val forceHideCallKeyboard: () -> Unit = {
        focusManager.clearFocus(force = true)
        rootView.findFocus()?.clearFocus()
        rootView.clearFocus()
        val activity = rootView.context as? android.app.Activity
        activity?.window?.let { window ->
            WindowCompat.getInsetsController(window, rootView)
                .hide(WindowInsetsCompat.Type.ime())
        }
    }

    DisposableEffect(isCallScreenVisible) {
        val activity = rootView.context as? android.app.Activity
        val previousSoftInputMode = activity?.window?.attributes?.softInputMode
        if (isCallScreenVisible) {
            forceHideCallKeyboard()
            activity?.window?.setSoftInputMode(
                WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN
            )
        }
        onDispose {
            if (isCallScreenVisible && previousSoftInputMode != null) {
                activity.window.setSoftInputMode(previousSoftInputMode)
            }
        }
    }

    if (isCallScreenVisible) {
        SideEffect {
            forceHideCallKeyboard()
        }
    }

    // Telegram-style behavior: while call screen is open, Back should minimize call to top banner.
    BackHandler(
        enabled = callUiState.isVisible &&
            isCallOverlayExpanded &&
            callUiState.phase != CallPhase.INCOMING
    ) {
        isCallOverlayExpanded = false
    }

    suspend fun refreshAccountIdentityState(accountKey: String) {
        val encryptedAccount = accountManager.getAccount(accountKey)
        val identityOwn =
                identitySnapshot.profile?.takeIf {
                    it.publicKey.equals(accountKey, ignoreCase = true)
                }
        val cachedOwn = protocolGateway.getCachedUserInfo(accountKey)

        val persistedName = encryptedAccount?.name?.trim().orEmpty()
        val persistedUsername = encryptedAccount?.username?.trim().orEmpty()
        val cachedName =
                identityOwn?.displayName?.trim().orEmpty().ifBlank {
                    cachedOwn?.title?.trim().orEmpty()
                }
        val cachedUsername =
                identityOwn?.username?.trim().orEmpty().ifBlank {
                    cachedOwn?.username?.trim().orEmpty()
                }

        if (cachedName.isNotBlank() &&
                !isPlaceholderAccountName(cachedName) &&
                (persistedName.isBlank() || isPlaceholderAccountName(persistedName))) {
            runCatching { accountManager.updateAccountName(accountKey, cachedName) }
        }
        if (cachedUsername.isNotBlank() && persistedUsername.isBlank()) {
            runCatching { accountManager.updateAccountUsername(accountKey, cachedUsername) }
        }

        val finalUsername = persistedUsername.ifBlank { cachedUsername }
        val preferredName =
                when {
                    persistedName.isNotBlank() && !isPlaceholderAccountName(persistedName) ->
                            persistedName
                    cachedName.isNotBlank() && !isPlaceholderAccountName(cachedName) -> cachedName
                    else -> encryptedAccount?.name ?: accountName
                }

        accountUsername = finalUsername
        accountVerified = identityOwn?.verified ?: cachedOwn?.verified ?: 0
        accountName = resolveAccountDisplayName(accountKey, preferredName, finalUsername)
        identityGateway.updateOwnProfile(
            publicKey = accountKey,
            displayName = accountName,
            username = accountUsername,
            verified = accountVerified,
            resolved = true,
            reason = "main_screen_refresh"
        )
    }

    LaunchedEffect(accountPublicKey, reloadTrigger) {
        if (accountPublicKey.isNotBlank()) {
            refreshAccountIdentityState(accountPublicKey)
        } else {
            accountVerified = 0
        }
    }

    LaunchedEffect(identitySnapshot.profile, accountPublicKey) {
        val profile = identitySnapshot.profile ?: return@LaunchedEffect
        if (!profile.publicKey.equals(accountPublicKey, ignoreCase = true)) return@LaunchedEffect

        val normalizedName =
            resolveAccountDisplayName(
                accountPublicKey,
                profile.displayName.ifBlank { accountName },
                profile.username.ifBlank { null }
            )
        accountName = normalizedName
        accountUsername = profile.username
        accountVerified = profile.verified
    }

    // Состояние протокола для передачи в SearchScreen
    val protocolState by protocolGateway.state.collectAsState()

    // Реактивно обновляем username/name когда сервер отвечает на fetchOwnProfile()
    val ownProfileUpdated by protocolGateway.ownProfileUpdated.collectAsState()
    LaunchedEffect(ownProfileUpdated, accountPublicKey) {
        if (ownProfileUpdated > 0L && accountPublicKey.isNotBlank()) {
            refreshAccountIdentityState(accountPublicKey)
        }
    }

    // ═══════════════════════════════════════════════════════════
    // Navigation stack — sealed class instead of ~15 boolean flags.
    // ChatsList is always the base layer (not in stack).
    // Each derivedStateOf only recomposes its SwipeBackContainer
    // when that specific screen appears/disappears — not on every
    // navigation change. This eliminates the massive recomposition
    // that happened when ANY boolean flag changed.
    // ═══════════════════════════════════════════════════════════
    var navStack by remember(accountPublicKey) { mutableStateOf(initialNavStack) }
    LaunchedEffect(navStack) { onNavStackChanged(navStack) }

    // Derived visibility — only triggers recomposition when THIS screen changes
    val isProfileVisible by remember { derivedStateOf { navStack.any { it is Screen.Profile } } }
    val isProfileFromChatVisible by remember {
        derivedStateOf { navStack.any { it is Screen.ProfileFromChat } }
    }
    val isRequestsVisible by remember { derivedStateOf { navStack.any { it is Screen.Requests } } }
    val isNotificationsVisible by remember {
        derivedStateOf { navStack.any { it is Screen.Notifications } }
    }
    val isSearchVisible by remember { derivedStateOf { navStack.any { it is Screen.Search } } }
    val isGroupSetupVisible by remember { derivedStateOf { navStack.any { it is Screen.GroupSetup } } }
    val chatDetailScreen by remember {
        derivedStateOf { navStack.filterIsInstance<Screen.ChatDetail>().lastOrNull() }
    }
    val selectedUser = chatDetailScreen?.user
    val groupInfoScreen by remember {
        derivedStateOf { navStack.filterIsInstance<Screen.GroupInfo>().lastOrNull() }
    }
    val selectedGroup = groupInfoScreen?.group
    val otherProfileScreen by remember {
        derivedStateOf { navStack.filterIsInstance<Screen.OtherProfile>().lastOrNull() }
    }
    val selectedOtherUser = otherProfileScreen?.user
    val isUpdatesVisible by remember { derivedStateOf { navStack.any { it is Screen.Updates } } }
    val isThemeVisible by remember { derivedStateOf { navStack.any { it is Screen.Theme } } }
    val isSafetyVisible by remember { derivedStateOf { navStack.any { it is Screen.Safety } } }
    val isBackupVisible by remember { derivedStateOf { navStack.any { it is Screen.Backup } } }
    val isLogsVisible by remember { derivedStateOf { navStack.any { it is Screen.Logs } } }
    val isConnectionLogsVisible by remember {
        derivedStateOf { navStack.any { it is Screen.ConnectionLogs } }
    }
    val isCrashLogsVisible by remember {
        derivedStateOf { navStack.any { it is Screen.CrashLogs } }
    }
    val isBiometricVisible by remember {
        derivedStateOf { navStack.any { it is Screen.Biometric } }
    }
    val isAppearanceVisible by remember {
        derivedStateOf { navStack.any { it is Screen.Appearance } }
    }
    val isAppIconVisible by remember {
        derivedStateOf { navStack.any { it is Screen.AppIcon } }
    }
    val isQrScannerVisible by remember { derivedStateOf { navStack.any { it is Screen.QrScanner } } }
    val isMyQrVisible by remember { derivedStateOf { navStack.any { it is Screen.MyQr } } }
    var profileHasUnsavedChanges by remember(accountPublicKey) { mutableStateOf(false) }
    var showDiscardProfileChangesDialog by remember { mutableStateOf(false) }
    var discardProfileChangesFromChat by remember { mutableStateOf(false) }

    // Navigation helpers
    fun pushScreen(screen: Screen) {
        // Anti-spam: do not stack duplicate screens from rapid taps.
        if (navStack.lastOrNull() == screen) return
        if (screen is Screen.Requests && navStack.any { it is Screen.Requests }) return
        // Hide keyboard and clear focus when navigating to any screen
        (context as? android.app.Activity)?.currentFocus?.let { focusedView ->
            val imm = context.getSystemService(android.content.Context.INPUT_METHOD_SERVICE) as android.view.inputmethod.InputMethodManager
            imm.hideSoftInputFromWindow(focusedView.windowToken, 0)
            focusedView.clearFocus()
        }
        navStack = navStack + screen
    }
    fun isCurrentAccountUser(user: SearchUser): Boolean {
        val candidatePublicKey = user.publicKey.trim()
        val normalizedAccountPublicKey = accountPublicKey.trim()
        if (
                candidatePublicKey.isNotBlank() &&
                        normalizedAccountPublicKey.isNotBlank() &&
                        candidatePublicKey.equals(normalizedAccountPublicKey, ignoreCase = true)
        ) {
            return true
        }

        val candidateUsername = user.username.trim().trimStart('@')
        val normalizedAccountUsername = accountUsername.trim().trimStart('@')
        return candidatePublicKey.isBlank() &&
                candidateUsername.isNotBlank() &&
                normalizedAccountUsername.isNotBlank() &&
                candidateUsername.equals(normalizedAccountUsername, ignoreCase = true)
    }
    fun popScreen() {
        navStack = navStack.dropLast(1)
    }
    fun openOwnProfile() {
        val filteredStack =
                navStack.filterNot {
                    it is Screen.ChatDetail || it is Screen.OtherProfile || it is Screen.GroupInfo
                }
        // Single state update avoids intermediate frame (chat list flash/jitter) when opening
        // profile from a mention inside chat.
        navStack =
                if (filteredStack.lastOrNull() == Screen.Profile) {
                    filteredStack
                } else {
                    filteredStack + Screen.Profile
                }
    }
    fun popProfileAndChildren() {
        navStack =
                navStack.filterNot {
                    it is Screen.Profile ||
                    it is Screen.Theme ||
                            it is Screen.Notifications ||
                            it is Screen.Safety ||
                            it is Screen.Backup ||
                            it is Screen.Logs ||
                            it is Screen.CrashLogs ||
                            it is Screen.Biometric ||
                            it is Screen.Appearance
                }
    }
    fun performProfileBack(fromChat: Boolean) {
        if (fromChat) {
            navStack = navStack.filterNot { it is Screen.ProfileFromChat }
        } else {
            popProfileAndChildren()
        }
    }
    fun requestProfileBack(fromChat: Boolean) {
        if (profileHasUnsavedChanges) {
            discardProfileChangesFromChat = fromChat
            showDiscardProfileChangesDialog = true
        } else {
            performProfileBack(fromChat)
        }
    }
    fun popChatAndChildren() {
        navStack =
                navStack.filterNot {
                    it is Screen.ChatDetail || it is Screen.OtherProfile || it is Screen.GroupInfo
                }
    }

    LaunchedEffect(isProfileVisible, isProfileFromChatVisible) {
        if (!isProfileVisible && !isProfileFromChatVisible) {
            profileHasUnsavedChanges = false
            showDiscardProfileChangesDialog = false
        }
    }

    // ProfileViewModel для логов
    val profileViewModel: com.rosetta.messenger.ui.settings.ProfileViewModel =
            androidx.hilt.navigation.compose.hiltViewModel()
    val profileState by profileViewModel.state.collectAsState()
    val chatsListViewModel: com.rosetta.messenger.ui.chats.ChatsListViewModel =
            androidx.hilt.navigation.compose.hiltViewModel()

    // Appearance: background blur color preference
    val prefsManager = preferencesManager
    val backgroundBlurColorId by
            prefsManager
                    .backgroundBlurColorIdForAccount(accountPublicKey)
                    .collectAsState(initial = "avatar")
    val chatWallpaperId by prefsManager.chatWallpaperId.collectAsState(initial = "")
    val chatWallpaperIdLight by prefsManager.chatWallpaperIdLight.collectAsState(initial = "")
    val chatWallpaperIdDark by prefsManager.chatWallpaperIdDark.collectAsState(initial = "")
    val pinnedChats by prefsManager.pinnedChats.collectAsState(initial = emptySet())

    // AvatarRepository для работы с аватарами
    val avatarRepository =
            remember(accountPublicKey) {
                if (accountPublicKey.isNotBlank()) {
                    val database = RosettaDatabase.getDatabase(context)
                    AvatarRepository(
                            context = context,
                            avatarDao = database.avatarDao(),
                            currentPublicKey = accountPublicKey
                    )
                } else {
                    null
                }
            }

    // Coroutine scope for profile updates
    val mainScreenScope = rememberCoroutineScope()

    LaunchedEffect(isDarkTheme, chatWallpaperId, chatWallpaperIdLight, chatWallpaperIdDark) {
        val targetWallpaperId =
                ThemeWallpapers.resolveWallpaperForTheme(
                        currentWallpaperId = chatWallpaperId,
                        isDarkTheme = isDarkTheme,
                        darkThemeWallpaperId = chatWallpaperIdDark,
                        lightThemeWallpaperId = chatWallpaperIdLight
                )

        if (targetWallpaperId != chatWallpaperId) {
            prefsManager.setChatWallpaperId(targetWallpaperId)
        }

        val currentThemeStored =
                if (isDarkTheme) chatWallpaperIdDark else chatWallpaperIdLight
        if (currentThemeStored != targetWallpaperId) {
            prefsManager.setChatWallpaperIdForTheme(
                    isDarkTheme = isDarkTheme,
                    value = targetWallpaperId
            )
        }
    }

    // 🔥 Простая навигация с swipe back
    Box(modifier = Modifier.fillMaxSize()) {
        // Base layer - chats list (всегда видимый, чтобы его было видно при свайпе)
        SwipeBackBackgroundEffect(modifier = Modifier.fillMaxSize(), layer = 0) {
            ChatsListScreen(
                    isDarkTheme = isDarkTheme,
                    accountName = accountName,
                    accountUsername = accountUsername,
                    accountVerified = accountVerified,
                    accountPublicKey = accountPublicKey,
                    accountPrivateKey = accountPrivateKey,
                    onToggleTheme = onToggleTheme,
                    onProfileClick = { pushScreen(Screen.Profile) },
                    onNewGroupClick = {
                        pushScreen(Screen.GroupSetup)
                    },
                    onCallsClick = {
                        // TODO: Navigate to calls
                    },
                    onSavedMessagesClick = {
                        // Открываем чат с самим собой (Saved Messages)
                        pushScreen(
                                Screen.ChatDetail(
                                        SearchUser(
                                                title = "Saved Messages",
                                                username = "",
                                                publicKey = accountPublicKey,
                                                verified = 0,
                                                online = 1
                                        )
                                )
                        )
                    },
                    onSettingsClick = { pushScreen(Screen.Profile) },
                    onSearchClick = { pushScreen(Screen.Search) },
                    onRequestsClick = { pushScreen(Screen.Requests) },
                    onNewChat = {
                        // TODO: Show new chat screen
                    },
                    onUserSelect = { selectedChatUser ->
                        pushScreen(Screen.ChatDetail(selectedChatUser))
                    },
                    onStartCall = { user ->
                        startCallWithPermission(user)
                    },
                    pinnedChats = pinnedChats,
                    onTogglePin = { opponentKey ->
                        mainScreenScope.launch { prefsManager.togglePinChat(opponentKey) }
                    },
                    protocolGateway = protocolGateway,
                    accountManager = accountManager,
                    preferencesManager = prefsManager,
                    chatsViewModel = chatsListViewModel,
                    avatarRepository = avatarRepository,
                    callUiState = callUiState,
                    isCallOverlayExpanded = isCallOverlayExpanded,
                    onOpenCallOverlay = { isCallOverlayExpanded = true },
                    onAddAccount = {
                        onAddAccount()
                    },
                    onSwitchAccount = onSwitchAccount,
                    onDeleteAccountFromSidebar = onDeleteAccountFromSidebar,
                    onQrScanClick = { pushScreen(Screen.QrScanner) },
                    onMyQrClick = { pushScreen(Screen.MyQr) }
            )
        }

        SwipeBackContainer(
                isVisible = isRequestsVisible,
                onBack = { navStack = navStack.filterNot { it is Screen.Requests } },
                isDarkTheme = isDarkTheme,
                layer = 1
        ) {
                RequestsListScreen(
                    isDarkTheme = isDarkTheme,
                    chatsViewModel = chatsListViewModel,
                    pinnedChats = pinnedChats,
                    onTogglePin = { opponentKey ->
                        mainScreenScope.launch {
                            prefsManager.togglePinChat(opponentKey)
                        }
                    },
                    onBack = { navStack = navStack.filterNot { it is Screen.Requests } },
                    onUserSelect = { selectedRequestUser ->
                        navStack =
                            navStack.filterNot {
                                it is Screen.ChatDetail || it is Screen.OtherProfile
                            } + Screen.ChatDetail(selectedRequestUser)
                    },
                    avatarRepository = avatarRepository
                )
        }

        // ═══════════════════════════════════════════════════════════
        // Profile Screen — MUST be before sub-screens so it stays
        // visible beneath them during swipe-back animation
        // ═══════════════════════════════════════════════════════════
        SwipeBackContainer(
                isVisible = isProfileVisible,
                onBack = { requestProfileBack(fromChat = false) },
                isDarkTheme = isDarkTheme,
                layer = 1,
                swipeEnabled = !profileHasUnsavedChanges,
                propagateBackgroundProgress = false
        ) {
            // Экран профиля
            ProfileScreen(
                    isDarkTheme = isDarkTheme,
                    accountName = accountName,
                    accountUsername = accountUsername,
                    accountVerified = accountVerified,
                    accountPublicKey = accountPublicKey,
                    accountPrivateKeyHash = privateKeyHash,
                    onBack = { requestProfileBack(fromChat = false) },
                    onHasChangesChanged = { profileHasUnsavedChanges = it },
                    onSaveProfile = { name, username ->
                        accountName = name
                        accountUsername = username
                        mainScreenScope.launch { onAccountInfoUpdated() }
                    },
                    onLogout = onLogout,
                    onNavigateToNotifications = { pushScreen(Screen.Notifications) },
                    onNavigateToTheme = { pushScreen(Screen.Theme) },
                    onNavigateToAppearance = { pushScreen(Screen.Appearance) },
                    onNavigateToSafety = { pushScreen(Screen.Safety) },
                    onNavigateToLogs = { pushScreen(Screen.Logs) },
                    onNavigateToBiometric = { pushScreen(Screen.Biometric) },
                    onNavigateToMyQr = { pushScreen(Screen.MyQr) },
                    viewModel = profileViewModel,
                    avatarRepository = avatarRepository,
                    dialogDao = RosettaDatabase.getDatabase(context).dialogDao(),
                    backgroundBlurColorId = backgroundBlurColorId
            )
        }

        // Other screens with swipe back
        SwipeBackContainer(
                isVisible = isNotificationsVisible,
                onBack = { navStack = navStack.filterNot { it is Screen.Notifications } },
                isDarkTheme = isDarkTheme,
                layer = 2
        ) {
            NotificationsScreen(
                    isDarkTheme = isDarkTheme,
                    preferencesManager = prefsManager,
                    onBack = { navStack = navStack.filterNot { it is Screen.Notifications } }
            )
        }

        SwipeBackContainer(
                isVisible = isSafetyVisible,
                onBack = { navStack = navStack.filterNot { it is Screen.Safety } },
                isDarkTheme = isDarkTheme,
                layer = 2
        ) {
            SafetyScreen(
                    isDarkTheme = isDarkTheme,
                    accountPublicKey = accountPublicKey,
                    accountPrivateKey = accountPrivateKey,
                    onBack = { navStack = navStack.filterNot { it is Screen.Safety } },
                    onBackupClick = {
                        navStack = navStack + Screen.Backup
                    },
                    onDeleteAccount = onDeleteAccount
            )
        }

        SwipeBackContainer(
                isVisible = isBackupVisible,
                onBack = { navStack = navStack.filterNot { it is Screen.Backup } },
                isDarkTheme = isDarkTheme,
                layer = 3
        ) {
            BackupScreen(
                    isDarkTheme = isDarkTheme,
                    onBack = {
                        navStack = navStack.filterNot { it is Screen.Backup }
                    },
                    onVerifyPassword = { password ->
                        // Verify password by trying to decrypt the private key
                        try {
                            val publicKey = account?.publicKey ?: return@BackupScreen null
                            val encryptedAccount = accountManager.getAccount(publicKey)

                            if (encryptedAccount != null) {
                                // Try to decrypt private key with password
                                val decryptedPrivateKey =
                                        com.rosetta.messenger.crypto.CryptoManager
                                                .decryptWithPassword(
                                                        encryptedAccount.encryptedPrivateKey,
                                                        password
                                                )

                                if (decryptedPrivateKey != null) {
                                    // Password is correct, decrypt seed phrase
                                    com.rosetta.messenger.crypto.CryptoManager.decryptWithPassword(
                                            encryptedAccount.encryptedSeedPhrase,
                                            password
                                    )
                                } else {
                                    null
                                }
                            } else {
                                null
                            }
                        } catch (e: Exception) {
                            null
                        }
                    }
            )
        }

        SwipeBackContainer(
                isVisible = isThemeVisible,
                onBack = { navStack = navStack.filterNot { it is Screen.Theme } },
                isDarkTheme = isDarkTheme,
                layer = 2,
                deferToChildren = true
        ) {
            ThemeScreen(
                    isDarkTheme = isDarkTheme,
                    currentThemeMode = themeMode,
                    currentWallpaperId = chatWallpaperId,
                    onBack = { navStack = navStack.filterNot { it is Screen.Theme } },
                    onThemeModeChange = onThemeModeChange,
                    onWallpaperChange = { wallpaperId ->
                        mainScreenScope.launch {
                            prefsManager.setChatWallpaperIdForTheme(
                                    isDarkTheme = isDarkTheme,
                                    value = wallpaperId
                            )
                            prefsManager.setChatWallpaperId(wallpaperId)
                        }
                    }
            )
        }

        SwipeBackContainer(
                isVisible = isAppearanceVisible,
                onBack = { navStack = navStack.filterNot { it is Screen.Appearance } },
                isDarkTheme = isDarkTheme,
                layer = 2
        ) {
            com.rosetta.messenger.ui.settings.AppearanceScreen(
                    isDarkTheme = isDarkTheme,
                    currentBlurColorId = backgroundBlurColorId,
                    onBack = { navStack = navStack.filterNot { it is Screen.Appearance } },
                    onBlurColorChange = { newId ->
                        mainScreenScope.launch {
                            prefsManager.setBackgroundBlurColorId(accountPublicKey, newId)
                        }
                    },
                    onToggleTheme = onToggleTheme,
                    onAppIconClick = { navStack = navStack + Screen.AppIcon },
                    accountPublicKey = accountPublicKey,
                    accountName = accountName,
                    avatarRepository = avatarRepository
            )
        }

        SwipeBackContainer(
                isVisible = isAppIconVisible,
                onBack = { navStack = navStack.filterNot { it is Screen.AppIcon } },
                isDarkTheme = isDarkTheme,
                layer = 3
        ) {
            com.rosetta.messenger.ui.settings.AppIconScreen(
                    isDarkTheme = isDarkTheme,
                    preferencesManager = prefsManager,
                    onBack = { navStack = navStack.filterNot { it is Screen.AppIcon } }
            )
        }

        SwipeBackContainer(
                isVisible = isUpdatesVisible,
                onBack = { navStack = navStack.filterNot { it is Screen.Updates } },
                isDarkTheme = isDarkTheme,
                layer = 2
        ) {
            UpdatesScreen(
                    isDarkTheme = isDarkTheme,
                    onBack = { navStack = navStack.filterNot { it is Screen.Updates } }
            )
        }

        // 🔒 Lock swipe-back while chat overlays are open (image viewer/editor/media picker/camera).
        var isChatSwipeLocked by remember { mutableStateOf(false) }
        var isChatVoiceWaveGestureLocked by remember { mutableStateOf(false) }

        // 🔴 Badge: total unread from OTHER chats (excluding current) for back-chevron badge
        val totalUnreadFromOthers by remember(accountPublicKey, selectedUser?.publicKey) {
            val db = RosettaDatabase.getDatabase(context)
            val opponentKey = selectedUser?.publicKey ?: ""
            if (accountPublicKey.isNotBlank() && opponentKey.isNotBlank()) {
                db.dialogDao().getTotalUnreadCountExcludingFlow(accountPublicKey, opponentKey)
            } else {
                kotlinx.coroutines.flow.flowOf(0)
            }
        }.collectAsState(initial = 0)

        var chatSelectionActive by remember { mutableStateOf(false) }
        val chatClearSelectionRef = remember { mutableStateOf<() -> Unit>({}) }
        LaunchedEffect(selectedUser?.publicKey) {
                isChatVoiceWaveGestureLocked = false
        }

        SwipeBackContainer(
                isVisible = selectedUser != null,
                onBack = { popChatAndChildren() },
                onInterceptSwipeBack = {
                    if (chatSelectionActive) {
                        chatClearSelectionRef.value()
                        true
                    } else false
                },
                isDarkTheme = isDarkTheme,
                layer = 1,
                swipeEnabled = !(isChatSwipeLocked || isChatVoiceWaveGestureLocked),
                enterAnimation = SwipeBackEnterAnimation.SlideFromRight,
                propagateBackgroundProgress = false
        ) {
            selectedUser?.let { currentChatUser ->
                // Экран чата
                ChatDetailScreen(
                        user = currentChatUser,
                        protocolGateway = protocolGateway,
                        preferencesManager = prefsManager,
                        messageRepository = messageRepository,
                        groupRepository = groupRepository,
                        currentUserPublicKey = accountPublicKey,
                        currentUserPrivateKey = accountPrivateKey,
                        currentUserName = accountName,
                        currentUserUsername = accountUsername,
                        totalUnreadFromOthers = totalUnreadFromOthers,
                        onBack = { popChatAndChildren() },
                        onCallClick = { callableUser ->
                            startCallWithPermission(callableUser)
                        },
                        onUserProfileClick = { user ->
                            if (isCurrentAccountUser(user)) {
                                // Свой профиль из чата открываем поверх текущего чата,
                                // чтобы возврат оставался в этот чат, а не в chat list.
                                pushScreen(Screen.ProfileFromChat)
                            } else {
                                // Открываем профиль другого пользователя
                                pushScreen(Screen.OtherProfile(user))
                            }
                        },
                        onGroupInfoClick = { groupUser ->
                            pushScreen(Screen.GroupInfo(groupUser))
                        },
                        onNavigateToChat = { forwardUser ->
                            // 📨 Forward: переход в выбранный чат с полными данными
                            navStack =
                                    navStack.filterNot {
                                        it is Screen.ChatDetail || it is Screen.OtherProfile
                                    } + Screen.ChatDetail(forwardUser)
                        },
                        isDarkTheme = isDarkTheme,
                        chatWallpaperId = chatWallpaperId,
                        avatarRepository = avatarRepository,
                        onImageViewerChanged = { isLocked -> isChatSwipeLocked = isLocked },
                        isCallActive = callUiState.isVisible,
                        onOpenCallOverlay = { isCallOverlayExpanded = true },
                        onSelectionModeChange = { chatSelectionActive = it },
                        registerClearSelection = { fn -> chatClearSelectionRef.value = fn },
                        onVoiceWaveGestureChanged = { locked ->
                                isChatVoiceWaveGestureLocked = locked
                        }
                )
            }
        }

        SwipeBackContainer(
                isVisible = isProfileFromChatVisible,
                onBack = { requestProfileBack(fromChat = true) },
                isDarkTheme = isDarkTheme,
                layer = 1,
                swipeEnabled = !profileHasUnsavedChanges,
                propagateBackgroundProgress = false
        ) {
            ProfileScreen(
                    isDarkTheme = isDarkTheme,
                    accountName = accountName,
                    accountUsername = accountUsername,
                    accountVerified = accountVerified,
                    accountPublicKey = accountPublicKey,
                    accountPrivateKeyHash = privateKeyHash,
                    onBack = { requestProfileBack(fromChat = true) },
                    onHasChangesChanged = { profileHasUnsavedChanges = it },
                    onSaveProfile = { name, username ->
                        accountName = name
                        accountUsername = username
                        mainScreenScope.launch { onAccountInfoUpdated() }
                    },
                    onLogout = onLogout,
                    onNavigateToNotifications = { pushScreen(Screen.Notifications) },
                    onNavigateToTheme = { pushScreen(Screen.Theme) },
                    onNavigateToAppearance = { pushScreen(Screen.Appearance) },
                    onNavigateToSafety = { pushScreen(Screen.Safety) },
                    onNavigateToLogs = { pushScreen(Screen.Logs) },
                    onNavigateToBiometric = { pushScreen(Screen.Biometric) },
                    onNavigateToMyQr = { pushScreen(Screen.MyQr) },
                    viewModel = profileViewModel,
                    avatarRepository = avatarRepository,
                    dialogDao = RosettaDatabase.getDatabase(context).dialogDao(),
                    backgroundBlurColorId = backgroundBlurColorId
            )
        }

        var isGroupInfoSwipeEnabled by remember { mutableStateOf(true) }
        LaunchedEffect(selectedGroup?.publicKey) {
            isGroupInfoSwipeEnabled = true
        }

        SwipeBackContainer(
                isVisible = selectedGroup != null,
                onBack = { navStack = navStack.filterNot { it is Screen.GroupInfo } },
                isDarkTheme = isDarkTheme,
                layer = 2,
                swipeEnabled = isGroupInfoSwipeEnabled,
                propagateBackgroundProgress = false
        ) {
            selectedGroup?.let { groupUser ->
                GroupInfoScreen(
                        groupUser = groupUser,
                        currentUserPublicKey = accountPublicKey,
                        currentUserPrivateKey = accountPrivateKey,
                        isDarkTheme = isDarkTheme,
                        protocolGateway = protocolGateway,
                        messageRepository = messageRepository,
                        preferencesManager = prefsManager,
                        groupRepository = groupRepository,
                        avatarRepository = avatarRepository,
                        onBack = { navStack = navStack.filterNot { it is Screen.GroupInfo } },
                        onMemberClick = { member ->
                            if (isCurrentAccountUser(member)) {
                                openOwnProfile()
                            } else {
                                pushScreen(Screen.OtherProfile(member))
                            }
                        },
                        onSwipeBackEnabledChanged = { enabled ->
                            isGroupInfoSwipeEnabled = enabled
                        },
                        onGroupLeft = {
                            navStack =
                                    navStack.filterNot {
                                        it is Screen.GroupInfo ||
                                                (it is Screen.ChatDetail &&
                                                        it.user.publicKey == groupUser.publicKey)
                                    }
                        }
                )
            }
        }

        SwipeBackContainer(
                isVisible = isSearchVisible,
                onBack = { navStack = navStack.filterNot { it is Screen.Search } },
                isDarkTheme = isDarkTheme,
                layer = 1
        ) {
            // Экран поиска
            SearchScreen(
                    privateKeyHash = privateKeyHash,
                    currentUserPublicKey = accountPublicKey,
                    accountManager = accountManager,
                    messageRepository = messageRepository,
                    isDarkTheme = isDarkTheme,
                    protocolState = protocolState,
                    onBackClick = { navStack = navStack.filterNot { it is Screen.Search } },
                    onUserSelect = { selectedSearchUser ->
                        navStack =
                                navStack.filterNot { it is Screen.Search } +
                                        Screen.ChatDetail(selectedSearchUser)
                    },
                    onNavigateToCrashLogs = {
                        navStack = navStack.filterNot { it is Screen.Search } + Screen.CrashLogs
                    },
                    onNavigateToConnectionLogs = {
                        navStack =
                                navStack.filterNot { it is Screen.Search } +
                                        Screen.ConnectionLogs
                    }
            )
        }

        SwipeBackContainer(
                isVisible = isGroupSetupVisible,
                onBack = { navStack = navStack.filterNot { it is Screen.GroupSetup } },
                isDarkTheme = isDarkTheme,
                layer = 1
        ) {
            GroupSetupScreen(
                    isDarkTheme = isDarkTheme,
                    accountPublicKey = accountPublicKey,
                    accountPrivateKey = accountPrivateKey,
                    accountName = accountName,
                    accountUsername = accountUsername,
                    messageRepository = messageRepository,
                    groupRepository = groupRepository,
                    avatarRepository = avatarRepository,
                    dialogDao = RosettaDatabase.getDatabase(context).dialogDao(),
                    onBack = { navStack = navStack.filterNot { it is Screen.GroupSetup } },
                    onGroupOpened = { groupUser ->
                        navStack =
                                navStack.filterNot { it is Screen.GroupSetup } +
                                        Screen.ChatDetail(groupUser)
                    }
            )
        }

        SwipeBackContainer(
                isVisible = isLogsVisible,
                onBack = { navStack = navStack.filterNot { it is Screen.Logs } },
                isDarkTheme = isDarkTheme,
                layer = 2
        ) {
            com.rosetta.messenger.ui.settings.ProfileLogsScreen(
                    isDarkTheme = isDarkTheme,
                    logs = profileState.logs,
                    onBack = { navStack = navStack.filterNot { it is Screen.Logs } },
                    onClearLogs = { profileViewModel.clearLogs() }
            )
        }

        SwipeBackContainer(
                isVisible = isCrashLogsVisible,
                onBack = { navStack = navStack.filterNot { it is Screen.CrashLogs } },
                isDarkTheme = isDarkTheme,
                layer = 1
        ) {
            CrashLogsScreen(
                    onBackClick = { navStack = navStack.filterNot { it is Screen.CrashLogs } }
            )
        }

        SwipeBackContainer(
                isVisible = isConnectionLogsVisible,
                onBack = { navStack = navStack.filterNot { it is Screen.ConnectionLogs } },
                isDarkTheme = isDarkTheme,
                layer = 1
        ) {
            ConnectionLogsScreen(
                    isDarkTheme = isDarkTheme,
                    protocolGateway = protocolGateway,
                    onBack = { navStack = navStack.filterNot { it is Screen.ConnectionLogs } }
            )
        }

        var isOtherProfileSwipeEnabled by remember { mutableStateOf(true) }
        LaunchedEffect(selectedOtherUser?.publicKey) {
            isOtherProfileSwipeEnabled = true
        }

        SwipeBackContainer(
                isVisible = selectedOtherUser != null,
                onBack = { navStack = navStack.filterNot { it is Screen.OtherProfile } },
                isDarkTheme = isDarkTheme,
                layer = 2,
                swipeEnabled = isOtherProfileSwipeEnabled,
                propagateBackgroundProgress = false
        ) {
            selectedOtherUser?.let { currentOtherUser ->
                OtherProfileScreen(
                        user = currentOtherUser,
                        isDarkTheme = isDarkTheme,
                        preferencesManager = prefsManager,
                        messageRepository = messageRepository,
                        onBack = { navStack = navStack.filterNot { it is Screen.OtherProfile } },
                        onSwipeBackEnabledChanged = { enabled ->
                            isOtherProfileSwipeEnabled = enabled
                        },
                        avatarRepository = avatarRepository,
                        currentUserPublicKey = accountPublicKey,
                        currentUserPrivateKey = accountPrivateKey,
                        onWriteMessage = { chatUser ->
                            // Close profile and navigate to chat
                            navStack = navStack.filterNot {
                                it is Screen.OtherProfile || it is Screen.ChatDetail
                            } + Screen.ChatDetail(chatUser)
                        },
                        onCall = { callableUser ->
                            startCallWithPermission(callableUser)
                        }
                )
            }
        }

        // Biometric Enable Screen
        SwipeBackContainer(
                isVisible = isBiometricVisible,
                onBack = { navStack = navStack.filterNot { it is Screen.Biometric } },
                isDarkTheme = isDarkTheme,
                layer = 2
        ) {
            val biometricManager = remember {
                com.rosetta.messenger.biometric.BiometricAuthManager(context)
            }
            val biometricPrefs = remember {
                com.rosetta.messenger.biometric.BiometricPreferences(context)
            }
            val activity = context as? FragmentActivity
            val isFingerprintSupported = remember {
                biometricManager.isFingerprintHardwareAvailable()
            }

            if (!isFingerprintSupported) {
                LaunchedEffect(Unit) {
                    navStack = navStack.filterNot { it is Screen.Biometric }
                }
                return@SwipeBackContainer
            }

            BiometricEnableScreen(
                    isDarkTheme = isDarkTheme,
                    onBack = { navStack = navStack.filterNot { it is Screen.Biometric } },
                    onEnable = { password, onSuccess, onError ->
                        if (activity == null) {
                            onError("Activity not available")
                            return@BiometricEnableScreen
                        }

                        // Verify password against the real account before saving
                        mainScreenScope.launch {
                            val account = accountManager.getAccount(accountPublicKey)
                            if (account == null) {
                                onError("Account not found")
                                return@launch
                            }
                            val decryptedKey = try {
                                CryptoManager.decryptWithPassword(account.encryptedPrivateKey, password)
                            } catch (_: Exception) { null }
                            if (decryptedKey == null) {
                                onError("Incorrect password")
                                return@launch
                            }

                            biometricManager.encryptPassword(
                                    activity = activity,
                                    password = password,
                                    onSuccess = { encryptedPassword ->
                                        mainScreenScope.launch {
                                            biometricPrefs.saveEncryptedPassword(
                                                    accountPublicKey,
                                                    encryptedPassword
                                            )
                                            biometricPrefs.enableBiometric(accountPublicKey)
                                            onSuccess()
                                        }
                                    },
                                    onError = { error -> onError(error) },
                                    onCancel = {
                                        navStack = navStack.filterNot { it is Screen.Biometric }
                                    }
                            )
                        }
                    }
            )
        }

        // QR Scanner
        SwipeBackContainer(
                isVisible = isQrScannerVisible,
                onBack = { navStack = navStack.filterNot { it is Screen.QrScanner } },
                isDarkTheme = isDarkTheme,
                layer = 3
        ) {
            com.rosetta.messenger.ui.qr.QrScannerScreen(
                onBack = { navStack = navStack.filterNot { it is Screen.QrScanner } },
                onResult = { result ->
                    navStack = navStack.filterNot { it is Screen.QrScanner }
                    when (result.type) {
                        com.rosetta.messenger.ui.qr.QrResultType.PROFILE -> {
                            mainScreenScope.launch {
                                val users = protocolGateway.searchUsers(result.payload, 5000)
                                val user = users.firstOrNull()
                                if (user != null) {
                                    pushScreen(Screen.OtherProfile(user))
                                } else {
                                    val searchUser = com.rosetta.messenger.network.SearchUser(
                                        publicKey = result.payload,
                                        title = "", username = "", verified = 0, online = 0
                                    )
                                    pushScreen(Screen.ChatDetail(searchUser))
                                }
                            }
                        }
                        com.rosetta.messenger.ui.qr.QrResultType.GROUP -> {
                            mainScreenScope.launch {
                                val joinResult =
                                    groupRepository.joinGroup(accountPublicKey, accountPrivateKey, result.payload)
                                if (joinResult.success && !joinResult.dialogPublicKey.isNullOrBlank()) {
                                    val groupUser = com.rosetta.messenger.network.SearchUser(
                                        publicKey = joinResult.dialogPublicKey,
                                        title = joinResult.title.ifBlank { "Group" },
                                        username = "", verified = 0, online = 0
                                    )
                                    pushScreen(Screen.ChatDetail(groupUser))
                                }
                            }
                        }
                        else -> {}
                    }
                }
            )
        }

        // My QR Code
        SwipeBackContainer(
                isVisible = isMyQrVisible,
                onBack = { navStack = navStack.filterNot { it is Screen.MyQr } },
                isDarkTheme = isDarkTheme,
                layer = 2
        ) {
            com.rosetta.messenger.ui.qr.MyQrCodeScreen(
                isDarkTheme = isDarkTheme,
                publicKey = accountPublicKey,
                displayName = accountName,
                username = accountUsername,
                avatarRepository = avatarRepository,
                onBack = { navStack = navStack.filterNot { it is Screen.MyQr } },
                onScanQr = {
                    navStack = navStack.filterNot { it is Screen.MyQr }
                    pushScreen(Screen.QrScanner)
                },
                onToggleTheme = onToggleTheme
            )
        }

        if (isCallScreenVisible) {
            // Блокируем любой ввод по нижележащим экранам, пока открыт полноэкранный CallOverlay.
            // Иначе тапы могут "пробивать" в чат (иконка звонка, kebab, input и т.д.).
            val blockerInteraction = remember { MutableInteractionSource() }
            Box(
                modifier = Modifier
                    .fillMaxSize()
                    .clickable(
                        interactionSource = blockerInteraction,
                        indication = null,
                        onClick = {}
                    )
            )
        }

        CallOverlay(
            state = callUiState,
            isDarkTheme = isDarkTheme,
            avatarRepository = avatarRepository,
            isExpanded = isCallOverlayExpanded || callUiState.phase == CallPhase.INCOMING,
            onAccept = { acceptCallWithPermission() },
            onDecline = { CallManager.declineIncomingCall() },
            onEnd = { CallManager.endCall() },
            onToggleMute = { CallManager.toggleMute() },
            onToggleSpeaker = { CallManager.toggleSpeaker() },
            onMinimize = {
                if (callUiState.phase != CallPhase.INCOMING) {
                    isCallOverlayExpanded = false
                }
            }
        )

        if (showDiscardProfileChangesDialog) {
            AlertDialog(
                onDismissRequest = { showDiscardProfileChangesDialog = false },
                containerColor = if (isDarkTheme) Color(0xFF1E1E20) else Color.White,
                title = {
                    Text(
                        text = "Discard changes?",
                        color = if (isDarkTheme) Color.White else Color.Black
                    )
                },
                text = {
                    Text(
                        text = "You have unsaved profile changes. If you leave now, they will be lost.",
                        color = if (isDarkTheme) Color(0xFFB5B5BC) else Color(0xFF5A5A66)
                    )
                },
                confirmButton = {
                    TextButton(
                        onClick = {
                            showDiscardProfileChangesDialog = false
                            profileHasUnsavedChanges = false
                            performProfileBack(discardProfileChangesFromChat)
                        }
                    ) {
                        Text("Discard", color = Color(0xFFFF3B30))
                    }
                },
                dismissButton = {
                    TextButton(onClick = { showDiscardProfileChangesDialog = false }) {
                        Text(
                            "Stay",
                            color = if (isDarkTheme) Color(0xFF5FA8FF) else Color(0xFF0D8CF4)
                        )
                    }
                }
            )
        }
    }
}
