package com.rosetta.messenger.ui.chats.components

import android.Manifest
import android.app.Activity
import android.content.Intent
import android.content.ContentUris
import android.content.Context
import android.util.Log
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.provider.Settings
import android.provider.MediaStore
import android.view.WindowManager
import android.view.inputmethod.InputMethodManager
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.animation.*
import androidx.compose.animation.core.*
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.foundation.*
import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.gestures.detectVerticalDragGestures
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.grid.*
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.runtime.snapshotFlow
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.layout.positionInWindow
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.viewinterop.AndroidView
import androidx.compose.ui.window.Popup
import androidx.compose.ui.window.PopupProperties
import androidx.activity.compose.BackHandler
import androidx.camera.core.CameraSelector
import androidx.camera.core.Preview
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.camera.view.PreviewView
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.core.view.WindowCompat
import coil.compose.AsyncImage
import coil.request.ImageRequest
import compose.icons.TablerIcons
import compose.icons.tablericons.*
import com.rosetta.messenger.ui.icons.TelegramIcons
import com.rosetta.messenger.ui.onboarding.PrimaryBlue
import com.rosetta.messenger.ui.components.AppleEmojiTextField
import com.rosetta.messenger.ui.components.KeyboardHeightProvider
import com.rosetta.messenger.ui.components.OptimizedEmojiPicker
import com.rosetta.messenger.ui.utils.NavigationModeUtils
import app.rosette.android.ui.keyboard.rememberKeyboardTransitionCoordinator
import app.rosette.android.ui.keyboard.AnimatedKeyboardTransition
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlin.math.roundToInt

private const val TAG = "MediaPickerBottomSheet"
private const val ALL_MEDIA_ALBUM_ID = 0L

/**
 * Media item from gallery
 */
data class MediaItem(
    val id: Long,
    val uri: Uri,
    val mimeType: String,
    val duration: Long = 0, // For videos, in milliseconds
    val dateModified: Long = 0,
    val bucketId: Long = 0,
    val bucketName: String = ""
) {
    val isVideo: Boolean get() = mimeType.startsWith("video/")
}

data class MediaAlbum(
    val id: Long,
    val name: String,
    val items: List<MediaItem>,
    val isAllMedia: Boolean = false
)

/**
 * 📸 Telegram-style Media Picker - INLINE OVERLAY
 * 
 * Ключевое отличие от обычного BottomSheet:
 * - Это НЕ Dialog, а обычный Composable который рендерится ВНУТРИ того же layout
 * - Позиционируется ПОВЕРХ клавиатуры с помощью imePadding()
 * - Клавиатура остаётся открытой!
 */
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MediaPickerBottomSheet(
    isVisible: Boolean,
    onDismiss: () -> Unit,
    isDarkTheme: Boolean,
    onMediaSelected: (List<MediaItem>, String) -> Unit,
    onMediaSelectedWithCaption: ((MediaItem, String) -> Unit)? = null,
    onOpenCamera: () -> Unit = {},
    onOpenFilePicker: () -> Unit = {},
    onAvatarClick: () -> Unit = {},
    currentUserPublicKey: String = "",
    maxSelection: Int = 10,
    recipientName: String? = null,
    onPhotoPreviewRequested: ((Uri, ThumbnailPosition?, List<Uri>, Int) -> Unit)? = null
) {
    val context = LocalContext.current
    val hasNativeNavigationBar = remember(context) {
        NavigationModeUtils.hasNativeNavigationBar(context)
    }
    val scope = rememberCoroutineScope()
    val density = LocalDensity.current
    val imeInsets = WindowInsets.ime
    val focusManager = LocalFocusManager.current
    val keyboardView = LocalView.current

    // Function to hide keyboard
    fun hideKeyboard() {
        focusManager.clearFocus(force = true)
        keyboardView.findFocus()?.clearFocus()
        val activity = context as? Activity
        activity?.currentFocus?.clearFocus()
        val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
        val servedToken =
            activity?.currentFocus?.windowToken
                ?: keyboardView.findFocus()?.windowToken
                ?: keyboardView.windowToken
        imm.hideSoftInputFromWindow(servedToken, 0)
        imm.hideSoftInputFromWindow(servedToken, InputMethodManager.HIDE_NOT_ALWAYS)
        activity?.window?.let { win ->
            WindowCompat.getInsetsController(win, keyboardView)
                .hide(androidx.core.view.WindowInsetsCompat.Type.ime())
        }
    }
    
    // Media items from gallery
    var mediaItems by remember { mutableStateOf<List<MediaItem>>(emptyList()) }
    var mediaAlbums by remember { mutableStateOf<List<MediaAlbum>>(emptyList()) }
    var selectedAlbumId by remember { mutableLongStateOf(ALL_MEDIA_ALBUM_ID) }
    var isLoading by remember { mutableStateOf(true) }
    var hasPermission by remember { mutableStateOf(false) }
    
    // Selected items in selection order (Telegram-style)
    var selectedItemOrder by remember { mutableStateOf<List<Long>>(emptyList()) }
    
    // Editor state - when user taps on a photo, open editor
    var editingItem by remember { mutableStateOf<MediaItem?>(null) }
    
    // 📍 Позиция thumbnail для Telegram-style анимации
    var thumbnailPosition by remember { mutableStateOf<ThumbnailPosition?>(null) }
    
    // Uri фото, только что сделанного с камеры (для редактирования)
    var pendingPhotoUri by remember { mutableStateOf<Uri?>(null) }
    
    // Uri отредактированного фото (для предпросмотра с caption)
    var previewPhotoUri by remember { mutableStateOf<Uri?>(null) }
    
    // Caption для фото
    var photoCaption by remember { mutableStateOf("") }

    // Caption для группы фото (внизу picker'а)
    var pickerCaption by remember { mutableStateOf("") }
    var captionEditTextView by remember { mutableStateOf<com.rosetta.messenger.ui.components.AppleEmojiEditTextView?>(null) }

    fun resetPickerCaptionInput() {
        pickerCaption = ""
        captionEditTextView?.clearFocus()
    }

    fun focusCaptionInput() {
        captionEditTextView?.let { view ->
            view.requestFocus()
            view.post {
                val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
                imm.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT)
            }
        }
    }

    fun resolveSelectedMedia(): List<MediaItem> {
        if (selectedItemOrder.isEmpty()) return emptyList()
        val byId = mediaItems.associateBy { it.id }
        return selectedItemOrder.mapNotNull { byId[it] }
    }

    val selectedAlbum =
        remember(mediaAlbums, selectedAlbumId) {
            mediaAlbums.firstOrNull { it.id == selectedAlbumId } ?: mediaAlbums.firstOrNull()
        }
    val visibleMediaItems = selectedAlbum?.items ?: mediaItems
    val canSwitchAlbums = mediaAlbums.size > 1

    fun toggleSelection(itemId: Long) {
        selectedItemOrder =
            if (selectedItemOrder.contains(itemId)) {
                selectedItemOrder.filterNot { it == itemId }
            } else if (selectedItemOrder.size < maxSelection) {
                selectedItemOrder + itemId
            } else {
                selectedItemOrder
            }
    }

    val mediaPermissions = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
        arrayOf(
            Manifest.permission.READ_MEDIA_IMAGES,
            Manifest.permission.READ_MEDIA_VIDEO
        )
    } else {
        arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE)
    }
    var mediaPermissionRequestedOnce by rememberSaveable { mutableStateOf(false) }

    // Permission launcher
    val permissionLauncher = rememberLauncherForActivityResult(
        contract = ActivityResultContracts.RequestMultiplePermissions()
    ) { permissions ->
        hasPermission = mediaPermissions.all { permissions[it] == true }
        if (hasPermission) {
            scope.launch {
                val loaded = loadMediaPickerData(context)
                mediaItems = loaded.items
                mediaAlbums = loaded.albums
                selectedAlbumId = loaded.albums.firstOrNull()?.id ?: ALL_MEDIA_ALBUM_ID
                isLoading = false
            }
        }
    }

    fun requestMediaPermissions() {
        val deniedPermissions = mediaPermissions.filter {
            ContextCompat.checkSelfPermission(context, it) != PackageManager.PERMISSION_GRANTED
        }
        if (deniedPermissions.isEmpty()) {
            hasPermission = true
            return
        }

        val activity = context as? Activity
        val permanentlyDenied = activity != null &&
            mediaPermissionRequestedOnce &&
            deniedPermissions.all { permission ->
                !ActivityCompat.shouldShowRequestPermissionRationale(activity, permission)
            }

        if (permanentlyDenied) {
            val intent = Intent(
                Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
                Uri.fromParts("package", context.packageName, null)
            ).apply {
                addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
            }
            context.startActivity(intent)
            return
        }

        mediaPermissionRequestedOnce = true
        permissionLauncher.launch(mediaPermissions)
    }
    
    // Check permission on show
    LaunchedEffect(isVisible) {
        if (isVisible) {
            // Reset selection when opening
            selectedItemOrder = emptyList()
            resetPickerCaptionInput()
            selectedAlbumId = ALL_MEDIA_ALBUM_ID
            
            hasPermission = mediaPermissions.all {
                ContextCompat.checkSelfPermission(context, it) == PackageManager.PERMISSION_GRANTED 
            }
            
            if (hasPermission) {
                isLoading = true
                val loaded = loadMediaPickerData(context)
                mediaItems = loaded.items
                mediaAlbums = loaded.albums
                selectedAlbumId = loaded.albums.firstOrNull()?.id ?: ALL_MEDIA_ALBUM_ID
                isLoading = false
            } else {
                requestMediaPermissions()
            }
        }
    }
    
    // Colors
    val backgroundColor = if (isDarkTheme) Color(0xFF1C1C1E) else Color(0xFFFFFFFF)
    val surfaceColor = if (isDarkTheme) Color(0xFF2C2C2E) else Color(0xFFF2F2F7)
    val textColor = if (isDarkTheme) Color.White else Color.Black
    val secondaryTextColor = if (isDarkTheme) Color(0xFF8E8E93) else Color(0xFF8E8E93)
    
    // ═══════════════════════════════════════════════════════════════
    // 🎬 TELEGRAM-STYLE: Popup поверх клавиатуры с анимацией
    // ═══════════════════════════════════════════════════════════════
    val configuration = LocalConfiguration.current
    val screenHeight = configuration.screenHeightDp.dp
    val screenHeightPx = with(density) { screenHeight.toPx() }
    val navigationBarInsetPx = if (hasNativeNavigationBar) {
        WindowInsets.navigationBars.getBottom(density).toFloat()
    } else {
        0f
    }
    val statusBarInsetPx = WindowInsets.statusBars.getTop(density).toFloat()

    // 🔄 Высоты в пикселях для точного контроля
    val collapsedHeightPx = screenHeightPx * 0.50f  // Свёрнутое - 50% экрана (легче тянуть дальше вверх)
    val expandedHeightPx =
        (screenHeightPx + statusBarInsetPx).coerceAtLeast(screenHeightPx * 0.95f)
    val minHeightPx = screenHeightPx * 0.2f         // Минимум при свайпе вниз
    val captionLiftEasing = CubicBezierEasing(0f, 0f, 0.2f, 1f)
    val telegramButtonsEasing = CubicBezierEasing(0f, 0f, 0.58f, 1f)
    val collapsedStateHeightPx = collapsedHeightPx.coerceAtMost(expandedHeightPx)
    val selectionHeaderExtraPx = with(density) { 26.dp.toPx() } // Telegram: 26dp header offset
    val captionBarProgress by animateFloatAsState(
        targetValue = if (selectedItemOrder.isNotEmpty()) 1f else 0f,
        animationSpec = tween(180, easing = captionLiftEasing),
        label = "caption_bar_progress"
    )
    
    // 🎬 Animatable для плавной высоты - КЛЮЧЕВОЙ ЭЛЕМЕНТ
    val sheetHeightPx = remember { Animatable(collapsedHeightPx) }
    var dragSheetHeightPx by remember { mutableFloatStateOf(Float.NaN) }
    val interactiveSheetHeightPx by remember {
        derivedStateOf {
            if (dragSheetHeightPx.isNaN()) sheetHeightPx.value else dragSheetHeightPx
        }
    }
    
    // Текущее состояние (для логики)
    var isExpanded by remember { mutableStateOf(false) }
    
    // 🎬 Анимация появления/закрытия
    var isClosing by remember { mutableStateOf(false) }
    var shouldShow by remember { mutableStateOf(false) }
    var closeAction by remember { mutableStateOf<(() -> Unit)?>(null) }
    var showDiscardSelectionDialog by remember { mutableStateOf(false) }
    var pendingDismissAfterConfirm by remember { mutableStateOf<(() -> Unit)?>(null) }
    var hadSelection by remember { mutableStateOf(false) }
    var isCaptionKeyboardVisible by remember { mutableStateOf(false) }
    var showAlbumMenu by remember { mutableStateOf(false) }
    var imeBottomInsetPx by remember { mutableIntStateOf(0) }
    
    // Scope для анимаций
    val animationScope = rememberCoroutineScope()
    
    // Анимация slide для появления/закрытия
    val animatedOffset by animateFloatAsState(
        targetValue = if (shouldShow && !isClosing) 0f else 1f,
        animationSpec = if (isClosing) {
            tween(200, easing = FastOutSlowInEasing)
        } else {
            tween(280, easing = FastOutSlowInEasing)
        },
        finishedListener = { 
            if (isClosing) {
                isClosing = false
                shouldShow = false
                isExpanded = false
                val action = closeAction
                closeAction = null
                // Сбрасываем высоту
                animationScope.launch {
                    dragSheetHeightPx = Float.NaN
                    sheetHeightPx.snapTo(collapsedHeightPx)
                }
                action?.invoke()
                onDismiss()
            }
        },
        label = "sheet_slide"
    )
    
    // 🌑 Плавное затемнение экрана (включая статус бар)
    // Мягкий fade-in вместо резкого черного overlay
    val scrimAlpha by animateFloatAsState(
        targetValue = if (shouldShow && !isClosing) {
            // Базовое затемнение + немного больше когда развёрнуто
            val expandRange = (expandedHeightPx - collapsedStateHeightPx).coerceAtLeast(1f)
            val expandProgress = (interactiveSheetHeightPx - collapsedStateHeightPx) / expandRange
            0.25f + 0.15f * expandProgress.coerceIn(0f, 1f)
        } else {
            0f
        },
        animationSpec = tween(
            durationMillis = if (isClosing) 200 else 300,
            easing = FastOutSlowInEasing
        ),
        label = "scrim_fade"
    )
    
    // Показываем галерею (но НЕ когда редактируем фото)
    val showSheet = isVisible && pendingPhotoUri == null && previewPhotoUri == null
    val mediaGridState = rememberLazyGridState()
    
    // Запускаем анимацию когда showSheet меняется
    LaunchedEffect(showSheet) {
        if (showSheet && editingItem == null) {
            // Ensure IME from chat is closed before picker opens.
            hideKeyboard()
            delay(16)
            shouldShow = true
            isClosing = false
            showAlbumMenu = false
            dragSheetHeightPx = Float.NaN
            sheetHeightPx.snapTo(collapsedStateHeightPx)
        }
    }

    // Плавно синхронизируем высоту sheet с UI выбора (caption + send) в collapsed-состоянии.
    // When items are selected, the sheet grows UPWARD by 26dp to reveal the "N photos selected" header.
    LaunchedEffect(showSheet, selectedItemOrder.isNotEmpty(), isExpanded, isClosing, editingItem, dragSheetHeightPx) {
        if (showSheet && editingItem == null && !isClosing && !isExpanded && dragSheetHeightPx.isNaN()) {
            val targetHeight = if (selectedItemOrder.isNotEmpty()) {
                collapsedStateHeightPx + selectionHeaderExtraPx
            } else {
                collapsedStateHeightPx
            }
            if (kotlin.math.abs(interactiveSheetHeightPx - targetHeight) > 1f) {
                sheetHeightPx.stop()
                sheetHeightPx.animateTo(
                    targetHeight,
                    animationSpec = tween(180, easing = captionLiftEasing)
                )
            }
        }
    }

    LaunchedEffect(showSheet) {
        if (showSheet) {
            snapshotFlow { imeInsets.getBottom(density) }
                .collect { imeBottom ->
                    imeBottomInsetPx = imeBottom
                    isCaptionKeyboardVisible = imeBottom > 0
                }
        } else {
            imeBottomInsetPx = 0
            isCaptionKeyboardVisible = false
        }
    }

    LaunchedEffect(selectedAlbumId) {
        mediaGridState.scrollToItem(0)
    }

    // Telegram behavior: when selection is fully cleared, caption input closes with keyboard.
    LaunchedEffect(selectedItemOrder.size) {
        if (selectedItemOrder.isNotEmpty()) {
            hadSelection = true
        } else if (hadSelection) {
            hadSelection = false
            hideKeyboard()
        }
    }
    
    // Закрываем popup когда переходим к редактору
    LaunchedEffect(editingItem) {
        if (editingItem != null) {
            // Галерея уже скрылась, скрываем popup
            shouldShow = false
        }
    }
    
    // Функция для анимированного закрытия.
    // afterClose важен для camera flow: сначала полностью закрываем sheet, потом открываем камеру.
    fun animatedClose(afterClose: (() -> Unit)? = null) {
        if (afterClose != null) {
            closeAction = afterClose
        }
        if (!isClosing) {
            isClosing = true
        }
    }

    fun requestClose(afterClose: (() -> Unit)? = null) {
        if (selectedItemOrder.isNotEmpty()) {
            pendingDismissAfterConfirm = afterClose
            showDiscardSelectionDialog = true
            return
        }
        animatedClose(afterClose)
    }
    
    // Функция snap к ближайшему состоянию с плавной анимацией
    // Используем velocity для определения направления
    fun snapToNearestState(velocity: Float = 0f) {
        animationScope.launch {
            val currentHeight = interactiveSheetHeightPx
            if (!dragSheetHeightPx.isNaN()) {
                sheetHeightPx.stop()
                sheetHeightPx.snapTo(currentHeight)
                dragSheetHeightPx = Float.NaN
            }
            
            // Пороги основаны на velocity (скорости свайпа) - не на позиции!
            // velocity < 0 = свайп вверх, velocity > 0 = свайп вниз
            val velocityThreshold = 180f // Более низкий порог: легче раскрыть sheet свайпом вверх
            val expandSnapThreshold =
                collapsedStateHeightPx + (expandedHeightPx - collapsedStateHeightPx) * 0.35f
            
            when {
                // Быстрый свайп вниз при минимальной высоте - закрываем
                velocity > velocityThreshold && currentHeight < collapsedStateHeightPx -> {
                    requestClose()
                }
                // Слишком низко - закрываем
                currentHeight < minHeightPx + 30 -> {
                    requestClose()
                }
                // Быстрый свайп вверх - разворачиваем
                velocity < -velocityThreshold -> {
                    isExpanded = true
                    sheetHeightPx.animateTo(
                        expandedHeightPx,
                        animationSpec = spring(
                            dampingRatio = Spring.DampingRatioLowBouncy,
                            stiffness = Spring.StiffnessMediumLow
                        )
                    )
                }
                // Быстрый свайп вниз - сворачиваем (или закрываем если уже свёрнут)
                velocity > velocityThreshold -> {
                    if (isExpanded) {
                        isExpanded = false
                        sheetHeightPx.animateTo(
                            collapsedStateHeightPx,
                            animationSpec = spring(
                                dampingRatio = Spring.DampingRatioLowBouncy,
                                stiffness = Spring.StiffnessMediumLow
                            )
                        )
                    } else {
                        requestClose()
                    }
                }
                // Без velocity - snap к ближайшему
                currentHeight > expandSnapThreshold -> {
                    isExpanded = true
                    sheetHeightPx.animateTo(
                        expandedHeightPx,
                        animationSpec = spring(
                            dampingRatio = Spring.DampingRatioLowBouncy,
                            stiffness = Spring.StiffnessMediumLow
                        )
                    )
                }
                else -> {
                    isExpanded = false
                    sheetHeightPx.animateTo(
                        collapsedStateHeightPx,
                        animationSpec = spring(
                            dampingRatio = Spring.DampingRatioLowBouncy,
                            stiffness = Spring.StiffnessMediumLow
                        )
                    )
                }
            }
        }
    }
    
    // 🎨 Статус бар и навигейшн бар — единый источник правды
    val view = LocalView.current

    val insetsController = remember(view) {
        val window = (view.context as? android.app.Activity)?.window
        window?.let { WindowCompat.getInsetsController(it, view) }
    }

    // Fullscreen state derived from sheet height (available at top level)
    val isPickerFullScreen by remember {
        derivedStateOf {
            val expandRange = (expandedHeightPx - collapsedStateHeightPx).coerceAtLeast(1f)
            val progress = ((interactiveSheetHeightPx - collapsedStateHeightPx) / expandRange).coerceIn(0f, 1f)
            progress > 0.9f
        }
    }

    // Save originals ONCE when picker opens, restore on close
    DisposableEffect(shouldShow) {
        if (shouldShow && !view.isInEditMode) {
            val window = (view.context as? android.app.Activity)?.window
            val origStatusBarColor = window?.statusBarColor ?: 0
            val origNavBarColor = window?.navigationBarColor ?: 0
            val origLightNav = insetsController?.isAppearanceLightNavigationBars ?: true
            val origLightStatus = insetsController?.isAppearanceLightStatusBars ?: false
            val origContrastEnforced =
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                    window?.isNavigationBarContrastEnforced
                } else {
                    null
                }

            onDispose {
                window?.statusBarColor = origStatusBarColor
                window?.navigationBarColor = origNavBarColor
                insetsController?.isAppearanceLightNavigationBars = origLightNav
                insetsController?.isAppearanceLightStatusBars = origLightStatus
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && origContrastEnforced != null) {
                    window?.isNavigationBarContrastEnforced = origContrastEnforced
                }
            }
        } else {
            onDispose { }
        }
    }

    // Telegram-style: system bar updates only by picker state,
    // no per-frame status bar color animation.
    LaunchedEffect(
        shouldShow,
        editingItem,
        isPickerFullScreen,
        isDarkTheme,
        hasNativeNavigationBar
    ) {
        if (!shouldShow || editingItem != null) return@LaunchedEffect
        val window = (view.context as? android.app.Activity)?.window ?: return@LaunchedEffect
        val dark = isDarkTheme
        val fullScreen = isPickerFullScreen

        if (hasNativeNavigationBar) {
            val navBaseColor = if (dark) 0xFF1C1C1E.toInt() else 0xFFFFFFFF.toInt()
            window.navigationBarColor = navBaseColor
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                window.isNavigationBarContrastEnforced = true
            }
            insetsController?.isAppearanceLightNavigationBars = !dark
        } else {
            window.navigationBarColor = android.graphics.Color.TRANSPARENT
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                window.isNavigationBarContrastEnforced = false
            }
            insetsController?.isAppearanceLightNavigationBars = !dark
        }

        // Telegram-like natural dim: status-bar tint follows picker scrim alpha.
        if (fullScreen) {
            window.statusBarColor = if (dark) 0xFF1C1C1E.toInt() else 0xFFFFFFFF.toInt()
            insetsController?.isAppearanceLightStatusBars = false
        } else {
            insetsController?.isAppearanceLightStatusBars = false
            var lastAppliedAlpha = -1
            snapshotFlow { (scrimAlpha * 255f).toInt().coerceIn(0, 255) }
                .collect { alpha ->
                    if (alpha != lastAppliedAlpha) {
                        lastAppliedAlpha = alpha
                        window.statusBarColor = android.graphics.Color.argb(alpha, 0, 0, 0)
                    }
                }
        }
    }
    
    // Используем Popup для показа поверх клавиатуры
    if (shouldShow && editingItem == null) {
        // BackHandler для закрытия по back
        BackHandler { 
            if (isExpanded) {
                animationScope.launch {
                    isExpanded = false
                    sheetHeightPx.animateTo(
                        collapsedStateHeightPx,
                        animationSpec = tween(250, easing = FastOutSlowInEasing)
                    )
                }
            } else {
                requestClose()
            }
        }
        
        Popup(
            alignment = Alignment.TopStart, // Начинаем с верха чтобы покрыть весь экран
            onDismissRequest = { requestClose() },
            properties = PopupProperties(
                focusable = true,
                dismissOnBackPress = true,
                dismissOnClickOutside = false
            )
        ) {
            // With enableEdgeToEdge() + focusable Popup, the system resizes the Popup
            // window when the keyboard opens (adjustResize). So we only need navBar padding.
            // However, the sheet has a FIXED pixel height that doesn't adapt to the smaller
            // viewport — we must subtract keyboard from the visible sheet height so the
            // caption bar stays visible. The grid (weight=1f) absorbs the shrinkage.
            val keyboardInsetPx =
                (imeBottomInsetPx.toFloat() - navigationBarInsetPx).coerceAtLeast(0f)
            val appliedKeyboardInsetPx =
                if (selectedItemOrder.isNotEmpty()) keyboardInsetPx else 0f
            val navInsetPxForSheet = if (appliedKeyboardInsetPx > 0f) 0f else navigationBarInsetPx
            val navInsetDpForSheet = with(density) { navInsetPxForSheet.toDp() }

            // Полноэкранный контейнер с мягким затемнением
            // background BEFORE padding — scrim covers area behind keyboard too
            Box(
                modifier = Modifier
                    .fillMaxSize()
                    .background(Color.Black.copy(alpha = scrimAlpha))
                    .clickable(
                        interactionSource = remember { MutableInteractionSource() },
                        indication = null
                    ) { requestClose() },
                contentAlignment = Alignment.BottomCenter
            ) {
                // Subtract keyboard from sheet height so it fits in the resized viewport.
                // The grid (weight=1f) shrinks; caption bar stays at the bottom edge.
                val visibleSheetHeightPx =
                    (interactiveSheetHeightPx - appliedKeyboardInsetPx + navInsetPxForSheet)
                        .coerceAtLeast(minHeightPx)
                val currentHeightDp = with(density) { visibleSheetHeightPx.toDp() }
                val slideOffset = (visibleSheetHeightPx * animatedOffset).toInt()
                val expandProgress =
                    ((interactiveSheetHeightPx - collapsedStateHeightPx) /
                        (expandedHeightPx - collapsedStateHeightPx).coerceAtLeast(1f))
                        .coerceIn(0f, 1f)
                val topCornerRadius by animateDpAsState(
                    targetValue = 16.dp * (1f - expandProgress),
                    animationSpec = tween(180, easing = FastOutSlowInEasing),
                    label = "sheet_top_corner_radius"
                )
                val handleAlpha by animateFloatAsState(
                    targetValue = (1f - expandProgress * 1.35f).coerceIn(0f, 1f),
                    animationSpec = tween(160, easing = FastOutSlowInEasing),
                    label = "sheet_handle_alpha"
                )

                // Отслеживаем velocity для плавного snap
                var lastDragVelocity by remember { mutableFloatStateOf(0f) }

                Box(
                    modifier = Modifier
                        .fillMaxWidth()
                        .height(currentHeightDp)
                        .offset { IntOffset(0, slideOffset) }
                        .graphicsLayer {
                            // Scale эффект только при появлении/закрытии
                            val scale = 0.95f + 0.05f * (1f - animatedOffset)
                            scaleX = scale
                            scaleY = scale
                            alpha = 0.9f + 0.1f * (1f - animatedOffset)
                        }
                        .clip(RoundedCornerShape(topStart = topCornerRadius, topEnd = topCornerRadius))
                        .background(backgroundColor)
                        .clickable(
                            interactionSource = remember { MutableInteractionSource() },
                            indication = null
                        ) { /* Prevent click through */ }
                        .pointerInput(Unit) {
                            detectVerticalDragGestures(
                                onDragStart = {
                                    animationScope.launch { sheetHeightPx.stop() }
                                    dragSheetHeightPx = interactiveSheetHeightPx
                                },
                                onDragCancel = {
                                    snapToNearestState()
                                    lastDragVelocity = 0f
                                },
                                onDragEnd = {
                                    // Snap с учётом velocity
                                    snapToNearestState(lastDragVelocity)
                                    lastDragVelocity = 0f
                                },
                                onVerticalDrag = { change, dragAmount ->
                                    change.consume()
                                    // Для подъёма вверх усиливаем жест, вниз делаем немного мягче.
                                    val adjustedDragAmount =
                                        if (dragAmount < 0f) dragAmount * 1.25f else dragAmount * 0.9f
                                    lastDragVelocity = adjustedDragAmount * 1.8f

                                    // 🔥 Меняем высоту в реальном времени
                                    val newHeight = (interactiveSheetHeightPx - adjustedDragAmount)
                                        .coerceIn(minHeightPx, expandedHeightPx)
                                    dragSheetHeightPx = newHeight
                                }
                            )
                        }
                ) {
                Column(modifier = Modifier.fillMaxSize()) {
                    // ═══════════════════════════════════════════════════════
                    // TELEGRAM-STYLE HEADER: drag handle → collapsed title → expanded actionbar
                    // Like ChatAttachAlertPhotoLayout: actionBar alpha goes 0→1 on expand,
                    // dropdown shows album name + chevron, "N photos selected" on selection.
                    // ═══════════════════════════════════════════════════════

                    val statusBarTopPadding = WindowInsets.statusBars.asPaddingValues().calculateTopPadding()
                    val currentAlbumTitle =
                        if (selectedAlbum?.isAllMedia != false) "Gallery"
                        else selectedAlbum?.name ?: "Gallery"

                    val fullScreenHeaderProgress by animateFloatAsState(
                        targetValue = if (expandProgress > 0.94f) 1f else 0f,
                        animationSpec = tween(170, easing = FastOutSlowInEasing),
                        label = "gallery_fullscreen_header_progress"
                    )
                    val collapsedHeaderAlpha = (1f - fullScreenHeaderProgress).coerceIn(0f, 1f)
                    val selectedCount = selectedItemOrder.size

                    // ── Collapsed header: drag handle + selection text ──
                    // Like Telegram: when photos are selected, a "N photo(s) selected"
                    // label appears below the handle, pushing the grid down by 26dp.

                    // Build selection text like Telegram: photo / video / media
                    val selectionHeaderText = remember(selectedItemOrder, mediaItems) {
                        val count = selectedItemOrder.size
                        if (count == 0) ""
                        else {
                            val byId = mediaItems.associateBy { it.id }
                            val selected = selectedItemOrder.mapNotNull { byId[it] }
                            val hasPhotos = selected.any { !it.isVideo }
                            val hasVideos = selected.any { it.isVideo }
                            when {
                                hasPhotos && hasVideos -> if (count == 1) "$count media selected" else "$count media selected"
                                hasVideos -> if (count == 1) "$count video selected" else "$count videos selected"
                                else -> if (count == 1) "$count photo selected" else "$count photos selected"
                            }
                        }
                    }
                    // Header height is DERIVED from how much the sheet has grown
                    // beyond collapsedStateHeightPx — perfectly in sync, no jerk.
                    val selectionHeaderHeightPx = if (!isExpanded) {
                        (interactiveSheetHeightPx - collapsedStateHeightPx)
                            .coerceIn(0f, selectionHeaderExtraPx)
                    } else 0f
                    val selectionHeaderHeightDp = with(density) { selectionHeaderHeightPx.toDp() }
                    val selectionHeaderAlpha = (selectionHeaderHeightPx / selectionHeaderExtraPx).coerceIn(0f, 1f)

                    Column(
                        modifier = Modifier
                            .fillMaxWidth()
                            .graphicsLayer { alpha = collapsedHeaderAlpha }
                    ) {
                        // Drag handle
                        Column(
                            modifier = Modifier.fillMaxWidth(),
                            horizontalAlignment = Alignment.CenterHorizontally
                        ) {
                            Spacer(modifier = Modifier.height(8.dp))
                            Box(
                                modifier = Modifier
                                    .width(36.dp)
                                    .height(4.dp)
                                    .graphicsLayer { alpha = handleAlpha }
                                    .clip(RoundedCornerShape(2.dp))
                                    .background(secondaryTextColor.copy(alpha = 0.3f))
                            )
                            Spacer(modifier = Modifier.height(6.dp))
                        }

                        // "N photo(s) selected" — height derived from sheet growth, always in layout
                        Box(
                            modifier = Modifier
                                .fillMaxWidth()
                                .height(selectionHeaderHeightDp)
                                .graphicsLayer {
                                    alpha = selectionHeaderAlpha
                                    clip = true
                                },
                            contentAlignment = Alignment.CenterStart
                        ) {
                            if (selectionHeaderAlpha > 0.01f) {
                                Text(
                                    text = selectionHeaderText,
                                    color = textColor,
                                    fontSize = 16.sp,
                                    fontWeight = FontWeight.Bold,
                                    maxLines = 1,
                                    modifier = Modifier.padding(start = 23.dp)
                                )
                            }
                        }
                    }

                    // ── Expanded actionbar: statusbar padding + back + title ──
                    val fullScreenHeaderHeight = (statusBarTopPadding + 52.dp) * fullScreenHeaderProgress
                    Box(
                        modifier = Modifier
                            .fillMaxWidth()
                            .height(fullScreenHeaderHeight)
                            .graphicsLayer { clip = true }
                    ) {
                        if (fullScreenHeaderProgress > 0.001f) {
                            val headerTranslationY = with(density) { (1f - fullScreenHeaderProgress) * (-14).dp.toPx() }
                            Row(
                                modifier = Modifier
                                    .fillMaxWidth()
                                    .padding(top = statusBarTopPadding, start = 4.dp, end = 8.dp)
                                    .graphicsLayer {
                                        alpha = fullScreenHeaderProgress
                                        translationY = headerTranslationY
                                    },
                                verticalAlignment = Alignment.CenterVertically
                            ) {
                                IconButton(
                                    onClick = { requestClose() },
                                    modifier = Modifier.size(40.dp)
                                ) {
                                    Icon(
                                        imageVector = TablerIcons.ChevronLeft,
                                        contentDescription = "Close gallery",
                                        tint = textColor
                                    )
                                }

                                // Crossfade between album dropdown and selection indicator
                                Box(modifier = Modifier.weight(1f)) {
                                    androidx.compose.animation.AnimatedContent(
                                        targetState = selectedCount > 0,
                                        transitionSpec = {
                                            fadeIn(tween(160)) togetherWith fadeOut(tween(160))
                                        },
                                        label = "expanded_header_title"
                                    ) { hasSelection ->
                                        if (hasSelection) {
                                            Text(
                                                text = when (selectedCount) {
                                                    1 -> "1 photo selected"
                                                    else -> "$selectedCount photos selected"
                                                },
                                                color = textColor,
                                                fontSize = 19.sp,
                                                fontWeight = FontWeight.SemiBold,
                                                maxLines = 1
                                            )
                                        } else {
                                            Row(
                                                modifier = Modifier
                                                    .clip(RoundedCornerShape(18.dp))
                                                    .clickable(
                                                        enabled = canSwitchAlbums,
                                                        interactionSource = remember { MutableInteractionSource() },
                                                        indication = null
                                                    ) {
                                                        if (canSwitchAlbums) showAlbumMenu = true
                                                    }
                                                    .padding(horizontal = 6.dp, vertical = 6.dp),
                                                verticalAlignment = Alignment.CenterVertically
                                            ) {
                                                Text(
                                                    text = currentAlbumTitle,
                                                    color = textColor,
                                                    fontSize = 19.sp,
                                                    fontWeight = FontWeight.SemiBold,
                                                    maxLines = 1
                                                )
                                                if (canSwitchAlbums) {
                                                    Spacer(modifier = Modifier.width(2.dp))
                                                    Icon(
                                                        imageVector = TablerIcons.ChevronDown,
                                                        contentDescription = null,
                                                        tint = textColor.copy(alpha = 0.7f),
                                                        modifier = Modifier.size(18.dp)
                                                    )
                                                }
                                            }
                                        }
                                    }

                                    // Album dropdown (expanded mode)
                                    AlbumDropdownMenu(
                                        expanded = showAlbumMenu && canSwitchAlbums && fullScreenHeaderProgress > 0.5f,
                                        onDismissRequest = { showAlbumMenu = false },
                                        albums = mediaAlbums,
                                        selectedAlbumId = selectedAlbumId,
                                        onAlbumSelected = { albumId ->
                                            selectedAlbumId = albumId
                                            showAlbumMenu = false
                                        },
                                        isDarkTheme = isDarkTheme,
                                        textColor = textColor,
                                        secondaryTextColor = secondaryTextColor
                                    )
                                }
                            }
                        }
                    }
                    
                    // Content
                    if (!hasPermission) {
                        // Permission request UI
                        PermissionRequestView(
                            isDarkTheme = isDarkTheme,
                            textColor = textColor,
                            secondaryTextColor = secondaryTextColor,
                            onRequestPermission = {
                                requestMediaPermissions()
                            }
                        )
                    } else if (isLoading) {
                        // Loading indicator
                        Box(
                            modifier = Modifier
                                .fillMaxWidth()
                                .weight(1f),
                            contentAlignment = Alignment.Center
                        ) {
                            CircularProgressIndicator(
                                color = PrimaryBlue,
                                modifier = Modifier.size(48.dp)
                            )
                        }
                    } else if (visibleMediaItems.isEmpty()) {
                        // Empty state
                        Box(
                            modifier = Modifier
                                .fillMaxWidth()
                                .weight(1f),
                            contentAlignment = Alignment.Center
                        ) {
                            Column(
                                horizontalAlignment = Alignment.CenterHorizontally
                            ) {
                                Icon(
                                    painter = TelegramIcons.Photos,
                                    contentDescription = null,
                                    tint = secondaryTextColor,
                                    modifier = Modifier.size(64.dp)
                                )
                                Spacer(modifier = Modifier.height(16.dp))
                                Text(
                                    text = "No photos or videos",
                                    color = secondaryTextColor,
                                    fontSize = 16.sp
                                )
                            }
                        }
                    } else {
                        // Media grid
                        MediaGrid(
                            mediaItems = visibleMediaItems,
                            selectedItemOrder = selectedItemOrder,
                            showCameraItem = selectedAlbum?.isAllMedia != false,
                            cameraEnabled = !isClosing,
                            gridState = mediaGridState,
                            onCameraClick = {
                                requestClose {
                                    hideKeyboard()
                                    onOpenCamera()
                                }
                            },
                            onItemClick = { item, position ->
                                if (!item.isVideo) {
                                    hideKeyboard()
                                    if (onPhotoPreviewRequested != null) {
                                        val photoItems = visibleMediaItems.filter { !it.isVideo }
                                        val photoUris = photoItems.map { it.uri }
                                        val currentIndex =
                                            photoItems.indexOfFirst { it.id == item.id }
                                                .takeIf { it >= 0 }
                                                ?: photoUris.indexOf(item.uri).coerceAtLeast(0)
                                        onPhotoPreviewRequested(item.uri, position, photoUris, currentIndex)
                                    } else {
                                        thumbnailPosition = position
                                        editingItem = item
                                    }
                                } else {
                                    // Videos don't have photo editor in this flow.
                                    toggleSelection(item.id)
                                }
                            },
                            onItemCheckClick = { item ->
                                toggleSelection(item.id)
                            },
                            onItemLongClick = { item ->
                                // Keep Telegram-like quick multiselect gesture.
                                toggleSelection(item.id)
                            },
                            isDarkTheme = isDarkTheme,
                            modifier = Modifier.weight(1f)
                        )
                    }

                    // Bottom actions (Telegram-style): anchored at the bottom and slide out when selection starts.
                    val bottomButtonsVisible = selectedItemOrder.isEmpty() && !isCaptionKeyboardVisible
                    val bottomButtonsHideProgress by animateFloatAsState(
                        targetValue = if (bottomButtonsVisible) 0f else 1f,
                        animationSpec = tween(180, easing = telegramButtonsEasing),
                        label = "bottom_buttons_hide_progress"
                    )
                    val bottomButtonsFullHeight = 108.dp
                    val bottomButtonsHeight = bottomButtonsFullHeight * (1f - bottomButtonsHideProgress)
                    Box(
                        modifier = Modifier
                            .fillMaxWidth()
                            .height(bottomButtonsHeight)
                            .graphicsLayer { clip = true }
                    ) {
                        if (bottomButtonsHideProgress < 0.999f) {
                            val rowOffsetPx =
                                with(density) { bottomButtonsFullHeight.toPx() * bottomButtonsHideProgress }
                            QuickActionsRow(
                                modifier =
                                    Modifier.fillMaxWidth()
                                        .graphicsLayer {
                                            translationY = rowOffsetPx
                                            alpha = 1f - bottomButtonsHideProgress
                                        },
                                isDarkTheme = isDarkTheme,
                                onImageClick = {
                                    requestClose {
                                        hideKeyboard()
                                        onOpenCamera()
                                    }
                                },
                                onFileClick = {
                                    requestClose { onOpenFilePicker() }
                                },
                                onAvatarClick = {
                                    requestClose { onAvatarClick() }
                                }
                            )
                        }
                    }

                    // Caption bar — Telegram-style: flat, full-width, same bg as sheet.
                    // No pill shape. Thin divider on top. Emoji button left, text field fills width.
                    // Right padding = 84dp to leave room for the floating send button.
                    // Bottom padding = 36dp so keyboard doesn't cover the input.
                    val captionBarHeight = 52.dp * captionBarProgress
                    Box(
                        modifier = Modifier
                            .fillMaxWidth()
                            .height(captionBarHeight)
                            .graphicsLayer { clip = true }
                    ) {
                        if (captionBarProgress > 0.001f) {
                            val captionOffsetPx =
                                with(density) { (1f - captionBarProgress) * 18.dp.toPx() }
                            Column(
                                modifier = Modifier
                                    .fillMaxWidth()
                                    .graphicsLayer {
                                        alpha = captionBarProgress
                                        translationY = captionOffsetPx
                                    }
                            ) {
                                // Thin divider line on top (like Telegram's 2dp shadow)
                                Box(
                                    modifier = Modifier
                                        .fillMaxWidth()
                                        .height(0.5.dp)
                                        .background(
                                            if (isDarkTheme) Color.White.copy(alpha = 0.08f)
                                            else Color.Black.copy(alpha = 0.12f)
                                        )
                                )
                                // Flat caption row — same background as sheet, no pill
                                Row(
                                    modifier = Modifier
                                        .fillMaxWidth()
                                        .padding(start = 6.dp, end = 84.dp, top = 4.dp, bottom = 4.dp),
                                    verticalAlignment = Alignment.CenterVertically,
                                    horizontalArrangement = Arrangement.spacedBy(4.dp)
                                ) {
                                    // Emoji / Keyboard toggle button
                                    val captionIconPainter =
                                        if (isCaptionKeyboardVisible) TelegramIcons.Keyboard
                                        else TelegramIcons.Smile
                                    Icon(
                                        painter = captionIconPainter,
                                        contentDescription = "Caption keyboard toggle",
                                        tint =
                                            if (isDarkTheme) Color.White.copy(alpha = 0.55f)
                                            else Color.Gray,
                                        modifier =
                                            Modifier
                                                .size(32.dp)
                                                .clip(CircleShape)
                                                .clickable(
                                                    interactionSource =
                                                        remember { MutableInteractionSource() },
                                                    indication = null
                                                ) {
                                                    if (isCaptionKeyboardVisible) {
                                                        hideKeyboard()
                                                    } else {
                                                        focusCaptionInput()
                                                    }
                                                }
                                                .padding(4.dp)
                                    )

                                    // Caption text field — no background, flat
                                    Box(
                                        modifier = Modifier
                                            .weight(1f)
                                            .heightIn(min = 28.dp, max = 120.dp)
                                            .clickable(
                                                interactionSource = remember { MutableInteractionSource() },
                                                indication = null
                                            ) { focusCaptionInput() },
                                        contentAlignment = Alignment.CenterStart
                                    ) {
                                        AppleEmojiTextField(
                                            value = pickerCaption,
                                            onValueChange = { pickerCaption = it },
                                            textColor = if (isDarkTheme) Color.White else Color.Black,
                                            textSize = 16f,
                                            hint = "Add a caption...",
                                            hintColor =
                                                if (isDarkTheme) Color.White.copy(alpha = 0.35f)
                                                else Color.Gray.copy(alpha = 0.5f),
                                            modifier = Modifier.fillMaxWidth(),
                                            requestFocus = false,
                                            onViewCreated = { captionEditTextView = it },
                                            onFocusChanged = { }
                                        )
                                    }
                                }
                            }
                        }
                    }
                    if (navInsetDpForSheet > 0.dp) {
                        Spacer(modifier = Modifier.height(navInsetDpForSheet))
                    }
                } // end Column

                    // ═══════════════════════════════════════════════════════
                    // Floating send button (Telegram-style: 56dp blue circle)
                    // Positioned at bottom-end, overlapping the caption bar
                    // — exactly like ChatAttachAlert.writeButton (110x110 container, 64dp circle)
                    // ═══════════════════════════════════════════════════════
                    val sendButtonVisible = selectedItemOrder.isNotEmpty()
                    val sendButtonProgress by animateFloatAsState(
                        targetValue = if (sendButtonVisible) 1f else 0f,
                        animationSpec = tween(180, easing = FastOutSlowInEasing),
                        label = "send_button_progress"
                    )
                    if (sendButtonProgress > 0.001f) {
                        val sendScale = 0.2f + 0.8f * sendButtonProgress
                        Box(
                            modifier = Modifier
                                .align(Alignment.BottomEnd)
                                .padding(end = 14.dp, bottom = 8.dp + navInsetDpForSheet)
                                .graphicsLayer {
                                    scaleX = sendScale
                                    scaleY = sendScale
                                    alpha = sendButtonProgress
                                },
                            contentAlignment = Alignment.Center
                        ) {
                            // The circle button
                            Box(
                                modifier = Modifier
                                    .size(56.dp)
                                    .shadow(
                                        elevation = 6.dp,
                                        shape = CircleShape,
                                        clip = false
                                    )
                                    .clip(CircleShape)
                                    .background(PrimaryBlue)
                                    .clickable {
                                        val selected = resolveSelectedMedia()
                                        val caption = pickerCaption.trim()
                                        resetPickerCaptionInput()
                                        onMediaSelected(selected, caption)
                                        animatedClose()
                                    },
                                contentAlignment = Alignment.Center
                            ) {
                                Icon(
                                    painter = TelegramIcons.Send,
                                    contentDescription = "Send",
                                    tint = Color.White,
                                    modifier = Modifier.size(24.dp)
                                )
                            }
                            // Counter badge (Telegram-style cutout ring on the button)
                            if (selectedItemOrder.size > 0) {
                                Box(
                                    modifier = Modifier
                                        .align(Alignment.TopEnd)
                                        .offset(x = 4.dp, y = (-2).dp)
                                        .sizeIn(minWidth = 22.dp, minHeight = 22.dp)
                                        .border(
                                            width = 2.dp,
                                            color = backgroundColor,
                                            shape = CircleShape
                                        )
                                        .clip(CircleShape)
                                        .background(PrimaryBlue)
                                        .padding(horizontal = 4.dp),
                                    contentAlignment = Alignment.Center
                                ) {
                                    Text(
                                        text = selectedItemOrder.size.toString(),
                                        color = Color.White,
                                        fontSize = 12.sp,
                                        fontWeight = FontWeight.Bold,
                                        maxLines = 1
                                    )
                                }
                            }
                        }
                    }
                } // end Box wrapper
            }
        }
    }

    if (showDiscardSelectionDialog) {
        AlertDialog(
            onDismissRequest = {
                showDiscardSelectionDialog = false
                pendingDismissAfterConfirm = null
            },
            containerColor = if (isDarkTheme) Color(0xFF2C2C2E) else Color.White,
            title = {
                Text(
                    text = "Discard selection?",
                    fontWeight = FontWeight.SemiBold,
                    color = textColor
                )
            },
            text = {
                Text(
                    text = "Selected photos will be removed.",
                    color = secondaryTextColor,
                    fontSize = 15.sp
                )
            },
            dismissButton = {
                TextButton(
                    onClick = {
                        showDiscardSelectionDialog = false
                        pendingDismissAfterConfirm = null
                    }
                ) {
                    Text("Cancel", color = PrimaryBlue)
                }
            },
            confirmButton = {
                TextButton(
                    onClick = {
                        val afterClose = pendingDismissAfterConfirm
                        showDiscardSelectionDialog = false
                        pendingDismissAfterConfirm = null
                        selectedItemOrder = emptyList()
                        resetPickerCaptionInput()
                        animatedClose(afterClose)
                    }
                ) {
                    Text("Discard", color = Color(0xFFFF3B30))
                }
            }
        )
    }
    
    // Fullscreen preview для выбранной фото из галереи (чистый экран без тулбаров).
    editingItem?.let { item ->
        SimpleFullscreenPhotoViewer(
            imageUri = item.uri,
            sourceThumbnail = thumbnailPosition,
            onDismiss = {
                editingItem = null
                thumbnailPosition = null
                shouldShow = true
            }
        )
    }

    // Image Editor overlay для фото с камеры
    pendingPhotoUri?.let { uri ->
        ImageEditorScreen(
            imageUri = uri,
            onDismiss = {
                pendingPhotoUri = null
            },
            onSave = { editedUri ->
                pendingPhotoUri = null
                // Если нет onMediaSelectedWithCaption - открываем preview
                if (onMediaSelectedWithCaption == null) {
                    previewPhotoUri = editedUri
                } else {
                    // Отправляем без caption
                    val mediaItem = MediaItem(
                        id = System.currentTimeMillis(),
                        uri = editedUri,
                        mimeType = "image/png",
                        dateModified = System.currentTimeMillis()
                    )
                    onMediaSelected(listOf(mediaItem), "")
                    onDismiss()
                }
            },
            onSaveWithCaption = if (onMediaSelectedWithCaption != null) { editedUri, caption ->
                pendingPhotoUri = null
                val mediaItem = MediaItem(
                    id = System.currentTimeMillis(),
                    uri = editedUri,
                    mimeType = "image/png",
                    dateModified = System.currentTimeMillis()
                )
                onMediaSelectedWithCaption(mediaItem, caption)
                onDismiss()
            } else null,
            isDarkTheme = isDarkTheme,
            showCaptionInput = onMediaSelectedWithCaption != null,
            recipientName = recipientName
        )
    }
    
    // Preview with caption before sending (как в Telegram)
    previewPhotoUri?.let { uri ->
        PhotoPreviewWithCaptionScreen(
            imageUri = uri,
            caption = photoCaption,
            onCaptionChange = { photoCaption = it },
            onSend = {
                val item = MediaItem(
                    id = System.currentTimeMillis(),
                    uri = uri,
                    mimeType = "image/png",
                    dateModified = System.currentTimeMillis()
                )
                // Отправляем фото (caption можно передать отдельно если нужно)
                onMediaSelected(listOf(item), "")
                previewPhotoUri = null
                photoCaption = ""
                onDismiss()
            },
            onDismiss = {
                previewPhotoUri = null
                photoCaption = ""
            },
            isDarkTheme = isDarkTheme
        )
    }
}

/**
 * Telegram-style album dropdown menu.
 * Mirrors ChatAttachAlertPhotoLayout's updateAlbumsDropDown() + AlbumButton items.
 * Each row: cover thumbnail · album name · item count.
 */
@Composable
private fun AlbumDropdownMenu(
    expanded: Boolean,
    onDismissRequest: () -> Unit,
    albums: List<MediaAlbum>,
    selectedAlbumId: Long,
    onAlbumSelected: (Long) -> Unit,
    isDarkTheme: Boolean,
    textColor: Color,
    secondaryTextColor: Color
) {
    val menuBg = if (isDarkTheme) Color(0xFF2C2C2E) else Color.White

    DropdownMenu(
        expanded = expanded,
        onDismissRequest = onDismissRequest,
        modifier = Modifier
            .background(menuBg)
            .widthIn(min = 220.dp, max = 300.dp)
    ) {
        albums.forEach { album ->
            val isSelected = album.id == selectedAlbumId
            val coverUri = album.items.firstOrNull()?.uri

            DropdownMenuItem(
                text = {
                    Row(
                        modifier = Modifier.fillMaxWidth(),
                        verticalAlignment = Alignment.CenterVertically,
                        horizontalArrangement = Arrangement.spacedBy(12.dp)
                    ) {
                        // Cover thumbnail (like Telegram's AlbumButton)
                        Box(
                            modifier = Modifier
                                .size(32.dp)
                                .clip(RoundedCornerShape(4.dp))
                                .background(if (isDarkTheme) Color(0xFF3A3A3C) else Color(0xFFE5E5EA))
                        ) {
                            if (coverUri != null) {
                                AsyncImage(
                                    model = ImageRequest.Builder(LocalContext.current)
                                        .data(coverUri)
                                        .crossfade(false)
                                        .size(80)
                                        .build(),
                                    contentDescription = null,
                                    contentScale = ContentScale.Crop,
                                    modifier = Modifier.fillMaxSize()
                                )
                            }
                        }

                        // Album name + count
                        Column(modifier = Modifier.weight(1f)) {
                            Text(
                                text = if (album.isAllMedia) "All media" else album.name,
                                color = textColor,
                                fontSize = 15.sp,
                                fontWeight = if (isSelected) FontWeight.SemiBold else FontWeight.Normal,
                                maxLines = 1
                            )
                            Text(
                                text = album.items.size.toString(),
                                color = secondaryTextColor,
                                fontSize = 12.sp,
                                maxLines = 1
                            )
                        }

                        // Checkmark for selected album
                        if (isSelected) {
                            Icon(
                                imageVector = Icons.Default.Check,
                                contentDescription = null,
                                tint = PrimaryBlue,
                                modifier = Modifier.size(18.dp)
                            )
                        }
                    }
                },
                onClick = { onAlbumSelected(album.id) },
                modifier = Modifier.height(48.dp)
            )
        }
    }
}

@Composable
private fun QuickActionsRow(
    modifier: Modifier = Modifier,
    isDarkTheme: Boolean,
    onImageClick: () -> Unit,
    onFileClick: () -> Unit,
    onAvatarClick: () -> Unit
) {
    Row(
        modifier =
            modifier
                .fillMaxWidth()
                .padding(start = 28.dp, end = 28.dp, top = 8.dp, bottom = 12.dp),
        horizontalArrangement = Arrangement.SpaceEvenly,
        verticalAlignment = Alignment.Bottom
    ) {
        QuickActionButton(
            icon = TelegramIcons.Photos,
            contentDescription = "Gallery",
            label = "Gallery",
            isActive = true,
            isDarkTheme = isDarkTheme,
            animationDelayMs = 0,
            onClick = onImageClick
        )
        QuickActionButton(
            icon = TelegramIcons.File,
            contentDescription = "File",
            label = "File",
            isDarkTheme = isDarkTheme,
            animationDelayMs = 32,
            onClick = onFileClick
        )
        QuickActionButton(
            icon = TelegramIcons.Contact,
            contentDescription = "Avatar",
            label = "Avatar",
            isDarkTheme = isDarkTheme,
            animationDelayMs = 64,
            onClick = onAvatarClick
        )
    }
}

@Composable
private fun QuickActionButton(
    icon: androidx.compose.ui.graphics.painter.Painter,
    contentDescription: String,
    label: String,
    isDarkTheme: Boolean,
    isActive: Boolean = false,
    animationDelayMs: Int,
    onClick: () -> Unit
) {
    val scale = remember { Animatable(0f) }
    val alpha = remember { Animatable(0f) }
    val easeOut = remember { CubicBezierEasing(0f, 0f, 0.58f, 1f) } // Telegram EASE_OUT
    val easeIn = remember { CubicBezierEasing(0.42f, 0f, 1f, 1f) } // Telegram EASE_IN
    LaunchedEffect(Unit) {
        delay(animationDelayMs.toLong())
        alpha.snapTo(0f)
        scale.snapTo(0f)
        coroutineScope {
            launch {
                alpha.animateTo(1f, animationSpec = tween(200, easing = easeOut))
            }
            launch {
                scale.animateTo(1.1f, animationSpec = tween(200, easing = easeOut))
                scale.animateTo(1f, animationSpec = tween(100, easing = easeIn))
            }
        }
    }

    Column(
        modifier = Modifier.width(72.dp).graphicsLayer { this.alpha = alpha.value },
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Box(
            modifier =
                Modifier.size(56.dp)
                    .graphicsLayer {
                        scaleX = scale.value
                        scaleY = scale.value
                    }
                    .clip(CircleShape)
                    .background(PrimaryBlue)
                    .clickable(
                        interactionSource = remember { MutableInteractionSource() },
                        indication = null,
                        onClick = onClick
                    ),
            contentAlignment = Alignment.Center
        ) {
            Icon(
                painter = icon,
                contentDescription = contentDescription,
                tint = Color.White,
                modifier = Modifier.size(24.dp)
            )
        }

        Spacer(modifier = Modifier.height(6.dp))
        Text(
            text = label,
            fontSize = 18.sp * 0.72f,
            fontWeight = FontWeight.Medium,
            color =
                when {
                    isActive -> PrimaryBlue
                    isDarkTheme -> Color(0xFF9AA1AB)
                    else -> Color(0xFF7A8190)
                },
            maxLines = 1
        )
    }
}

@Composable
private fun MediaGrid(
    mediaItems: List<MediaItem>,
    selectedItemOrder: List<Long>,
    showCameraItem: Boolean = true,
    cameraEnabled: Boolean = true,
    gridState: LazyGridState = rememberLazyGridState(),
    onCameraClick: () -> Unit,
    onItemClick: (MediaItem, ThumbnailPosition) -> Unit,
    onItemCheckClick: (MediaItem) -> Unit,
    onItemLongClick: (MediaItem) -> Unit,
    isDarkTheme: Boolean,
    modifier: Modifier = Modifier
) {
    val selectionIndexById =
        remember(selectedItemOrder) {
            selectedItemOrder.withIndex().associate { (index, id) -> id to (index + 1) }
        }
    
    LazyVerticalGrid(
        columns = GridCells.Fixed(3),
        state = gridState,
        modifier = modifier.fillMaxWidth(),
        contentPadding = PaddingValues(4.dp),
        horizontalArrangement = Arrangement.spacedBy(4.dp),
        verticalArrangement = Arrangement.spacedBy(4.dp)
    ) {
        // Camera button as first item (only in All Media album, like Telegram)
        if (showCameraItem) {
            item(key = "camera_button") {
                CameraGridItem(
                    onClick = onCameraClick,
                    enabled = cameraEnabled,
                    isDarkTheme = isDarkTheme
                )
            }
        }
        
        // Media items
        items(
            items = mediaItems,
            key = { it.id }
        ) { item ->
            val selectionIndex = selectionIndexById[item.id] ?: 0
            MediaGridItem(
                item = item,
                isSelected = selectionIndex > 0,
                selectionIndex = selectionIndex,
                onContentClick = { position -> onItemClick(item, position) },
                onCheckClick = { onItemCheckClick(item) },
                onLongClick = { onItemLongClick(item) },
                isDarkTheme = isDarkTheme
            )
        }
    }
}

/**
 * 📷 Camera button in grid - first item with live preview
 */
@Composable
private fun CameraGridItem(
    onClick: () -> Unit,
    enabled: Boolean = true,
    isDarkTheme: Boolean
) {
    val context = LocalContext.current
    val lifecycleOwner = LocalLifecycleOwner.current
    val backgroundColor = if (isDarkTheme) Color(0xFF2C2C2E) else Color(0xFFF2F2F7)
    var cameraProvider by remember { mutableStateOf<ProcessCameraProvider?>(null) }
    var previewUseCase by remember { mutableStateOf<Preview?>(null) }

    // Bounce animation for camera icon
    val iconScale = remember { Animatable(0f) }
    LaunchedEffect(Unit) {
        iconScale.animateTo(
            targetValue = 1f,
            animationSpec = spring(
                dampingRatio = 0.5f,
                stiffness = 400f
            )
        )
    }
    
    // Check if camera permission is granted - use mutableState for reactivity
    var hasCameraPermission by remember { 
        mutableStateOf(
            ContextCompat.checkSelfPermission(
                context,
                Manifest.permission.CAMERA
            ) == PackageManager.PERMISSION_GRANTED
        )
    }
    
    // Re-check permission when component becomes visible
    LaunchedEffect(Unit) {
        hasCameraPermission = ContextCompat.checkSelfPermission(
            context,
            Manifest.permission.CAMERA
        ) == PackageManager.PERMISSION_GRANTED
    }

    val enabledState = rememberUpdatedState(enabled)

    DisposableEffect(lifecycleOwner, hasCameraPermission, enabled) {
        onDispose {
            val provider = cameraProvider
            val preview = previewUseCase
            if (provider != null && preview != null) {
                try {
                    provider.unbind(preview)
                } catch (_: Exception) {
                }
            }
            previewUseCase = null
            cameraProvider = null
        }
    }
    
    Box(
        modifier = Modifier
            .aspectRatio(1f)
            .clip(RoundedCornerShape(4.dp))
            .background(backgroundColor)
            .clickable(enabled = enabled, onClick = onClick),
        contentAlignment = Alignment.Center
    ) {
        if (hasCameraPermission && enabled) {
            // Show live camera preview
            AndroidView(
                factory = { ctx ->
                    val previewView = PreviewView(ctx).apply {
                        scaleType = PreviewView.ScaleType.FILL_CENTER
                        implementationMode = PreviewView.ImplementationMode.COMPATIBLE
                    }
                    
                    val cameraProviderFuture = ProcessCameraProvider.getInstance(ctx)
                    cameraProviderFuture.addListener({
                        try {
                            if (!enabledState.value) {
                                return@addListener
                            }
                            val provider = cameraProviderFuture.get()
                            cameraProvider = provider
                            
                            val preview = Preview.Builder().build().also {
                                it.setSurfaceProvider(previewView.surfaceProvider)
                            }
                            
                            // Use back camera
                            val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
                            
                            previewUseCase?.let { existing ->
                                try {
                                    provider.unbind(existing)
                                } catch (_: Exception) {
                                }
                            }
                            provider.bindToLifecycle(
                                lifecycleOwner,
                                cameraSelector,
                                preview
                            )
                            previewUseCase = preview
                        } catch (e: Exception) {
                            // Camera init failed
                        }
                    }, ContextCompat.getMainExecutor(ctx))
                    
                    previewView
                },
                modifier = Modifier.fillMaxSize()
            )
            
            // Camera icon overlay
            Box(
                modifier = Modifier
                    .fillMaxSize()
                    .background(Color.Black.copy(alpha = 0.3f)),
                contentAlignment = Alignment.Center
            ) {
                Icon(
                    painter = TelegramIcons.Camera,
                    contentDescription = "Camera",
                    tint = Color.White,
                    modifier = Modifier
                        .size(32.dp)
                        .graphicsLayer {
                            scaleX = iconScale.value
                            scaleY = iconScale.value
                        }
                )
            }
        } else {
            // No permission - show placeholder
            Column(
                horizontalAlignment = Alignment.CenterHorizontally,
                verticalArrangement = Arrangement.Center
            ) {
                Icon(
                    painter = TelegramIcons.Camera,
                    contentDescription = "Camera",
                    tint = PrimaryBlue,
                    modifier = Modifier
                        .size(40.dp)
                        .graphicsLayer {
                            scaleX = iconScale.value
                            scaleY = iconScale.value
                        }
                )
                Spacer(modifier = Modifier.height(8.dp))
                Text(
                    text = "Camera",
                    color = PrimaryBlue,
                    fontSize = 12.sp,
                    fontWeight = FontWeight.Medium
                )
            }
        }
    }
}

@Composable
private fun MediaGridItem(
    item: MediaItem,
    isSelected: Boolean,
    selectionIndex: Int,
    onContentClick: (ThumbnailPosition) -> Unit,
    onCheckClick: () -> Unit,
    onLongClick: () -> Unit,
    isDarkTheme: Boolean
) {
    val context = LocalContext.current
    val selectedTransition = updateTransition(targetState = isSelected, label = "mediaSelection")
    val itemScale by selectedTransition.animateFloat(
        transitionSpec = { tween(durationMillis = 200, easing = FastOutSlowInEasing) },
        label = "itemScale"
    ) { selected ->
        if (selected) 0.787f else 1f
    }
    val tileBackgroundColor by animateColorAsState(
        targetValue =
            if (isSelected) {
                if (isDarkTheme) Color(0xFF2F2F31) else Color(0xFFE8EDF5)
            } else {
                Color.Transparent
            },
        animationSpec = tween(durationMillis = 200, easing = FastOutSlowInEasing),
        label = "tileBackgroundColor"
    )
    val checkBackgroundColor by animateColorAsState(
        targetValue = if (isSelected) PrimaryBlue else Color(0xCCFFFFFF),
        animationSpec = tween(durationMillis = 170, easing = FastOutSlowInEasing),
        label = "checkBackgroundColor"
    )
    val checkBorderColor by animateColorAsState(
        targetValue = if (isSelected) PrimaryBlue else Color(0x80B0B0B0),
        animationSpec = tween(durationMillis = 170, easing = FastOutSlowInEasing),
        label = "checkBorderColor"
    )
    val checkContentAlpha by animateFloatAsState(
        targetValue = if (isSelected) 1f else 0f,
        animationSpec = tween(durationMillis = 140, easing = FastOutSlowInEasing),
        label = "checkContentAlpha"
    )
    val checkScale = remember { Animatable(1f) }
    LaunchedEffect(isSelected) {
        if (isSelected) {
            checkScale.snapTo(0.72f)
            checkScale.animateTo(
                targetValue = 1f,
                animationSpec = spring(
                    dampingRatio = Spring.DampingRatioMediumBouncy,
                    stiffness = Spring.StiffnessMedium
                )
            )
        }
    }
    
    // 📍 Отслеживаем позицию для анимации
    var itemPosition by remember { mutableStateOf<ThumbnailPosition?>(null) }
    
    Box(
        modifier = Modifier
            .aspectRatio(1f)
            .clip(RoundedCornerShape(4.dp))
            .background(tileBackgroundColor)
            .onGloballyPositioned { coordinates ->
                val positionInWindow = coordinates.positionInWindow()
                itemPosition = ThumbnailPosition(
                    x = positionInWindow.x,
                    y = positionInWindow.y,
                    width = coordinates.size.width.toFloat(),
                    height = coordinates.size.height.toFloat(),
                    cornerRadius = 4f
                )
            }
    ) {
        Box(
            modifier =
                Modifier.fillMaxSize()
                    .pointerInput(Unit) {
                        detectTapGestures(
                            onTap = {
                                itemPosition?.let { onContentClick(it) }
                            },
                            onLongPress = { onLongClick() }
                        )
                    }
                    .graphicsLayer {
                        scaleX = itemScale
                        scaleY = itemScale
                    }
                    .clip(RoundedCornerShape(4.dp))
        ) {
            // Thumbnail
            val imageRequest =
                remember(item.uri) {
                    ImageRequest.Builder(context)
                        .data(item.uri)
                        .crossfade(false)
                        .build()
                }
            AsyncImage(
                model = imageRequest,
                contentDescription = null,
                contentScale = ContentScale.Crop,
                modifier = Modifier.fillMaxSize()
            )
            
            // Video duration overlay
            if (item.isVideo && item.duration > 0) {
                Box(
                    modifier = Modifier
                        .align(Alignment.BottomStart)
                        .padding(4.dp)
                        .background(
                            Color.Black.copy(alpha = 0.6f),
                            RoundedCornerShape(4.dp)
                        )
                        .padding(horizontal = 4.dp, vertical = 2.dp)
                ) {
                    Text(
                        text = formatDuration(item.duration),
                        color = Color.White,
                        fontSize = 11.sp,
                        fontWeight = FontWeight.Medium
                    )
                }
            }
            
        }
        
        // Selection checkbox
        Box(
            modifier = Modifier
                .align(Alignment.TopEnd)
                .padding(6.dp)
                .size(24.dp)
                .graphicsLayer {
                    scaleX = checkScale.value
                    scaleY = checkScale.value
                }
                .clip(CircleShape)
                .background(checkBackgroundColor)
                .border(
                    width = 2.dp,
                    color = checkBorderColor,
                    shape = CircleShape
                )
                .clickable(
                    interactionSource = remember { MutableInteractionSource() },
                    indication = null,
                    onClick = onCheckClick
                ),
            contentAlignment = Alignment.Center
        ) {
            if (selectionIndex > 0) {
                Text(
                    text = selectionIndex.toString(),
                    color = Color.White.copy(alpha = checkContentAlpha),
                    fontSize = 12.sp,
                    fontWeight = FontWeight.Bold
                )
            }
        }
    }
}

@Composable
private fun PermissionRequestView(
    isDarkTheme: Boolean,
    textColor: Color,
    secondaryTextColor: Color,
    onRequestPermission: () -> Unit
) {
    Box(
        modifier = Modifier
            .fillMaxWidth()
            .padding(32.dp),
        contentAlignment = Alignment.Center
    ) {
        Column(
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            Icon(
                TablerIcons.PhotoOff,
                contentDescription = null,
                tint = secondaryTextColor,
                modifier = Modifier.size(64.dp)
            )
            Spacer(modifier = Modifier.height(16.dp))
            Text(
                text = "Access to gallery",
                color = textColor,
                fontSize = 18.sp,
                fontWeight = FontWeight.SemiBold
            )
            Spacer(modifier = Modifier.height(8.dp))
            Text(
                text = "Allow access to your photos and videos to share them in chat",
                color = secondaryTextColor,
                fontSize = 14.sp,
                textAlign = TextAlign.Center
            )
            Spacer(modifier = Modifier.height(24.dp))
            Button(
                onClick = onRequestPermission,
                colors = ButtonDefaults.buttonColors(
                    containerColor = PrimaryBlue
                ),
                shape = RoundedCornerShape(12.dp)
            ) {
                Text("Allow Access", color = Color.White)
            }
        }
    }
}

/**
 * Result of loading media from device gallery
 */
data class MediaPickerData(
    val items: List<MediaItem>,
    val albums: List<MediaAlbum>
)

/**
 * Load media items from device gallery, grouped into albums.
 * Mirrors Telegram's MediaController album loading logic:
 * - "All media" album (bucketId=0) contains everything sorted by date
 * - Real albums sorted: All media first, then by item count descending
 */
private suspend fun loadMediaPickerData(context: Context): MediaPickerData = withContext(Dispatchers.IO) {
    val items = mutableListOf<MediaItem>()
    
    try {
        // Query images with bucket info
        val imageProjection = arrayOf(
            MediaStore.Images.Media._ID,
            MediaStore.Images.Media.MIME_TYPE,
            MediaStore.Images.Media.DATE_MODIFIED,
            MediaStore.Images.Media.BUCKET_ID,
            MediaStore.Images.Media.BUCKET_DISPLAY_NAME
        )
        
        context.contentResolver.query(
            MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
            imageProjection,
            null,
            null,
            "${MediaStore.Images.Media.DATE_MODIFIED} DESC"
        )?.use { cursor ->
            val idColumn = cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID)
            val mimeColumn = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.MIME_TYPE)
            val dateColumn = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATE_MODIFIED)
            val bucketIdColumn = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.BUCKET_ID)
            val bucketNameColumn = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.BUCKET_DISPLAY_NAME)
            
            while (cursor.moveToNext()) {
                val id = cursor.getLong(idColumn)
                val mimeType = cursor.getString(mimeColumn) ?: "image/*"
                val dateModified = cursor.getLong(dateColumn)
                val bucketId = cursor.getLong(bucketIdColumn)
                val bucketName = cursor.getString(bucketNameColumn) ?: "Unknown"
                
                val uri = ContentUris.withAppendedId(
                    MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                    id
                )
                
                items.add(MediaItem(
                    id = id,
                    uri = uri,
                    mimeType = mimeType,
                    dateModified = dateModified,
                    bucketId = bucketId,
                    bucketName = bucketName
                ))
            }
        }
        
        // Query videos with bucket info
        val videoProjection = arrayOf(
            MediaStore.Video.Media._ID,
            MediaStore.Video.Media.MIME_TYPE,
            MediaStore.Video.Media.DURATION,
            MediaStore.Video.Media.DATE_MODIFIED,
            MediaStore.Video.Media.BUCKET_ID,
            MediaStore.Video.Media.BUCKET_DISPLAY_NAME
        )
        
        context.contentResolver.query(
            MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
            videoProjection,
            null,
            null,
            "${MediaStore.Video.Media.DATE_MODIFIED} DESC"
        )?.use { cursor ->
            val idColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media._ID)
            val mimeColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.MIME_TYPE)
            val durationColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATION)
            val dateColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DATE_MODIFIED)
            val bucketIdColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.BUCKET_ID)
            val bucketNameColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.BUCKET_DISPLAY_NAME)
            
            while (cursor.moveToNext()) {
                val id = cursor.getLong(idColumn)
                val mimeType = cursor.getString(mimeColumn) ?: "video/*"
                val duration = cursor.getLong(durationColumn)
                val dateModified = cursor.getLong(dateColumn)
                val bucketId = cursor.getLong(bucketIdColumn)
                val bucketName = cursor.getString(bucketNameColumn) ?: "Unknown"
                
                val uri = ContentUris.withAppendedId(
                    MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
                    id
                )
                
                // Use negative id to avoid collision with images
                items.add(MediaItem(
                    id = -id,
                    uri = uri,
                    mimeType = mimeType,
                    duration = duration,
                    dateModified = dateModified,
                    bucketId = bucketId,
                    bucketName = bucketName
                ))
            }
        }
        
        // Sort all items by date
        items.sortByDescending { it.dateModified }
        
    } catch (e: Exception) {
        Log.e(TAG, "Failed to load media", e)
    }

    // Build albums (like Telegram's updateAlbumsDropDown)
    val allMediaAlbum = MediaAlbum(
        id = ALL_MEDIA_ALBUM_ID,
        name = "All media",
        items = items,
        isAllMedia = true
    )

    val bucketAlbums = items
        .groupBy { it.bucketId }
        .map { (bucketId, bucketItems) ->
            MediaAlbum(
                id = bucketId,
                name = bucketItems.first().bucketName,
                items = bucketItems.sortedByDescending { it.dateModified }
            )
        }
        .sortedByDescending { it.items.size } // Largest albums first, like Telegram

    val albums = listOf(allMediaAlbum) + bucketAlbums

    MediaPickerData(items = items, albums = albums)
}

/**
 * Format duration in milliseconds to MM:SS
 */
private fun formatDuration(durationMs: Long): String {
    val totalSeconds = durationMs / 1000
    val minutes = totalSeconds / 60
    val seconds = totalSeconds % 60
    return "%d:%02d".format(minutes, seconds)
}

/**
 * Экран предпросмотра фото с caption и кнопкой отправки (как в Telegram)
 * С плавной анимацией перехода между клавиатурой и emoji picker
 *
 * Использует тот же подход что ChatDetailInput:
 * - imePadding() применяется ТОЛЬКО когда emoji НЕ показан
 * - AnimatedKeyboardTransition управляет emoji picker
 */
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun PhotoPreviewWithCaptionScreen(
    imageUri: Uri,
    caption: String,
    onCaptionChange: (String) -> Unit,
    onSend: () -> Unit,
    onDismiss: () -> Unit,
    isDarkTheme: Boolean
) {
    val backgroundColor = if (isDarkTheme) Color.Black else Color.White

    val context = LocalContext.current
    val hasNativeNavigationBar = remember(context) {
        NavigationModeUtils.hasNativeNavigationBar(context)
    }
    val view = LocalView.current
    val focusManager = LocalFocusManager.current
    val density = LocalDensity.current

    // ═══════════════════════════════════════════════════════════════
    // 😀 EMOJI PICKER STATE
    // ═══════════════════════════════════════════════════════════════
    var showEmojiPicker by remember { mutableStateOf(false) }
    val coordinator = rememberKeyboardTransitionCoordinator()
    var editTextView by remember { mutableStateOf<com.rosetta.messenger.ui.components.AppleEmojiEditTextView?>(null) }
    var lastToggleTime by remember { mutableLongStateOf(0L) }
    val toggleCooldownMs = 500L

    // Отслеживание высоты клавиатуры
    val imeInsets = WindowInsets.ime
    var isKeyboardVisible by remember { mutableStateOf(false) }
    var lastStableKeyboardHeight by remember { mutableStateOf(0.dp) }

    // Update coordinator through snapshotFlow
    LaunchedEffect(Unit) {
        snapshotFlow { with(density) { imeInsets.getBottom(density).toDp() } }.collect { currentImeHeight ->
            isKeyboardVisible = currentImeHeight > 50.dp
            coordinator.updateKeyboardHeight(currentImeHeight)
            if (currentImeHeight > 100.dp) {
                coordinator.syncHeights()
                lastStableKeyboardHeight = currentImeHeight
            }
        }
    }

    // Load saved keyboard height
    LaunchedEffect(Unit) {
        KeyboardHeightProvider.getSavedKeyboardHeight(context)
    }

    // Save keyboard height when stable
    LaunchedEffect(isKeyboardVisible, showEmojiPicker) {
        if (isKeyboardVisible && !showEmojiPicker) {
            delay(350)
            if (isKeyboardVisible && !showEmojiPicker && lastStableKeyboardHeight > 300.dp) {
                val heightPx = with(density) { lastStableKeyboardHeight.toPx().toInt() }
                KeyboardHeightProvider.saveKeyboardHeight(context, heightPx)
            }
        }
    }

    // Toggle emoji picker function
    fun toggleEmojiPicker() {
        val currentTime = System.currentTimeMillis()
        if (currentTime - lastToggleTime < toggleCooldownMs) {
            return
        }
        lastToggleTime = currentTime

        val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager

        if (coordinator.isEmojiVisible) {
            // EMOJI → KEYBOARD
            coordinator.requestShowKeyboard(
                showKeyboard = {
                    editTextView?.let { editText ->
                        editText.requestFocus()
                        imm.showSoftInput(editText, InputMethodManager.SHOW_IMPLICIT)
                    }
                },
                hideEmoji = {
                    showEmojiPicker = false
                }
            )
        } else {
            // KEYBOARD → EMOJI
            coordinator.requestShowEmoji(
                hideKeyboard = {
                    imm.hideSoftInputFromWindow(view.windowToken, 0)
                },
                showEmoji = {
                    showEmojiPicker = true
                }
            )
        }
    }

    // 🔥 КЛЮЧЕВОЕ: imePadding применяется ТОЛЬКО когда emoji box НЕ виден
    val shouldUseImePadding = !coordinator.isEmojiBoxVisible
    val shouldAddNavBarPadding =
        hasNativeNavigationBar && !isKeyboardVisible && !coordinator.isEmojiBoxVisible

    // Логируем состояние при каждой рекомпозиции
    Surface(
        color = backgroundColor,
        modifier = Modifier.fillMaxSize()
    ) {
        Box(modifier = Modifier.fillMaxSize()) {
            // ═══════════════════════════════════════════════════════════
            // 📸 FULLSCREEN PHOTO - не реагирует на клавиатуру
            // ═══════════════════════════════════════════════════════════
            AsyncImage(
                model = ImageRequest.Builder(context)
                    .data(imageUri)
                    .crossfade(true)
                    .build(),
                contentDescription = null,
                modifier = Modifier.fillMaxSize(),
                contentScale = ContentScale.Fit
            )

            // ═══════════════════════════════════════════════════════════
            // 🎛️ TOP BAR - Transparent overlay
            // ═══════════════════════════════════════════════════════════
            Box(
                modifier = Modifier
                    .fillMaxWidth()
                    .align(Alignment.TopCenter)
                    .background(
                        Brush.verticalGradient(
                            colors = listOf(
                                Color.Black.copy(alpha = 0.5f),
                                Color.Transparent
                            )
                        )
                    )
                    .statusBarsPadding()
                    .padding(horizontal = 4.dp, vertical = 8.dp)
            ) {
                IconButton(
                    onClick = {
                        showEmojiPicker = false
                        val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
                        imm.hideSoftInputFromWindow(view.windowToken, 0)
                        focusManager.clearFocus()
                        onDismiss()
                    },
                    modifier = Modifier.align(Alignment.CenterStart)
                ) {
                    Icon(
                        painter = TelegramIcons.Close,
                        contentDescription = "Close",
                        tint = Color.White,
                        modifier = Modifier.size(28.dp)
                    )
                }
            }

            // ═══════════════════════════════════════════════════════════
            // 📝 CAPTION INPUT + EMOJI PICKER
            // Как в ChatDetailInput: imePadding + AnimatedKeyboardTransition
            // ═══════════════════════════════════════════════════════════
            Column(
                modifier = Modifier
                    .fillMaxWidth()
                    .align(Alignment.BottomCenter)
                    // 🔥 imePadding ТОЛЬКО когда emoji НЕ показан
                    .then(if (shouldUseImePadding) Modifier.imePadding() else Modifier)
            ) {
                // Caption bar
                Box(
                    modifier = Modifier
                        .fillMaxWidth()
                        .background(Color.Black.copy(alpha = 0.75f))
                        .padding(
                            start = 12.dp,
                            end = 12.dp,
                            top = 10.dp,
                            bottom = if (isKeyboardVisible || coordinator.isEmojiBoxVisible) 10.dp else 16.dp
                        )
                        .then(if (shouldAddNavBarPadding) Modifier.navigationBarsPadding() else Modifier)
                ) {
                    Row(
                        modifier = Modifier.fillMaxWidth(),
                        verticalAlignment = Alignment.CenterVertically,
                        horizontalArrangement = Arrangement.spacedBy(10.dp)
                    ) {
                        // Emoji/Keyboard toggle button
                        IconButton(
                            onClick = { toggleEmojiPicker() },
                            modifier = Modifier.size(32.dp)
                        ) {
                            Crossfade(
                                targetState = showEmojiPicker,
                                animationSpec = tween(150),
                                label = "emojiIcon"
                            ) { isEmoji ->
                                Icon(
                                    painter = if (isEmoji) TelegramIcons.Keyboard else TelegramIcons.Smile,
                                    contentDescription = if (isEmoji) "Keyboard" else "Emoji",
                                    tint = Color.White.copy(alpha = 0.7f),
                                    modifier = Modifier.size(26.dp)
                                )
                            }
                        }

                        // Caption text field
                        Box(
                            modifier = Modifier
                                .weight(1f)
                                .heightIn(min = 24.dp, max = 100.dp)
                        ) {
                            AppleEmojiTextField(
                                value = caption,
                                onValueChange = onCaptionChange,
                                textColor = Color.White,
                                textSize = 16f,
                                hint = "Add a caption...",
                                hintColor = Color.White.copy(alpha = 0.5f),
                                modifier = Modifier.fillMaxWidth(),
                                requestFocus = false,
                                onViewCreated = { v -> editTextView = v },
                                onFocusChanged = { hasFocus ->
                                    if (hasFocus && showEmojiPicker) {
                                        toggleEmojiPicker()
                                    }
                                }
                            )
                        }

                        // Send button (Telegram-style)
                        Box(
                            modifier = Modifier
                                .size(44.dp)
                                .shadow(
                                    elevation = 4.dp,
                                    shape = CircleShape,
                                    clip = false
                                )
                                .clip(CircleShape)
                                .background(PrimaryBlue)
                                .clickable { onSend() },
                            contentAlignment = Alignment.Center
                        ) {
                            Icon(
                                painter = TelegramIcons.Send,
                                contentDescription = "Send",
                                tint = Color.White,
                                modifier = Modifier
                                    .size(24.dp)
                                    .offset(x = 1.dp)
                            )
                        }
                    }
                }

                // ═══════════════════════════════════════════════════════════
                // 🔥 EMOJI PICKER - используем AnimatedKeyboardTransition
                // Точно как в ChatDetailInput!
                // ═══════════════════════════════════════════════════════════
                AnimatedKeyboardTransition(
                    coordinator = coordinator,
                    showEmojiPicker = showEmojiPicker
                ) {
                    OptimizedEmojiPicker(
                        isVisible = true,
                        isDarkTheme = isDarkTheme,
                        onEmojiSelected = { emoji -> onCaptionChange(caption + emoji) },
                        onClose = { toggleEmojiPicker() },
                        modifier = Modifier.fillMaxWidth()
                    )
                }
            }
        }
    }
}
