package com.rosetta.messenger.ui.settings

import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.net.Uri
import androidx.activity.compose.BackHandler
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import android.util.Log
import androidx.compose.animation.*
import androidx.compose.animation.core.*
import androidx.compose.foundation.*
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.gestures.animateScrollBy
import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.asPaddingValues
import androidx.compose.foundation.layout.statusBars
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.BasicTextField
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.clipToBounds
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
import androidx.compose.ui.input.nestedscroll.NestedScrollSource
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalHapticFeedback
import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.Velocity
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import kotlinx.coroutines.launch
import androidx.fragment.app.FragmentActivity
import androidx.palette.graphics.Palette as AndroidPalette
import com.rosetta.messenger.biometric.BiometricAuthManager
import com.rosetta.messenger.biometric.BiometricAvailability
import com.rosetta.messenger.biometric.BiometricPreferences
import com.rosetta.messenger.data.MessageRepository
import com.rosetta.messenger.repository.AvatarRepository
import com.rosetta.messenger.ui.components.BlurredAvatarBackground
import com.rosetta.messenger.ui.components.VerifiedBadge

import com.rosetta.messenger.ui.onboarding.PrimaryBlue
import com.rosetta.messenger.ui.onboarding.PrimaryBlueDark

import com.rosetta.messenger.utils.AvatarFileManager
import androidx.compose.ui.graphics.Brush
import androidx.compose.foundation.gestures.detectVerticalDragGestures
import androidx.compose.ui.input.pointer.pointerInput
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
import com.rosetta.messenger.utils.ImageCropHelper
import compose.icons.TablerIcons
import compose.icons.tablericons.*
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.res.painterResource
import com.rosetta.messenger.R
import com.rosetta.messenger.ui.icons.TelegramIcons
import androidx.compose.ui.graphics.vector.rememberVectorPainter
import androidx.hilt.navigation.compose.hiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext

private const val TAG = "ProfileScreen"
private const val PROFILE_NAME_MAX_LENGTH = 40
private const val PROFILE_USERNAME_MIN_LENGTH = 5
private const val PROFILE_USERNAME_MAX_LENGTH = 32

private val PROFILE_NAME_ALLOWED_REGEX = Regex("^[\\p{L}\\p{N} ._'-]+\$")
private val PROFILE_USERNAME_ALLOWED_REGEX = Regex("^[A-Za-z0-9_]+\$")
private val PROFILE_ERROR_CODE_REGEX = Regex("error code:\\s*(\\d+)", RegexOption.IGNORE_CASE)

private data class ProfileSaveErrorUi(
        val toastMessage: String,
        val nameError: String? = null,
        val usernameError: String? = null,
        val generalMessage: String? = null
)

private fun mapProfileSaveError(rawError: String): ProfileSaveErrorUi {
    val errorCode = PROFILE_ERROR_CODE_REGEX.find(rawError)?.groupValues?.getOrNull(1)?.toIntOrNull()

    return when {
        errorCode == 3 ->
                ProfileSaveErrorUi(
                        toastMessage = "Username is unavailable. Try another one.",
                        usernameError = "Username is unavailable or invalid",
                        generalMessage = "Could not save profile: username is unavailable."
                )
        rawError.contains("timeout", ignoreCase = true) ->
                ProfileSaveErrorUi(
                        toastMessage = "Server timeout. Please try again.",
                        generalMessage = "Server timeout. Check connection and try again."
                )
        rawError.contains("network", ignoreCase = true) ->
                ProfileSaveErrorUi(
                        toastMessage = "Network error. Please try again.",
                        generalMessage = "Network error while saving profile."
                )
        else ->
                ProfileSaveErrorUi(
                        toastMessage = "Error: $rawError",
                        generalMessage = "Could not save profile. Please try again."
                )
    }
}

private fun validateProfileName(name: String): String? {
    if (name.isBlank()) return "Name can't be empty"
    if (name.length > PROFILE_NAME_MAX_LENGTH) {
        return "Name is too long (max $PROFILE_NAME_MAX_LENGTH)"
    }
    if (!PROFILE_NAME_ALLOWED_REGEX.matches(name)) {
        return "Only letters, numbers, spaces, . _ - ' are allowed"
    }
    return null
}

private fun validateProfileUsername(username: String): String? {
    if (username.isBlank()) return null // optional field
    if (username.length < PROFILE_USERNAME_MIN_LENGTH) {
        return "Username must be at least $PROFILE_USERNAME_MIN_LENGTH characters"
    }
    if (username.length > PROFILE_USERNAME_MAX_LENGTH) {
        return "Username is too long (max $PROFILE_USERNAME_MAX_LENGTH)"
    }
    if (!PROFILE_USERNAME_ALLOWED_REGEX.matches(username)) {
        return "Use only letters, numbers, and underscore"
    }
    return null
}

// 🎨 Avatar colors - используем те же цвета что и в ChatsListScreen
private val avatarColorsLight =
        listOf(
                Color(0xFF1971c2) to Color(0xFFd0ebff), // blue
                Color(0xFF0c8599) to Color(0xFFc5f6fa), // cyan
                Color(0xFF9c36b5) to Color(0xFFeebefa), // grape
                Color(0xFF2f9e44) to Color(0xFFd3f9d8), // green
                Color(0xFF4263eb) to Color(0xFFdbe4ff), // indigo
                Color(0xFF5c940d) to Color(0xFFe9fac8), // lime
                Color(0xFFd9480f) to Color(0xFFffe8cc), // orange
                Color(0xFFc2255c) to Color(0xFFffdeeb), // pink
                Color(0xFFe03131) to Color(0xFFffe0e0), // red
                Color(0xFF099268) to Color(0xFFc3fae8), // teal
                Color(0xFF6741d9) to Color(0xFFe5dbff) // violet
        )

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

data class AvatarColors(val textColor: Color, val backgroundColor: Color)

private val avatarColorCache = mutableMapOf<String, AvatarColors>()

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

/**
 * Вычисляет средний цвет bitmap (для случаев когда Palette не может извлечь swatch)
 * Используется для белых/чёрных/однотонных изображений
 */
private fun calculateAverageColor(bitmap: android.graphics.Bitmap): Color {
    var redSum = 0L
    var greenSum = 0L
    var blueSum = 0L
    val width = bitmap.width
    val height = bitmap.height
    val pixelCount = width * height
    
    // Сэмплируем каждый 4-й пиксель для производительности
    val step = 4
    var sampledCount = 0
    
    for (y in 0 until height step step) {
        for (x in 0 until width step step) {
            val pixel = bitmap.getPixel(x, y)
            redSum += android.graphics.Color.red(pixel)
            greenSum += android.graphics.Color.green(pixel)
            blueSum += android.graphics.Color.blue(pixel)
            sampledCount++
        }
    }
    
    if (sampledCount == 0) return Color.White
    
    return Color(
        red = (redSum / sampledCount) / 255f,
        green = (greenSum / sampledCount) / 255f,
        blue = (blueSum / sampledCount) / 255f
    )
}

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

fun getInitials(name: String): String {
    if (name.isBlank()) return "?"
    val parts = name.trim().split(" ").filter { it.isNotEmpty() }
    return when {
        parts.isEmpty() -> "?"
        parts.size == 1 -> parts[0].take(2).uppercase()
        else -> (parts[0].first().toString() + parts[1].first().toString()).uppercase()
    }
}

// ═════════════════════════════════════════════════════════════
// 🎯 COLLAPSING HEADER CONSTANTS
// ═════════════════════════════════════════════════════════════
private val EXPANDED_HEADER_HEIGHT = 280.dp
private val COLLAPSED_HEADER_HEIGHT = 64.dp // Increased for more bottom space
private val AVATAR_SIZE_EXPANDED = 120.dp
private val AVATAR_SIZE_COLLAPSED = 36.dp
private val STATUS_BAR_HEIGHT = 24.dp

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun ProfileScreen(
        isDarkTheme: Boolean,
        accountName: String,
        accountUsername: String,
        accountVerified: Int = 0,
        accountPublicKey: String,
        accountPrivateKeyHash: String,
        onBack: () -> Unit,
        onHasChangesChanged: (Boolean) -> Unit = {},
        onSaveProfile: (name: String, username: String) -> Unit,
        onLogout: () -> Unit,
        onNavigateToNotifications: () -> Unit = {},
        onNavigateToTheme: () -> Unit = {},
        onNavigateToAppearance: () -> Unit = {},
        onNavigateToSafety: () -> Unit = {},
        onNavigateToLogs: () -> Unit = {},
        onNavigateToBiometric: () -> Unit = {},
        onNavigateToMyQr: () -> Unit = {},
        viewModel: ProfileViewModel = hiltViewModel(),
        avatarRepository: AvatarRepository? = null,
        dialogDao: com.rosetta.messenger.database.DialogDao? = null,
        backgroundBlurColorId: String = "avatar"
) {
    val view = LocalView.current
    if (!view.isInEditMode) {
        DisposableEffect(isDarkTheme) {
            val window = (view.context as android.app.Activity).window
            val insetsController = androidx.core.view.WindowCompat.getInsetsController(window, view)
            val prev = insetsController.isAppearanceLightStatusBars
            insetsController.isAppearanceLightStatusBars = !isDarkTheme
            window.statusBarColor = android.graphics.Color.TRANSPARENT
            onDispose { insetsController.isAppearanceLightStatusBars = prev }
        }
    }

    val context = LocalContext.current
    val activity = context as? FragmentActivity
    val biometricManager = remember { BiometricAuthManager(context) }
    val scope = rememberCoroutineScope()

    // Biometric availability
    var biometricAvailable by remember {
        mutableStateOf<BiometricAvailability>(BiometricAvailability.NotAvailable("Checking..."))
    }

    // Biometric enabled state - per account
    val biometricPrefs = remember { BiometricPreferences(context) }
    LaunchedEffect(accountPublicKey) {
        biometricPrefs.loadForAccount(accountPublicKey)
    }
    val isBiometricEnabled by biometricPrefs.isBiometricEnabled.collectAsState(initial = false)

    // Check biometric availability
    LaunchedEffect(Unit) {
        biometricAvailable = biometricManager.isBiometricAvailable()
    }

    // Состояние меню аватара для установки фото профиля
    var showAvatarMenu by remember { mutableStateOf(false) }
    
    // 🖼️ Состояние для нашего кастомного photo picker
    var showPhotoPicker by remember { mutableStateOf(false) }

    // 🔍 Full-screen avatar viewer state
    var showAvatarViewer by remember { mutableStateOf(false) }
    var avatarViewerBitmap by remember { mutableStateOf<android.graphics.Bitmap?>(null) }
    var avatarViewerTimestamp by remember { mutableStateOf(0L) }

    // URI выбранного изображения (до crop)
    var selectedImageUri by remember { mutableStateOf<Uri?>(null) }

    // Launcher для обрезки изображения (uCrop)
    val cropLauncher =
            rememberLauncherForActivityResult(
                    contract = ActivityResultContracts.StartActivityForResult()
            ) { result ->

                val croppedUri = ImageCropHelper.getCroppedImageUri(result)
                val error = ImageCropHelper.getCropError(result)

                if (croppedUri != null) {
                    scope.launch {
                        try {
                            // Читаем обрезанное изображение
                            val inputStream = context.contentResolver.openInputStream(croppedUri)
                            val imageBytes = inputStream?.readBytes()
                            inputStream?.close()


                            if (imageBytes != null) {
                                val base64Png =
                                        withContext(Dispatchers.IO) {
                                            AvatarFileManager.imagePrepareForNetworkTransfer(
                                                    context,
                                                    imageBytes
                                            )
                                        }


                                // Сохраняем аватар через репозиторий
                                avatarRepository?.changeMyAvatar(base64Png)


                                android.widget.Toast.makeText(
                                                context,
                                                "Avatar updated successfully",
                                                android.widget.Toast.LENGTH_SHORT
                                        )
                                        .show()
                            }
                        } catch (e: Exception) {
                            android.widget.Toast.makeText(
                                            context,
                                            "Failed to update avatar: ${e.message}",
                                            android.widget.Toast.LENGTH_LONG
                                    )
                                    .show()
                        }
                    }
                } else if (error != null) {
                    android.widget.Toast.makeText(
                                    context,
                                    "Failed to crop image: ${error.message}",
                                    android.widget.Toast.LENGTH_LONG
                            )
                            .show()
                } else {
                }
            }

    // Цвета в зависимости от темы
    val backgroundColor = if (isDarkTheme) Color(0xFF1A1A1A) else Color(0xFFFFFFFF)
    val avatarColors = getAvatarColor(accountPublicKey, isDarkTheme)

    // Проверяем наличие аватара
    val avatars by
            avatarRepository?.getAvatars(accountPublicKey, allDecode = false)?.collectAsState()
                    ?: remember { mutableStateOf(emptyList()) }
    val hasAvatar = avatars.isNotEmpty()

    // State for editing - Update when account data changes
    var editedName by remember(accountName) { mutableStateOf(accountName) }
    var editedUsername by remember(accountUsername) { mutableStateOf(accountUsername) }
    val hasChanges = editedName != accountName || editedUsername != accountUsername
    var nameTouched by remember { mutableStateOf(false) }
    var usernameTouched by remember { mutableStateOf(false) }
    var showValidationErrors by remember { mutableStateOf(false) }
    var serverNameError by remember { mutableStateOf<String?>(null) }
    var serverUsernameError by remember { mutableStateOf<String?>(null) }
    var serverGeneralError by remember { mutableStateOf<String?>(null) }

    val trimmedName = editedName.trim()
    val trimmedUsername = editedUsername.trim()
    val nameValidationError =
            if (nameTouched || showValidationErrors) validateProfileName(trimmedName) else null
    val usernameValidationError =
            if (usernameTouched || showValidationErrors)
                    validateProfileUsername(trimmedUsername)
            else null
    val nameError = nameValidationError ?: serverNameError
    val usernameError = usernameValidationError ?: serverUsernameError
    val isFormValid = nameError == null && usernameError == null

    // Sync edited fields when account data changes from parent (after save)
    LaunchedEffect(accountName, accountUsername) {
        editedName = accountName
        editedUsername = accountUsername
        nameTouched = false
        usernameTouched = false
        showValidationErrors = false
        serverNameError = null
        serverUsernameError = null
        serverGeneralError = null
    }

    // ViewModel state
    val profileState by viewModel.state.collectAsState()

    // Scroll state for collapsing header + overscroll avatar expansion
    val density = LocalDensity.current
    val statusBarHeight = WindowInsets.statusBars.asPaddingValues().calculateTopPadding()
    val navigationBarHeight = WindowInsets.navigationBars.asPaddingValues().calculateBottomPadding()

    // Header heights
    val expandedHeightPx = with(density) { (EXPANDED_HEADER_HEIGHT + statusBarHeight).toPx() }
    val collapsedHeightPx = with(density) { (COLLAPSED_HEADER_HEIGHT + statusBarHeight).toPx() }
    val maxScrollOffset = expandedHeightPx - collapsedHeightPx

    // ═══════════════════════════════════════════════════════════════
    // TELEGRAM ARCHITECTURE: LazyColumn = RecyclerView
    // Item 0 = spacer высотой maxScrollOffset (ровно сколько нужно проскроллить)
    // scrollOffset = firstVisibleItemScrollOffset (напрямую, без coerce)
    // LazyColumn имеет padding-top = collapsedHeight чтобы контент
    // не залезал под collapsed хедер.
    // Мёртвой зоны нет — каждый пиксель скролла двигает хедер.
    // ═══════════════════════════════════════════════════════════════
    val listState = rememberLazyListState()
    val focusManager = androidx.compose.ui.platform.LocalFocusManager.current

    // Hide keyboard when scrolling
    LaunchedEffect(listState.isScrollInProgress) {
        if (listState.isScrollInProgress) {
            focusManager.clearFocus()
        }
    }

    val spacerHeightDp = with(density) { maxScrollOffset.toDp() }
    val collapsedHeightDp = with(density) { collapsedHeightPx.toDp() }

    // scrollOffset напрямую из LazyColumn — как Telegram checkListViewScroll()
    val scrollOffset by remember {
        derivedStateOf {
            if (listState.firstVisibleItemIndex == 0) {
                listState.firstVisibleItemScrollOffset.toFloat()
            } else {
                maxScrollOffset
            }
        }
    }

    // Calculate collapse progress (0 = expanded, 1 = collapsed)
    val collapseProgress = (scrollOffset / maxScrollOffset).coerceIn(0f, 1f)

    // Dynamic header height based on scroll
    val headerHeight =
            with(density) {
                (expandedHeightPx - scrollOffset).coerceAtLeast(collapsedHeightPx).toDp()
            }

    // ═══════════════════════════════════════════════════════════════
    // TELEGRAM-STYLE AVATAR EXPANSION
    // При свайпе вниз от верха списка - аватарка расширяется
    // Порог snap = 33% (как в Telegram: expandProgress >= 0.33f)
    // ═══════════════════════════════════════════════════════════════
    var overscrollOffset by remember { mutableFloatStateOf(0f) }
    val maxOverscroll = with(density) { 250.dp.toPx() }  // Максимальное расширение
    val snapThreshold = maxOverscroll * 0.05f  // 🔥 5% - мгновенный snap!

    // Track dragging state
    var isDragging by remember { mutableStateOf(false) }
    
    // isPulledDown = зафиксировано в раскрытом состоянии (как Telegram)
    var isPulledDown by remember { mutableStateOf(false) }
    
    // Velocity для учёта скорости свайпа
    var lastVelocity by remember { mutableFloatStateOf(0f) }
    
    // Haptic feedback
    val hapticFeedback = LocalHapticFeedback.current
    var hasTriggeredExpandHaptic by remember { mutableStateOf(false) }

    // ═══════════════════════════════════════════════════════════════
    // SNAP ANIMATION - как Telegram's expandAnimator
    // При отпускании пальца: snap к 0 или к max в зависимости от порога
    // 🔥 FIX: Если isPulledDown=true - ВСЕГДА snap к max (даже во время drag!)
    // isPulledDown имеет ВЫСШИЙ ПРИОРИТЕТ - игнорирует isDragging
    // ═══════════════════════════════════════════════════════════════
    val targetOverscroll = when {
        isPulledDown -> maxOverscroll
        isDragging -> overscrollOffset
        overscrollOffset > snapThreshold -> maxOverscroll
        else -> 0f
    }
    
    // Spring анимация для snap (без bounce)
    val animatedOverscroll by animateFloatAsState(
        targetValue = targetOverscroll,
        animationSpec = if (isDragging && !isPulledDown) {
            spring(stiffness = Spring.StiffnessHigh)
        } else {
            spring(
                dampingRatio = Spring.DampingRatioNoBouncy,
                stiffness = Spring.StiffnessMedium
            )
        },
        label = "overscroll"
    )

    // ExpansionProgress для передачи в overlay
    // 🔥 FIX: Когда isPulledDown=true - ВСЕГДА используем animatedOverscroll
    // чтобы аватарка автоматически расширилась до конца
    val expansionProgress = when {
        collapseProgress > 0.1f -> 0f  // Не расширяем при collapse
        isPulledDown -> (animatedOverscroll / maxOverscroll).coerceIn(0f, 1f)  // 🔥 AUTO-EXPAND!
        isDragging -> (overscrollOffset / maxOverscroll).coerceIn(0f, 1f)
        else -> (animatedOverscroll / maxOverscroll).coerceIn(0f, 1f)
    }
    
    // Haptic при достижении порога (как Telegram)
    // 🔥 FIX: Также автоматически snap к expanded при достижении порога
    LaunchedEffect(expansionProgress, isDragging) {
        if (expansionProgress >= 0.10f && !hasTriggeredExpandHaptic && isDragging) {
            hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
            hasTriggeredExpandHaptic = true
            // 🔥 AUTO-SNAP: После порога автоматически snap к expanded
            isPulledDown = true
        } else if (expansionProgress < 0.02f) {
            hasTriggeredExpandHaptic = false
        }
    }

    // Haptic on collapse — light tick when avatar reaches notch
    var hasTriggeredCollapseHaptic by remember { mutableStateOf(false) }
    LaunchedEffect(collapseProgress) {
        if (collapseProgress >= 0.95f && !hasTriggeredCollapseHaptic) {
            hapticFeedback.performHapticFeedback(HapticFeedbackType.TextHandleMove)
            hasTriggeredCollapseHaptic = true
        } else if (collapseProgress < 0.5f) {
            hasTriggeredCollapseHaptic = false
        }
    }

    // Haptic on snap back — when avatar snaps back from expanded
    var hasTriggeredSnapBackHaptic by remember { mutableStateOf(false) }
    LaunchedEffect(isPulledDown, expansionProgress) {
        if (!isPulledDown && expansionProgress < 0.05f && hasTriggeredSnapBackHaptic) {
            hapticFeedback.performHapticFeedback(HapticFeedbackType.TextHandleMove)
            hasTriggeredSnapBackHaptic = false
        } else if (isPulledDown) {
            hasTriggeredSnapBackHaptic = true
        }
    }

    // Коллапс при удалении аватара — сразу сворачиваем
    LaunchedEffect(hasAvatar) {
        if (!hasAvatar) {
            isPulledDown = false
            overscrollOffset = 0f
        }
    }
    
    // ═══════════════════════════════════════════════════════════════
    // NESTED SCROLL — overscroll (pull-down аватарка) + header snap
    // Header collapse управляется скроллом LazyColumn (Telegram RecyclerView)
    // Snap вызывается в onPreFling — СРАЗУ при отпускании пальца
    // (как Telegram ACTION_UP → smoothScrollBy)
    // ═══════════════════════════════════════════════════════════════
    val nestedScrollConnection = remember(hasAvatar) {
        object : NestedScrollConnection {
            override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset {
                val delta = available.y

                // Тянем вверх (delta < 0) — убираем overscroll
                if (delta < 0) {
                    if (overscrollOffset > 0 || isPulledDown) {
                        isDragging = true
                        if (isPulledDown) {
                            if (delta < -10f) {
                                isPulledDown = false
                            }
                            return Offset(0f, delta)
                        }
                        val newOffset = (overscrollOffset + delta).coerceAtLeast(0f)
                        val consumed = overscrollOffset - newOffset
                        overscrollOffset = newOffset
                        return Offset(0f, -consumed)
                    }
                }

                return Offset.Zero
            }

            override fun onPostScroll(
                    consumed: Offset,
                    available: Offset,
                    source: NestedScrollSource
            ): Offset {
                // Overscroll при свайпе вниз от верха (только если есть аватар)
                if (available.y > 0 && !listState.canScrollBackward && hasAvatar) {
                    isDragging = true
                    val resistance = if (isPulledDown) 1f else 0.5f
                    val delta = available.y * resistance
                    overscrollOffset = (overscrollOffset + delta).coerceAtMost(maxOverscroll)
                    return Offset(0f, available.y)
                }
                return Offset.Zero
            }

            // ═══════════════════════════════════════════════════════
            // onPreFling — Telegram ACTION_UP
            // Вызывается СРАЗУ при отпускании пальца, ДО fling.
            // Если хедер в промежуточной позиции — перехватываем
            // velocity и запускаем animateScrollToItem.
            // LazyColumn НЕ получит velocity → нет fling → нет дёрганья.
            // ═══════════════════════════════════════════════════════
            override suspend fun onPreFling(available: Velocity): Velocity {
                lastVelocity = available.y
                isDragging = false

                // Overscroll snap (аватарка pull-down)
                val velocityThreshold = 1000f
                when {
                    overscrollOffset > snapThreshold || (lastVelocity > velocityThreshold && overscrollOffset > snapThreshold * 0.5f) -> {
                        isPulledDown = true
                    }
                    lastVelocity < -velocityThreshold && overscrollOffset > 0 -> {
                        isPulledDown = false
                    }
                    else -> {
                        isPulledDown = overscrollOffset > snapThreshold
                    }
                }

                // HEADER SNAP — Telegram smoothScrollBy(dy, EASE_OUT_QUINT)
                // animateScrollBy = Compose эквивалент smoothScrollBy
                val currentOffset = scrollOffset
                if (currentOffset > 0f && currentOffset < maxScrollOffset) {
                    val progress = currentOffset / maxScrollOffset
                    val snapToCollapsed = when {
                        available.y < -velocityThreshold -> true
                        available.y > velocityThreshold -> false
                        progress >= 0.6f -> true
                        else -> false
                    }
                    val snapDelta = if (snapToCollapsed) {
                        maxScrollOffset - currentOffset // скролл вперёд = collapse
                    } else {
                        -currentOffset // скролл назад = expand
                    }
                    listState.animateScrollBy(
                        value = snapDelta,
                        animationSpec = tween(
                            durationMillis = 250,
                            easing = CubicBezierEasing(0.25f, 1f, 0.5f, 1f)
                        )
                    )
                    return available
                }

                return Velocity.Zero
            }

            override suspend fun onPostFling(consumed: Velocity, available: Velocity): Velocity {
                return Velocity.Zero
            }
        }
    }

    // Show success toast and update local profile
    LaunchedEffect(profileState.saveSuccess) {
        if (profileState.saveSuccess) {
            android.widget.Toast.makeText(
                            context,
                            "Profile updated successfully",
                            android.widget.Toast.LENGTH_SHORT
                    )
                    .show()

            // Following desktop version: update local data AFTER server confirms success
            viewModel.updateLocalProfile(accountPublicKey, editedName, editedUsername)

            serverNameError = null
            serverUsernameError = null
            serverGeneralError = null
            viewModel.resetSaveState()

            // Notify parent about profile update (updates UI in MainActivity)
            onSaveProfile(editedName, editedUsername)
        }
    }

    // Show error toast
    LaunchedEffect(profileState.error) {
        profileState.error?.let { rawError ->
            val mappedError = mapProfileSaveError(rawError)
            serverNameError = mappedError.nameError
            serverUsernameError = mappedError.usernameError
            serverGeneralError =
                    if (mappedError.nameError == null && mappedError.usernameError == null) {
                        mappedError.generalMessage
                    } else {
                        null
                    }
            if (mappedError.nameError != null) {
                nameTouched = true
                showValidationErrors = true
            }
            if (mappedError.usernameError != null) {
                usernameTouched = true
                showValidationErrors = true
            }

            android.widget.Toast.makeText(
                            context,
                            mappedError.toastMessage,
                            android.widget.Toast.LENGTH_SHORT
                    )
                    .show()
            viewModel.resetSaveState()
        }
    }

    SideEffect {
        onHasChangesChanged(hasChanges)
    }

    DisposableEffect(Unit) {
        onDispose {
            onHasChangesChanged(false)
        }
    }

    // Handle back button press - navigate to chat list instead of closing app
    BackHandler { onBack() }

    Box(
            modifier =
                    Modifier.fillMaxSize()
                            .background(backgroundColor)
                            .nestedScroll(nestedScrollConnection)
    ) {
        // Scrollable content — Telegram architecture:
        // Item 0 = spacer (ровно maxScrollOffset px) → каждый пиксель скролла двигает хедер
        // padding-top = collapsedHeightDp → контент не залезает под collapsed хедер
        LazyColumn(
            state = listState,
            modifier = Modifier.fillMaxSize(),
            contentPadding =
                    PaddingValues(
                            top = collapsedHeightDp,
                            bottom = navigationBarHeight + 28.dp
                    )
        ) {
            // Item 0: spacer = ровно сколько нужно проскроллить для collapse
            item {
                Spacer(modifier = Modifier.fillMaxWidth().height(spacerHeightDp))
            }
            item {
                Spacer(modifier = Modifier.height(16.dp))

                // ═════════════════════════════════════════════════════════════
                // 📋 ACCOUNT SECTION - Telegram style
                // ═════════════════════════════════════════════════════════════
                TelegramSectionTitle(title = "Account", isDarkTheme = isDarkTheme)

                AnimatedVisibility(
                        visible = !serverGeneralError.isNullOrBlank(),
                        enter = fadeIn(),
                        exit = fadeOut()
                ) {
                    Text(
                            text = serverGeneralError ?: "",
                            fontSize = 13.sp,
                            color = Color(0xFFFF3B30),
                            modifier = Modifier.padding(horizontal = 16.dp, vertical = 4.dp)
                    )
                }

                // Name field
                TelegramTextField(
                        value = editedName,
                        label = "Your name",
                        isDarkTheme = isDarkTheme,
                        isEditable = true,
                        onValueChange = {
                            editedName = it
                            nameTouched = true
                            serverNameError = null
                            serverGeneralError = null
                        },
                        showDivider = true,
                        placeholder = "Add your name",
                        errorText = nameError
                )

                // Username field
                TelegramTextField(
                        value = editedUsername,
                        label = "Username",
                        isDarkTheme = isDarkTheme,
                        isEditable = true,
                        onValueChange = {
                            editedUsername = it
                            usernameTouched = true
                            serverUsernameError = null
                            serverGeneralError = null
                        },
                        showDivider = true,
                        placeholder = "Add username",
                        errorText = usernameError
                )

                // Public Key field
                TelegramCopyField(
                        value = accountPublicKey.take(16) + "..." + accountPublicKey.takeLast(6),
                        fullValue = accountPublicKey,
                        label = "Public Key",
                        isDarkTheme = isDarkTheme
                )

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

                // ═════════════════════════════════════════════════════════════
                // ⚙️ SETTINGS SECTION - Telegram style
                // ═════════════════════════════════════════════════════════════
                TelegramSectionTitle(title = "Settings", isDarkTheme = isDarkTheme)

                TelegramSettingsItem(
                        icon = TelegramIcons.Notifications,
                        title = "Notifications",
                        onClick = onNavigateToNotifications,
                        isDarkTheme = isDarkTheme,
                        showDivider = true
                )

                TelegramSettingsItem(
                        icon = TelegramIcons.Theme,
                        title = "Theme",
                        onClick = onNavigateToTheme,
                        isDarkTheme = isDarkTheme,
                        showDivider = true
                )

                TelegramSettingsItem(
                        icon = TelegramIcons.Customize,
                        title = "Appearance",
                        onClick = onNavigateToAppearance,
                        isDarkTheme = isDarkTheme,
                        showDivider = true
                )

                TelegramSettingsItem(
                        icon = TelegramIcons.Secret,
                        title = "Safety",
                        onClick = onNavigateToSafety,
                        isDarkTheme = isDarkTheme,
                        showDivider = biometricAvailable is BiometricAvailability.Available
                )

                // Biometric settings (only show if available)
                if (biometricAvailable is BiometricAvailability.Available && activity != null) {
                    TelegramSettingsItem(
                            icon = TelegramIcons.Fingerprint,
                            title = "Biometric Authentication",
                            onClick = {
                                onNavigateToBiometric()
                            },
                            isDarkTheme = isDarkTheme,
                            showDivider = true,
                            subtitle = if (isBiometricEnabled) "Enabled" else "Disabled"
                    )
                }

                TelegramSettingsItem(
                        icon = androidx.compose.ui.graphics.vector.rememberVectorPainter(compose.icons.TablerIcons.Scan),
                        title = "QR Code",
                        onClick = onNavigateToMyQr,
                        isDarkTheme = isDarkTheme,
                        showDivider = false,
                        subtitle = "Share your profile"
                )

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

                // ═════════════════════════════════════════════════════════════
                // 🚪 LOGOUT - Telegram style (red text)
                // ═════════════════════════════════════════════════════════════
                TelegramLogoutItem(onClick = onLogout, isDarkTheme = isDarkTheme)

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

        // ═════════════════════════════════════════════════════════════
        // 🎨 COLLAPSING PROFILE HEADER with overscroll expansion
        // ═════════════════════════════════════════════════════════════
        CollapsingProfileHeader(
                name = editedName.ifBlank { accountPublicKey.take(10) },
                username = editedUsername,
                verified = accountVerified,
                publicKey = accountPublicKey,
                avatarColors = avatarColors,
                collapseProgress = collapseProgress,
                expansionProgress = expansionProgress,
                onBack = onBack,
                hasChanges = hasChanges,
                isSaveEnabled = isFormValid && !profileState.isSaving,
                onSave = saveProfile@{
                    showValidationErrors = true
                    nameTouched = true
                    usernameTouched = true

                    val nameToSave = editedName.trim()
                    val usernameToSave = editedUsername.trim()
                    val localNameError = validateProfileName(nameToSave)
                    val localUsernameError = validateProfileUsername(usernameToSave)
                    if (localNameError != null || localUsernameError != null) {
                        return@saveProfile
                    }

                    serverNameError = null
                    serverUsernameError = null
                    serverGeneralError = null

                    editedName = nameToSave
                    editedUsername = usernameToSave

                    // Following desktop version logic:
                    // 1. Send packet to server
                    // 2. Wait for response in ProfileViewModel
                    // 3. Update local data only on success (in LaunchedEffect above)
                    viewModel.saveProfile(
                            publicKey = accountPublicKey,
                            privateKeyHash = accountPrivateKeyHash,
                            name = nameToSave,
                            username = usernameToSave
                    )
                    // Note: Local update happens in LaunchedEffect when saveSuccess is true
                },
                isDarkTheme = isDarkTheme,
                showAvatarMenu = showAvatarMenu,
                onAvatarMenuChange = { showAvatarMenu = it },
                onSetPhotoClick = { showPhotoPicker = true },
                onDeletePhotoClick = {
                    // Удаляем аватар
                    scope.launch {
                        avatarRepository?.deleteMyAvatar()
                        android.widget.Toast.makeText(
                                        context,
                                        "Avatar deleted",
                                        android.widget.Toast.LENGTH_SHORT
                                )
                                .show()
                    }
                },
                hasAvatar = hasAvatar,
                avatarRepository = avatarRepository,
                backgroundBlurColorId = backgroundBlurColorId,
                onQrCodeClick = onNavigateToMyQr,
                onAvatarLongPress = {
                    if (hasAvatar) {
                        scope.launch {
                            val avatarList = avatarRepository?.getAvatars(accountPublicKey, allDecode = false)?.first()
                            val first = avatarList?.firstOrNull()
                            if (first != null) {
                                avatarViewerTimestamp = first.timestamp
                                val bmp = withContext(Dispatchers.IO) {
                                    AvatarFileManager.base64ToBitmap(first.base64Data)
                                }
                                avatarViewerBitmap = bmp
                                showAvatarViewer = true
                            }
                        }
                    }
                }
        )

        // ═══════════════════════════════════════════════════════════
        // 📷 + QR FLOATING BUTTONS — at boundary between header and content
        // Positioned at bottom-right of header, half overlapping content area
        // Fades out when collapsed or when avatar is expanded
        // ═══════════════════════════════════════════════════════════
        val cameraButtonSize = 60.dp
        val floatingButtonsAlpha = (1f - collapseProgress * 2f).coerceIn(0f, 1f)
        if (floatingButtonsAlpha > 0.01f) {
            Box(
                    modifier = Modifier
                            .align(Alignment.TopEnd)
                            .offset(
                                    x = (-16).dp,
                                    y = headerHeight - cameraButtonSize / 2
                            )
                            .graphicsLayer { alpha = floatingButtonsAlpha }
            ) {
                Box(
                        modifier = Modifier
                                .size(cameraButtonSize)
                                .shadow(
                                        elevation = 4.dp,
                                        shape = CircleShape,
                                        clip = false
                                )
                                .clip(CircleShape)
                                .background(
                                        if (isDarkTheme) Color(0xFF2A2A2A)
                                        else Color(0xFF0D8CF4)
                                )
                                .clickable { showPhotoPicker = true },
                        contentAlignment = Alignment.Center
                ) {
                        Icon(
                                painter = TelegramIcons.AddPhoto,
                                contentDescription = "Change avatar",
                                tint = if (isDarkTheme) Color(0xFF8E8E93) else Color.White,
                                modifier = Modifier.size(26.dp).offset(x = 2.dp)
                        )
                }
            }
        }
    }

    // 🖼️ Кастомный быстрый Photo Picker
    ProfilePhotoPicker(
        isVisible = showPhotoPicker,
        onDismiss = { showPhotoPicker = false },
        onPhotoSelected = { uri ->
            showPhotoPicker = false
            // Запускаем uCrop для обрезки
            val cropIntent = ImageCropHelper.createCropIntent(context, uri, isDarkTheme)
            cropLauncher.launch(cropIntent)
        },
        isDarkTheme = isDarkTheme
    )

    // 🔍 Full-screen avatar viewer
    FullScreenAvatarViewer(
            isVisible = showAvatarViewer,
            onDismiss = { showAvatarViewer = false },
            displayName = editedName.ifBlank { accountPublicKey.take(10) },
            avatarTimestamp = avatarViewerTimestamp,
            avatarBitmap = avatarViewerBitmap,
            publicKey = accountPublicKey,
            isDarkTheme = isDarkTheme,
            avatarRepository = avatarRepository
    )
}

// ═════════════════════════════════════════════════════════════
// 🎯 COLLAPSING PROFILE HEADER - Circle by default, Square on overscroll
// По умолчанию: круглая аватарка
// При overscroll вниз (expansionProgress): расширяется до квадрата
// При скролле вверх (collapseProgress): уменьшается и уходит вверх
// ═════════════════════════════════════════════════════════════
@Composable
private fun CollapsingProfileHeader(
        name: String,
        username: String,
        verified: Int = 0,
        publicKey: String,
        avatarColors: AvatarColors,
        collapseProgress: Float,
        expansionProgress: Float,
        onBack: () -> Unit,
        hasChanges: Boolean,
        isSaveEnabled: Boolean,
        onSave: () -> Unit,
        isDarkTheme: Boolean,
        showAvatarMenu: Boolean,
        onAvatarMenuChange: (Boolean) -> Unit,
        onSetPhotoClick: () -> Unit,
        onDeletePhotoClick: () -> Unit,
        hasAvatar: Boolean,
        avatarRepository: AvatarRepository?,
        backgroundBlurColorId: String = "avatar",
        onQrCodeClick: () -> Unit = {},
        onAvatarLongPress: () -> Unit = {}
) {
    @Suppress("UNUSED_VARIABLE")
    val density = LocalDensity.current

    // Get actual status bar height
    val statusBarHeight = WindowInsets.statusBars.asPaddingValues().calculateTopPadding()

    // ═══════════════════════════════════════════════════════════
    // 🎨 TEXT COLOR - просто по теме: белый в тёмной, чёрный в светлой
    // ═══════════════════════════════════════════════════════════
    val textColor = Color.White

    // ═══════════════════════════════════════════════════════════
    // 📐 HEADER HEIGHT - ФИКСИРОВАННАЯ! Не меняется при overscroll
    // ═══════════════════════════════════════════════════════════
    val expandedHeight = EXPANDED_HEADER_HEIGHT + statusBarHeight
    val collapsedHeight = COLLAPSED_HEADER_HEIGHT + statusBarHeight

    // Header height меняется только при collapse, НЕ при overscroll
    val headerHeight =
            androidx.compose.ui.unit.lerp(expandedHeight, collapsedHeight, collapseProgress)

    // ═══════════════════════════════════════════════════════════
    // 👤 AVATAR - Размер шрифта для placeholder (без аватарки)
    // Основная логика теперь в ProfileMetaballEffect
    // ═══════════════════════════════════════════════════════════
    val avatarFontSize = androidx.compose.ui.unit.lerp(40.sp, 12.sp, collapseProgress)

    // ═══════════════════════════════════════════════════════════
    // 📝 TEXT - внизу header зоны, внутри блока
    // ═══════════════════════════════════════════════════════════
    val textDefaultY = expandedHeight - 70.dp // Ближе к аватарке
    // Collapsed: center text block vertically in collapsed header
    // Text block is ~35dp tall (name 18sp + 2dp spacer + online 13sp)
    val textBlockHeight = 35.dp
    val textCollapsedY = statusBarHeight + (COLLAPSED_HEADER_HEIGHT - textBlockHeight) / 2

    // Текст меняет позицию только при collapse, НЕ при overscroll
    val textY = androidx.compose.ui.unit.lerp(textDefaultY, textCollapsedY, collapseProgress)

    // Font sizes
    val nameFontSize = androidx.compose.ui.unit.lerp(24.sp, 18.sp, collapseProgress)
    val onlineFontSize = androidx.compose.ui.unit.lerp(14.sp, 13.sp, collapseProgress)
    val rosettaBadgeBlue = Color(0xFF1DA1F2)
    val isOfficialByKey = MessageRepository.isSystemAccount(publicKey)

    Box(modifier = Modifier.fillMaxWidth().height(headerHeight).clipToBounds()) {
        // Expansion fraction — computed early so gradient can fade during expansion
        val expandFraction = expansionProgress.coerceIn(0f, 1f)
        val headerBaseColor = if (isDarkTheme) Color(0xFF2A2A2A) else Color(0xFF0D8CF4)
        // Neutral screen bg — used under blur/overlay so blue doesn't bleed through
        val screenBgColor = if (isDarkTheme) Color(0xFF1A1A1A) else Color(0xFFFFFFFF)

        // ═══════════════════════════════════════════════════════════
        // 🎨 BLURRED AVATAR BACKGROUND — ВСЕГДА видим
        // Не fadeout'им при расширении: аватарка растёт поверх blur'а
        // и естественно перекрывает его. Без мерцания.
        // ═══════════════════════════════════════════════════════════
        Box(modifier = Modifier.matchParentSize()) {
            if (backgroundBlurColorId == "none") {
                // None — стандартный цвет шапки без blur
                Box(
                    modifier = Modifier
                        .matchParentSize()
                        .background(headerBaseColor)
                )
            } else {
                // Neutral base so transparent blur layers don't pick up blue tint
                Box(modifier = Modifier.matchParentSize().background(screenBgColor))
                BlurredAvatarBackground(
                        publicKey = publicKey,
                        avatarRepository = avatarRepository,
                        fallbackColor = avatarColors.backgroundColor,
                        blurRadius = 20f,
                        alpha = 1f,
                        overlayColors = BackgroundBlurPresets.getOverlayColors(backgroundBlurColorId),
                        isDarkTheme = isDarkTheme
                )
            }
        }

        // ═══════════════════════════════════════════════════════════
        // 🌅 BOTTOM GRADIENT — плавно исчезает только когда аватарка
        // уже почти заполнила всю область (90%+)
        // ═══════════════════════════════════════════════════════════
        val gradientAlpha = (1f - expandFraction * 1.2f).coerceIn(0f, 1f)
        if (gradientAlpha > 0.01f) {
            Box(
                    modifier = Modifier
                            .fillMaxWidth()
                            .height(80.dp)
                            .align(Alignment.BottomCenter)
                            .graphicsLayer { alpha = gradientAlpha }
                            .background(
                                    Brush.verticalGradient(
                                            colors = listOf(
                                                    Color.Transparent,
                                                    Color.Black.copy(alpha = 0.35f)
                                            )
                                    )
                            )
            )
        }

        // ═══════════════════════════════════════════════════════════
        // 👤 AVATAR — Telegram-style expansion to fill header on pull-down
        // Normal: circle, centered. Pull-down: grows to fill full header width
        // ═══════════════════════════════════════════════════════════
        val avatarSize = androidx.compose.ui.unit.lerp(
                AVATAR_SIZE_EXPANDED, AVATAR_SIZE_COLLAPSED, collapseProgress
        )
        val avatarAlpha = (1f - collapseProgress * 1.8f).coerceIn(0f, 1f)
        val avatarShadowSize = androidx.compose.ui.unit.lerp(12.dp, 0.dp, collapseProgress)
        val contentAreaHeight = EXPANDED_HEADER_HEIGHT - 70.dp
        val avatarExpandedY = statusBarHeight + (contentAreaHeight - AVATAR_SIZE_EXPANDED) / 2
        val avatarCollapsedY = statusBarHeight + (COLLAPSED_HEADER_HEIGHT - AVATAR_SIZE_COLLAPSED) / 2
        val avatarY = androidx.compose.ui.unit.lerp(avatarExpandedY, avatarCollapsedY, collapseProgress)

        // Telegram-style expansion math
        val screenWidth = LocalConfiguration.current.screenWidthDp.dp
        // Avatar width: circle → full screen width
        val expandedAvatarWidth = androidx.compose.ui.unit.lerp(avatarSize, screenWidth, expandFraction)
        // Avatar height: circle → full header height
        val expandedAvatarHeight = androidx.compose.ui.unit.lerp(avatarSize, headerHeight, expandFraction)
        // Corner radius: fully circular → 0 (square)
        val cornerRadius = androidx.compose.ui.unit.lerp(avatarSize / 2, 0.dp, expandFraction)
        // Avatar X: centered → left edge
        val avatarCenterX = (screenWidth - avatarSize) / 2
        val expandedAvatarX = androidx.compose.ui.unit.lerp(avatarCenterX, 0.dp, expandFraction)
        // Avatar Y: normal position → top
        val expandedAvatarY = androidx.compose.ui.unit.lerp(avatarY, 0.dp, expandFraction)

        // Pre-compute pixel values for graphicsLayer (avoids layout-phase recomposition)
        val expandedAvatarXPx = with(density) { expandedAvatarX.toPx() }
        val expandedAvatarYPx = with(density) { expandedAvatarY.toPx() }

        Box(
                modifier = Modifier
                        .size(width = expandedAvatarWidth, height = expandedAvatarHeight)
                        .graphicsLayer {
                            translationX = expandedAvatarXPx
                            translationY = expandedAvatarYPx
                            alpha = avatarAlpha
                            shadowElevation = if (expansionProgress > 0.01f) 0f
                                    else with(density) { avatarShadowSize.toPx() }
                            shape = RoundedCornerShape(cornerRadius)
                            clip = true
                        }
                        .background(avatarColors.backgroundColor)
                        .pointerInput(Unit) {
                            detectTapGestures(
                                    onLongPress = { onAvatarLongPress() }
                            )
                        },
                contentAlignment = Alignment.Center
        ) {
            if (hasAvatar && avatarRepository != null) {
                FullSizeAvatar(
                        publicKey = publicKey,
                        avatarRepository = avatarRepository,
                        isDarkTheme = isDarkTheme
                )
            } else {
                Text(
                        text = getInitials(name),
                        fontSize = avatarFontSize,
                        fontWeight = FontWeight.Bold,
                        color = avatarColors.textColor
                )
            }
        }

        // Gradient overlays when avatar is expanded
        if (expandFraction > 0.01f) {
            // Top gradient
            Box(
                    modifier = Modifier
                            .fillMaxWidth()
                            .height(120.dp)
                            .align(Alignment.TopCenter)
                            .graphicsLayer { alpha = expandFraction }
                            .background(
                                    Brush.verticalGradient(
                                            colors = listOf(
                                                    Color.Black.copy(alpha = 0.6f),
                                                    Color.Transparent
                                            )
                                    )
                            )
            )
            // Bottom gradient
            Box(
                    modifier = Modifier
                            .fillMaxWidth()
                            .height(120.dp)
                            .align(Alignment.BottomCenter)
                            .graphicsLayer { alpha = expandFraction }
                            .background(
                                    Brush.verticalGradient(
                                            colors = listOf(
                                                    Color.Transparent,
                                                    Color.Black.copy(alpha = 0.6f)
                                            )
                                    )
                            )
            )
        }

        // ═══════════════════════════════════════════════════════════
        // 🔙 BACK BUTTON - At top when expanded, centered when collapsed
        // ═══════════════════════════════════════════════════════════
        val buttonsExpandedY = statusBarHeight + 8.dp
        val buttonsCollapsedY = statusBarHeight + (COLLAPSED_HEADER_HEIGHT - 48.dp) / 2
        val buttonsY = androidx.compose.ui.unit.lerp(buttonsExpandedY, buttonsCollapsedY, collapseProgress)

        Box(
                modifier =
                        Modifier
                                .align(Alignment.TopStart)
                                .offset(x = 4.dp, y = buttonsY)
                                .size(48.dp),
                contentAlignment = Alignment.Center
        ) {
            IconButton(onClick = onBack, modifier = Modifier.size(48.dp)) {
                Icon(
                        imageVector = TablerIcons.ChevronLeft,
                        contentDescription = "Back",
                        tint = Color.White,
                        modifier = Modifier.size(24.dp)
                )
            }
        }

        // ═══════════════════════════════════════════════════════════
        // ⋮ MENU BUTTON / 💾 SAVE BUTTON - At top when expanded, centered when collapsed
        // ═══════════════════════════════════════════════════════════
        Box(
                modifier =
                        Modifier.align(Alignment.TopEnd)
                                .offset(x = -4.dp, y = buttonsY),
                contentAlignment = Alignment.Center
        ) {
            AnimatedVisibility(visible = hasChanges, enter = fadeIn(), exit = fadeOut()) {
                TextButton(onClick = onSave, enabled = isSaveEnabled) {
                    Text(
                            text = "Save",
                            color =
                                    if (isSaveEnabled) {
                                        Color.White
                                    } else {
                                        Color.White.copy(alpha = 0.45f)
                                    },
                            fontWeight = FontWeight.SemiBold
                    )
                }
            }

            AnimatedVisibility(visible = !hasChanges, enter = fadeIn(), exit = fadeOut()) {
                IconButton(
                        onClick = { onAvatarMenuChange(true) },
                        modifier = Modifier.size(48.dp)
                ) {
                    Icon(
                            painter = TelegramIcons.More,
                            contentDescription = "Profile menu",
                            tint = Color.White,
                            modifier = Modifier.size(24.dp)
                    )
                }
            }

            com.rosetta.messenger.ui.chats.components.ProfilePhotoMenu(
                    expanded = showAvatarMenu,
                    onDismiss = { onAvatarMenuChange(false) },
                    isDarkTheme = isDarkTheme,
                    onQrCodeClick = {
                        onAvatarMenuChange(false)
                        onQrCodeClick()
                    },
                    onSetPhotoClick = {
                        onAvatarMenuChange(false)
                        onSetPhotoClick()
                    },
                    onDeletePhotoClick = {
                        onAvatarMenuChange(false)
                        onDeletePhotoClick()
                    },
                    hasAvatar = hasAvatar
            )
        }

        // ═══════════════════════════════════════════════════════════
        // 📝 TEXT BLOCK - Name + Online
        // ═══════════════════════════════════════════════════════════
        Column(
                modifier =
                        Modifier.align(Alignment.TopCenter).offset(y = textY),
                horizontalAlignment = Alignment.CenterHorizontally
        ) {
            val verifiedBadgeSize = (nameFontSize.value * 0.8f).toInt()
            Row(
                    horizontalArrangement = Arrangement.Center
            ) {
                Text(
                        text = name,
                        fontSize = nameFontSize,
                        fontWeight = FontWeight.SemiBold,
                        color = textColor,
                        maxLines = 1,
                        overflow = TextOverflow.Ellipsis,
                        modifier = Modifier.widthIn(max = 220.dp).alignByBaseline(),
                        textAlign = TextAlign.Center
                )
                if (verified > 0 || isOfficialByKey) {
                    Box(
                            modifier =
                                    Modifier.padding(start = 4.dp)
                                            .alignBy { (it.measuredHeight * 0.78f).toInt() }
                    ) {
                        VerifiedBadge(
                                verified = if (verified > 0) verified else 2,
                                size = verifiedBadgeSize,
                                isDarkTheme = isDarkTheme,
                                badgeTint = Color.White
                        )
                    }
                }
            }

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

            Text(text = "online", fontSize = onlineFontSize, color = textColor)
        }
    }
}

// ═════════════════════════════════════════════════════════════
// 🖼 FULL SIZE AVATAR - Fills entire container (for expanded state)
// ═════════════════════════════════════════════════════════════
@Composable
private fun FullSizeAvatar(
        publicKey: String,
        avatarRepository: AvatarRepository?,
        isDarkTheme: Boolean = false
) {
    val avatars by
            avatarRepository?.getAvatars(publicKey, allDecode = false)?.collectAsState()
                    ?: remember { mutableStateOf(emptyList()) }

    // 🔥 FIX: Используем стабильный ключ (timestamp) вместо reference списка
    // Это предотвращает перезагрузку bitmap при recomposition когда данные не изменились
    val avatarKey = remember(avatars) { 
        avatars.firstOrNull()?.timestamp ?: 0L 
    }

    // 🔥 FIX: Сохраняем bitmap БЕЗ сброса при изменении ключа
    // Предыдущий bitmap показывается пока загружается новый (double buffering)
    var bitmap by remember { mutableStateOf<android.graphics.Bitmap?>(null) }
    
    // 🔥 FIX: isLoading только для первой загрузки, не сбрасываем если bitmap уже есть
    var initialLoadComplete by remember { mutableStateOf(false) }

    // 🔥 FIX: Декодируем только когда avatarKey (timestamp) реально изменился
    // НЕ сбрасываем bitmap в null перед загрузкой - показываем старый пока грузится новый
    LaunchedEffect(avatarKey) {
        val currentAvatars = avatars
        if (currentAvatars.isNotEmpty()) {
            val newBitmap = kotlinx.coroutines.withContext(kotlinx.coroutines.Dispatchers.IO) {
                com.rosetta.messenger.utils.AvatarFileManager.base64ToBitmap(
                        currentAvatars.first().base64Data
                )
            }
            // Устанавливаем новый bitmap только если декодирование успешно
            if (newBitmap != null) {
                bitmap = newBitmap
            }
            initialLoadComplete = true
        } else {
            // Нет аватарки - сбрасываем bitmap и помечаем загрузку завершенной
            bitmap = null
            initialLoadComplete = true
        }
    }

    // Показываем картинку если есть, иначе placeholder
    // 🔥 FIX: Показываем bitmap сразу если он есть (даже во время загрузки нового)
    when {
        bitmap != null -> {
            Image(
                    bitmap = bitmap!!.asImageBitmap(),
                    contentDescription = "Avatar",
                    modifier = Modifier.fillMaxSize(),
                    contentScale = ContentScale.Crop
            )
        }
        initialLoadComplete -> {
            // Placeholder только когда точно нет аватарки И загрузка завершена
            val avatarColors = getAvatarColor(publicKey, isDarkTheme)
            Box(
                    modifier = Modifier.fillMaxSize().background(avatarColors.backgroundColor),
                    contentAlignment = Alignment.Center
            ) {
                Text(
                        text = publicKey.take(2).uppercase(),
                        color = avatarColors.textColor,
                        fontSize = 80.sp,
                        fontWeight = FontWeight.Bold
                )
            }
        }
        // Пока initialLoadComplete=false - ничего не показываем (прозрачно)
        // Это только самый первый момент загрузки
    }
}

// ═════════════════════════════════════════════════════════════
// �📦 PROFILE CARD COMPONENT - Legacy (kept for OtherProfileScreen)
// ═════════════════════════════════════════════════════════════
@Composable
fun ProfileCard(
        name: String,
        username: String,
        publicKey: String,
        isDarkTheme: Boolean,
        onBack: (() -> Unit)?,
        hasChanges: Boolean,
        onSave: () -> Unit
) {
    val avatarColors = getAvatarColor(publicKey, isDarkTheme)

    Box(modifier = Modifier.fillMaxWidth().background(avatarColors.backgroundColor)) {
        // Back button (if callback provided)
        if (onBack != null) {
            IconButton(
                    onClick = onBack,
                    modifier = Modifier.align(Alignment.TopStart).statusBarsPadding().padding(4.dp)
            ) {
                Icon(
                        imageVector = TablerIcons.ChevronLeft,
                        contentDescription = "Back",
                        tint = if (isDarkTheme) Color.White else Color.Black
                )
            }
        }

        // Save button (if changes)
        AnimatedVisibility(
                visible = hasChanges,
                enter = fadeIn() + expandHorizontally(),
                exit = fadeOut() + shrinkHorizontally(),
                modifier =
                        Modifier.align(Alignment.TopEnd)
                                .statusBarsPadding()
                                .padding(end = 52.dp, top = 4.dp) // Сдвинуто левее
        ) {
            TextButton(onClick = onSave) {
                Text(
                        text = "Save",
                        color = if (isDarkTheme) Color.White else Color.Black,
                        fontWeight = FontWeight.SemiBold
                )
            }
        }

        Column(
                modifier = Modifier.fillMaxWidth().padding(top = 80.dp, bottom = 48.dp),
                horizontalAlignment = Alignment.CenterHorizontally
        ) {
            // 👤 Large Avatar - Telegram style
            Box(
                    modifier =
                            Modifier.size(140.dp)
                                    .clip(CircleShape)
                                    .background(Color.White.copy(alpha = 0.2f))
                                    .padding(3.dp)
                                    .clip(CircleShape)
                                    .background(avatarColors.backgroundColor),
                    contentAlignment = Alignment.Center
            ) {
                Text(
                        text = getInitials(name),
                        fontSize = 48.sp,
                        fontWeight = FontWeight.Bold,
                        color = avatarColors.textColor
                )
            }

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

            // Name
            Text(
                    text = name,
                    fontSize = 24.sp,
                    fontWeight = FontWeight.SemiBold,
                    color = Color.White,
                    textAlign = TextAlign.Center
            )

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

            // Username and short public key
            Row(
                    horizontalArrangement = Arrangement.Center,
                    verticalAlignment = Alignment.CenterVertically
            ) {
                if (username.isNotBlank()) {
                    Text(
                            text = "@$username",
                            fontSize = 14.sp,
                            color = Color.White.copy(alpha = 0.8f)
                    )
                    Text(text = " • ", fontSize = 14.sp, color = Color.White.copy(alpha = 0.8f))
                }
                Text(
                        text = "${publicKey.take(3)}...${publicKey.takeLast(3)}",
                        fontSize = 14.sp,
                        color = Color.White.copy(alpha = 0.8f)
                )
            }
        }
    }
}

// ═════════════════════════════════════════════════════════════
// � TELEGRAM-STYLE COMPONENTS
// ═════════════════════════════════════════════════════════════

@Composable
fun TelegramSectionTitle(title: String, isDarkTheme: Boolean, color: Color? = null) {
    val textColor = color ?: if (isDarkTheme) Color(0xFF8E8E93) else Color(0xFF8E8E93)

    Text(
            text = title,
            fontSize = 15.sp,
            fontWeight = FontWeight.Medium,
            color = textColor,
            modifier = Modifier.padding(horizontal = 16.dp, vertical = 12.dp)
    )
}

@Composable
private fun TelegramTextField(
        value: String,
        label: String,
        isDarkTheme: Boolean,
        isEditable: Boolean = false,
        onValueChange: ((String) -> Unit)? = null,
        showDivider: Boolean = false,
        placeholder: String = "",
        errorText: String? = null
) {
    val textColor = if (isDarkTheme) Color.White else Color.Black
    val secondaryTextColor = if (isDarkTheme) Color(0xFF8E8E93) else Color(0xFF666666)
    val dividerColor = if (isDarkTheme) Color(0xFF3A3A3A) else Color(0xFFE0E0E0)
    val hasError = !errorText.isNullOrBlank()
    val errorColor = Color(0xFFFF3B30)
    val labelText = if (hasError) errorText.orEmpty() else label
    val labelColor by
            animateColorAsState(
                    targetValue = if (hasError) errorColor else secondaryTextColor,
                    label = "profile_field_label_color"
            )
    val fieldModifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp, vertical = 12.dp)

    Column {
        Column(modifier = fieldModifier) {
            if (isEditable && onValueChange != null) {
                BasicTextField(
                        value = value,
                        onValueChange = onValueChange,
                        modifier = Modifier.fillMaxWidth(),
                        textStyle = TextStyle(color = textColor, fontSize = 16.sp),
                        singleLine = true,
                        cursorBrush = androidx.compose.ui.graphics.SolidColor(textColor),
                        decorationBox = { innerTextField ->
                            if (value.isEmpty() && placeholder.isNotEmpty()) {
                                Text(
                                        text = placeholder,
                                        fontSize = 16.sp,
                                        color = secondaryTextColor.copy(alpha = 0.5f)
                                )
                            }
                            innerTextField()
                        }
                )
            } else {
                Text(
                        text = value.ifBlank { placeholder },
                        fontSize = 16.sp,
                        color =
                                if (value.isBlank()) secondaryTextColor.copy(alpha = 0.5f)
                                else textColor
                )
            }

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

            Text(text = labelText, fontSize = 13.sp, color = labelColor)
        }

        if (showDivider) {
            Divider(
                    color = dividerColor,
                    thickness = 0.5.dp,
                    modifier = Modifier.padding(start = 16.dp)
            )
        }
    }
}

@Composable
fun TelegramCopyField(value: String, fullValue: String, label: String, isDarkTheme: Boolean) {
    val textColor = if (isDarkTheme) Color.White else Color.Black
    val secondaryTextColor = if (isDarkTheme) Color(0xFF8E8E93) else Color(0xFF666666)
    val context = LocalContext.current
    val scope = rememberCoroutineScope()
    var showCopied by remember { mutableStateOf(false) }

    Column(
            modifier =
                    Modifier.fillMaxWidth()
                            .clickable {
                                val clipboard =
                                        context.getSystemService(Context.CLIPBOARD_SERVICE) as
                                                ClipboardManager
                                val clip = ClipData.newPlainText(label, fullValue)
                                clipboard.setPrimaryClip(clip)

                                scope.launch {
                                    showCopied = true
                                    delay(1500)
                                    showCopied = false
                                }
                            }
                            .padding(horizontal = 16.dp, vertical = 12.dp)
    ) {
        AnimatedContent(targetState = showCopied, label = "copy_animation") { copied ->
            Text(text = if (copied) "Copied!" else value, fontSize = 16.sp, color = textColor)
        }

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

        Text(text = label, fontSize = 13.sp, color = secondaryTextColor)
    }
}

@Composable
private fun TelegramSettingsItem(
        icon: Painter,
        title: String,
        onClick: () -> Unit,
        isDarkTheme: Boolean,
        showDivider: Boolean = false,
        subtitle: String? = null,
        iconTint: Color? = null
) {
    val textColor = if (isDarkTheme) Color.White else Color.Black
    val secondaryTextColor = if (isDarkTheme) Color(0xFF8E8E93) else Color(0xFF666666)
    val iconColor = iconTint ?: if (isDarkTheme) Color(0xFF8E8E93) else Color(0xFF666666)
    val dividerColor = if (isDarkTheme) Color(0xFF3A3A3A) else Color(0xFFE0E0E0)

    Column {
        Row(
                modifier =
                        Modifier.fillMaxWidth()
                                .clickable(onClick = onClick)
                                .padding(horizontal = 16.dp, vertical = 14.dp),
                verticalAlignment = Alignment.CenterVertically
        ) {
            Icon(
                    painter = icon,
                    contentDescription = null,
                    tint = iconColor,
                    modifier = Modifier.size(24.dp)
            )

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

            Column(modifier = Modifier.weight(1f)) {
                Text(text = title, fontSize = 16.sp, color = textColor)
                if (subtitle != null) {
                    Spacer(modifier = Modifier.height(2.dp))
                    Text(text = subtitle, fontSize = 13.sp, color = secondaryTextColor)
                }
            }
        }

        if (showDivider) {
            Divider(
                    color = dividerColor,
                    thickness = 0.5.dp,
                    modifier = Modifier.padding(start = 60.dp)
            )
        }
    }
}

@Composable
fun TelegramToggleItem(
        icon: Painter,
        title: String,
        subtitle: String? = null,
        isEnabled: Boolean,
        onToggle: () -> Unit,
        isDarkTheme: Boolean,
        showDivider: Boolean = false
) {
    val textColor = if (isDarkTheme) Color.White else Color.Black
    val secondaryTextColor = if (isDarkTheme) Color(0xFF8E8E93) else Color(0xFF666666)
    val iconColor = if (isDarkTheme) Color(0xFF8E8E93) else Color(0xFF666666)
    val accentColor = if (isDarkTheme) PrimaryBlueDark else Color(0xFF0D8CF4)
    val dividerColor = if (isDarkTheme) Color(0xFF3A3A3A) else Color(0xFFE0E0E0)

    Column {
        Row(
                modifier =
                        Modifier.fillMaxWidth()
                                .clickable(onClick = onToggle)
                                .padding(horizontal = 16.dp, vertical = 14.dp),
                verticalAlignment = Alignment.CenterVertically
        ) {
            Icon(
                    painter = icon,
                    contentDescription = null,
                    tint = iconColor,
                    modifier = Modifier.size(24.dp)
            )

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

            Column(modifier = Modifier.weight(1f)) {
                Text(text = title, fontSize = 16.sp, color = textColor)
                if (subtitle != null) {
                    Spacer(modifier = Modifier.height(2.dp))
                    Text(text = subtitle, fontSize = 13.sp, color = secondaryTextColor)
                }
            }

            // Telegram-style switch with outlined thumb
            val thumbOffset by animateFloatAsState(
                    targetValue = if (isEnabled) 1f else 0f,
                    animationSpec = tween(durationMillis = 200),
                    label = "thumb"
            )
            val trackColor by animateColorAsState(
                    targetValue = if (isEnabled) accentColor
                    else if (isDarkTheme) Color(0xFF5A5A5E) else Color(0xFF999999),
                    animationSpec = tween(durationMillis = 200),
                    label = "track"
            )
            val thumbBorderColor by animateColorAsState(
                    targetValue = if (isEnabled) accentColor
                    else if (isDarkTheme) Color(0xFF5A5A5E) else Color(0xFF999999),
                    animationSpec = tween(durationMillis = 200),
                    label = "thumbBorder"
            )

            val trackWidth = 38.dp
            val trackHeight = 22.dp
            val thumbSize = 26.dp
            val borderWidth = 2.dp
            val thumbTravel = trackWidth - thumbSize + borderWidth

            Box(
                    modifier = Modifier
                            .width(trackWidth)
                            .height(thumbSize)
                            .clickable(
                                    indication = null,
                                    interactionSource = remember { MutableInteractionSource() },
                                    onClick = onToggle
                            ),
                    contentAlignment = Alignment.CenterStart
            ) {
                // Track
                Box(
                        modifier = Modifier
                                .width(trackWidth)
                                .height(trackHeight)
                                .clip(RoundedCornerShape(trackHeight / 2))
                                .background(trackColor)
                                .align(Alignment.Center)
                )
                // Thumb with border
                Box(
                        modifier = Modifier
                                .offset(x = thumbTravel * thumbOffset)
                                .size(thumbSize)
                                .clip(CircleShape)
                                .background(thumbBorderColor)
                                .padding(borderWidth)
                                .clip(CircleShape)
                                .background(Color.White)
                )
            }
        }

        if (showDivider) {
            Divider(
                    color = dividerColor,
                    thickness = 0.5.dp,
                    modifier = Modifier.padding(start = 60.dp)
            )
        }
    }
}

@Composable
private fun TelegramBiometricItem(isEnabled: Boolean, onToggle: () -> Unit, isDarkTheme: Boolean) {
    TelegramToggleItem(
            icon = TelegramIcons.Fingerprint,
            title = "Biometric Authentication",
            isEnabled = isEnabled,
            onToggle = onToggle,
            isDarkTheme = isDarkTheme
    )
}

@Composable
private fun TelegramLogoutItem(onClick: () -> Unit, isDarkTheme: Boolean) {
    val redColor = if (isDarkTheme) Color(0xFFFF5555) else Color(0xFFFF3B30)

    Row(
            modifier =
                    Modifier.fillMaxWidth()
                            .clickable(onClick = onClick)
                            .padding(horizontal = 16.dp, vertical = 14.dp),
            verticalAlignment = Alignment.CenterVertically
    ) {
        Icon(
                painter = TelegramIcons.Leave,
                contentDescription = null,
                tint = redColor,
                modifier = Modifier.size(24.dp)
        )

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

        Text(text = "Log Out", fontSize = 16.sp, color = redColor)
    }
}

// ═════════════════════════════════════════════════════════════
// 📦 LEGACY COMPONENTS (kept for compatibility)
// ═════════════════════════════════════════════════════════════

@Composable
private fun ProfileSectionTitle(title: String, isDarkTheme: Boolean) {
    val textColor = if (isDarkTheme) Color(0xFF8E8E93) else Color(0xFF8E8E93)

    Text(
            text = title.uppercase(),
            fontSize = 13.sp,
            fontWeight = FontWeight.SemiBold,
            color = textColor,
            modifier = Modifier.padding(horizontal = 32.dp, vertical = 8.dp)
    )
}

@Composable
fun ProfileNavigationItem(
        icon: Painter,
        iconBackground: Color,
        title: String,
        subtitle: String,
        onClick: () -> Unit,
        isDarkTheme: Boolean,
        showDivider: Boolean = false,
        hideChevron: Boolean = false,
        textColor: Color? = null
) {
    val defaultTextColor = if (isDarkTheme) Color.White else Color.Black
    val secondaryTextColor = if (isDarkTheme) Color(0xFF8E8E93) else Color(0xFF666666)
    val iconTintColor = if (isDarkTheme) Color(0xFF8E8E93) else Color(0xFF666666)
    val dividerColor = if (isDarkTheme) Color(0xFF3A3A3A) else Color(0xFFE8E8E8)

    Column {
        Row(
                modifier =
                        Modifier.fillMaxWidth()
                                .clickable(onClick = onClick)
                                .padding(horizontal = 16.dp, vertical = 12.dp),
                verticalAlignment = Alignment.CenterVertically
        ) {
            Box(
                    modifier =
                            Modifier.size(36.dp)
                                    .clip(RoundedCornerShape(8.dp))
                                    .background(iconBackground),
                    contentAlignment = Alignment.Center
            ) {
                Icon(
                        painter = icon,
                        contentDescription = null,
                        tint = Color.White,
                        modifier = Modifier.size(20.dp)
                )
            }

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

            Column(modifier = Modifier.weight(1f)) {
                Text(
                        text = title,
                        fontSize = 16.sp,
                        color = textColor ?: defaultTextColor,
                        fontWeight = FontWeight.Medium
                )
                Spacer(modifier = Modifier.height(2.dp))
                Text(text = subtitle, fontSize = 13.sp, color = secondaryTextColor)
            }

            if (!hideChevron) {
                Icon(
                        imageVector = TablerIcons.ChevronRight,
                        contentDescription = null,
                        tint = iconTintColor.copy(alpha = 0.5f),
                        modifier = Modifier.size(20.dp)
                )
            }
        }

        if (showDivider) {
            Divider(
                    color = dividerColor,
                    thickness = 0.5.dp,
                    modifier = Modifier.padding(start = 68.dp)
            )
        }
    }
}

// ═════════════════════════════════════════════════════════════
// 🖼️ FULL SCREEN AVATAR VIEWER — Telegram style
// Long-press avatar → full screen with swipe-down to dismiss
// ═════════════════════════════════════════════════════════════
@Composable
@OptIn(androidx.compose.foundation.ExperimentalFoundationApi::class)
fun FullScreenAvatarViewer(
        isVisible: Boolean,
        onDismiss: () -> Unit,
        displayName: String,
        avatarTimestamp: Long,
        avatarBitmap: android.graphics.Bitmap?,
        publicKey: String,
        isDarkTheme: Boolean,
        avatarRepository: com.rosetta.messenger.repository.AvatarRepository? = null
) {
    val context = LocalContext.current
    val density = LocalDensity.current
    val screenHeight = with(density) { LocalConfiguration.current.screenHeightDp.dp.toPx() }

    var showContent by remember { mutableStateOf(false) }
    LaunchedEffect(isVisible) { showContent = isVisible }

    // Load avatar history
    var avatarHistory by remember { mutableStateOf(emptyList<com.rosetta.messenger.repository.AvatarInfo>()) }
    var decodedBitmaps by remember { mutableStateOf<Map<Int, android.graphics.Bitmap>>(emptyMap()) }

    LaunchedEffect(isVisible, publicKey) {
        if (isVisible && avatarRepository != null) {
            kotlinx.coroutines.withContext(kotlinx.coroutines.Dispatchers.IO) {
                val allAvatars = avatarRepository.getAvatars(publicKey, allDecode = true)
                val first = allAvatars.value
                if (first.isNotEmpty()) {
                    avatarHistory = first
                    val bitmaps = mutableMapOf<Int, android.graphics.Bitmap>()
                    first.forEachIndexed { idx, info ->
                        try {
                            val raw = info.base64Data
                            val base64 = if (raw.contains(",")) raw.substringAfter(",") else raw
                            val bytes = android.util.Base64.decode(base64, android.util.Base64.DEFAULT)
                            android.graphics.BitmapFactory.decodeByteArray(bytes, 0, bytes.size)?.let {
                                bitmaps[idx] = it
                            }
                        } catch (_: Exception) {}
                    }
                    decodedBitmaps = bitmaps
                }
            }
        }
    }

    val pageCount = if (avatarHistory.isNotEmpty()) avatarHistory.size else 1
    val pagerState = androidx.compose.foundation.pager.rememberPagerState(pageCount = { pageCount })

    // Current page timestamp
    val currentTimestamp = if (avatarHistory.isNotEmpty() && pagerState.currentPage in avatarHistory.indices) {
        avatarHistory[pagerState.currentPage].timestamp
    } else avatarTimestamp

    // Swipe-to-dismiss
    var dragOffsetY by remember { mutableFloatStateOf(0f) }
    var isDragging by remember { mutableStateOf(false) }
    val dismissThreshold = screenHeight * 0.25f

    val animatedAlpha by animateFloatAsState(
            targetValue = if (showContent) {
                val dragProgress = (kotlin.math.abs(dragOffsetY) / dismissThreshold).coerceIn(0f, 1f)
                1f - dragProgress * 0.6f
            } else 0f,
            animationSpec = tween(if (showContent && !isDragging) 250 else 200),
            label = "bg_alpha"
    )
    val animatedScale by animateFloatAsState(
            targetValue = if (showContent) {
                val dragProgress = (kotlin.math.abs(dragOffsetY) / dismissThreshold).coerceIn(0f, 1f)
                1f - dragProgress * 0.15f
            } else 0.8f,
            animationSpec = tween(if (showContent && !isDragging) 250 else 200),
            label = "scale"
    )
    val animatedOffset by animateFloatAsState(
            targetValue = if (isDragging) dragOffsetY else 0f,
            animationSpec = if (isDragging) spring(stiffness = Spring.StiffnessHigh)
                           else spring(dampingRatio = Spring.DampingRatioMediumBouncy),
            label = "offset",
            finishedListener = { if (!showContent) onDismiss() }
    )

    fun formatTimestamp(ts: Long): String {
        if (ts <= 0) return ""
        val sdf = SimpleDateFormat("MMMM d, yyyy 'at' h:mm a", Locale.ENGLISH)
        val ms = when {
            ts >= 1_000_000_000_000_000_000L -> ts / 1_000_000
            ts >= 1_000_000_000_000_000L -> ts / 1_000
            ts >= 1_000_000_000_000L -> ts
            else -> ts * 1_000
        }
        return sdf.format(Date(ms))
    }

    if (isVisible) {
        BackHandler { showContent = false }

        Box(
                modifier = Modifier
                        .fillMaxSize()
                        .graphicsLayer { alpha = animatedAlpha }
                        .background(Color.Black)
                        .pointerInput(Unit) {
                            detectVerticalDragGestures(
                                    onDragStart = { isDragging = true },
                                    onDragEnd = {
                                        isDragging = false
                                        if (kotlin.math.abs(dragOffsetY) > dismissThreshold) showContent = false
                                        dragOffsetY = 0f
                                    },
                                    onDragCancel = { isDragging = false; dragOffsetY = 0f },
                                    onVerticalDrag = { _, dragAmount -> dragOffsetY += dragAmount }
                            )
                        }
        ) {
            // Avatar pager
            Box(
                    modifier = Modifier
                            .fillMaxSize()
                            .graphicsLayer {
                                translationY = animatedOffset
                                scaleX = animatedScale
                                scaleY = animatedScale
                            },
                    contentAlignment = Alignment.Center
            ) {
                if (avatarHistory.size > 1) {
                    androidx.compose.foundation.pager.HorizontalPager(
                            state = pagerState,
                            modifier = Modifier.fillMaxSize(),
                            key = { it }
                    ) { page ->
                        Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
                            val bmp = decodedBitmaps[page]
                            if (bmp != null) {
                                Image(
                                        bitmap = bmp.asImageBitmap(),
                                        contentDescription = "Avatar ${page + 1}",
                                        modifier = Modifier.fillMaxWidth().aspectRatio(1f),
                                        contentScale = ContentScale.Crop
                                )
                            }
                        }
                    }
                } else if (avatarBitmap != null) {
                    Image(
                            bitmap = avatarBitmap.asImageBitmap(),
                            contentDescription = "Avatar",
                            modifier = Modifier.fillMaxWidth().aspectRatio(1f),
                            contentScale = ContentScale.Crop
                    )
                } else {
                    val avatarColors = getAvatarColor(publicKey, isDarkTheme)
                    Box(
                            modifier = Modifier.fillMaxWidth().aspectRatio(1f)
                                    .background(avatarColors.backgroundColor),
                            contentAlignment = Alignment.Center
                    ) {
                        Text(
                                text = getInitials(displayName.ifBlank { publicKey.take(6) }),
                                fontSize = 80.sp,
                                fontWeight = FontWeight.Bold,
                                color = avatarColors.textColor
                        )
                    }
                }
            }

            // Top gradient
            Box(modifier = Modifier.fillMaxWidth().height(120.dp).align(Alignment.TopCenter)
                    .background(Brush.verticalGradient(listOf(Color.Black.copy(alpha = 0.6f), Color.Transparent))))

            // Bottom gradient
            Box(modifier = Modifier.fillMaxWidth().height(120.dp).align(Alignment.BottomCenter)
                    .background(Brush.verticalGradient(listOf(Color.Transparent, Color.Black.copy(alpha = 0.6f)))))

            // Page indicator dots
            if (pageCount > 1) {
                Row(
                        modifier = Modifier.align(Alignment.TopCenter)
                                .statusBarsPadding()
                                .padding(top = 56.dp),
                        horizontalArrangement = Arrangement.spacedBy(4.dp)
                ) {
                    repeat(pageCount) { idx ->
                        Box(
                                modifier = Modifier
                                        .weight(1f)
                                        .height(2.dp)
                                        .background(
                                                if (idx == pagerState.currentPage) Color.White
                                                else Color.White.copy(alpha = 0.35f),
                                                RoundedCornerShape(1.dp)
                                        )
                        )
                    }
                }
            }

            // Header
            Row(
                    modifier = Modifier.fillMaxWidth().statusBarsPadding()
                            .padding(horizontal = 4.dp, vertical = 8.dp),
                    verticalAlignment = Alignment.CenterVertically
            ) {
                IconButton(onClick = { showContent = false }) {
                    Icon(imageVector = TablerIcons.ChevronLeft, contentDescription = "Close",
                            tint = Color.White, modifier = Modifier.size(24.dp))
                }
                Column(modifier = Modifier.weight(1f)) {
                    Text(text = displayName.ifBlank { publicKey.take(10) },
                            fontSize = 16.sp, fontWeight = FontWeight.SemiBold,
                            color = Color.White, maxLines = 1, overflow = TextOverflow.Ellipsis)
                    val dateText = formatTimestamp(currentTimestamp)
                    if (dateText.isNotEmpty()) {
                        Text(text = dateText, fontSize = 13.sp,
                                color = Color.White.copy(alpha = 0.7f), maxLines = 1)
                    }
                }
                IconButton(onClick = { /* menu */ }) {
                    Icon(painter = TelegramIcons.More, contentDescription = "Menu",
                            tint = Color.White, modifier = Modifier.size(24.dp))
                }
            }
        }
    }
}
