package ru.forbion.f7cloud.feature.talk

import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxScope
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ExperimentalLayoutApi
import androidx.compose.foundation.layout.FlowRow
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.OutlinedTextFieldDefaults
import androidx.compose.material3.Text
import androidx.compose.material3.rememberModalBottomSheetState
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.IconButton
import androidx.compose.material3.Surface
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import coil.compose.SubcomposeAsyncImage
import coil.request.ImageRequest
import okhttp3.Credentials
import ru.forbion.f7cloud.core.auth.AuthSession
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.graphicsLayer
import coil.compose.AsyncImage
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.foundation.layout.widthIn
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.window.Popup
import androidx.compose.ui.window.PopupProperties
import ru.forbion.f7cloud.core.designsystem.F7Colors
import ru.forbion.f7cloud.core.designsystem.F7PrimaryButton
import ru.forbion.f7cloud.core.designsystem.F7TextButton
import java.text.DateFormat
import java.util.Calendar
import java.util.Date
import kotlin.math.abs

private val CallBadgeColor = Color(0xFF43A047)

@Composable
fun TalkChatBackground(
    session: AuthSession,
    modifier: Modifier = Modifier,
    content: @Composable BoxScope.() -> Unit = {},
) {
    Box(
        modifier = modifier
            .fillMaxSize()
            .background(F7Colors.ChatBackground),
    ) {
        // Локальная подложка чата из дизайна (Подложка2): светло-зелёный градиент + водяной
        // паттерн иконок. Была с сервера — теперь офлайн и точно из макета.
        Image(
            painter = painterResource(R.drawable.chat_background),
            contentDescription = null,
            modifier = Modifier.fillMaxSize(),
            contentScale = ContentScale.Crop,
        )
        content()
    }
}

@Composable
fun TalkSystemMessagesToggle(
    collapsed: Boolean,
    systemCount: Int,
    session: AuthSession,
    onClick: () -> Unit,
    modifier: Modifier = Modifier,
) {
    if (systemCount <= 0) return
    Box(
        modifier = modifier.fillMaxWidth(),
        contentAlignment = Alignment.Center,
    ) {
        Row(
            modifier = Modifier
                .heightIn(min = 28.dp)
                .clip(RoundedCornerShape(100.dp))
                .background(F7Colors.PrimaryLight)
                .border(1.dp, F7Colors.Border, RoundedCornerShape(100.dp))
                .clickable(onClick = onClick)
                .padding(horizontal = 12.dp, vertical = 6.dp),
            verticalAlignment = Alignment.CenterVertically,
            horizontalArrangement = Arrangement.spacedBy(8.dp),
        ) {
            Text(
                when {
                    collapsed -> "Показать системные сообщения"
                    systemCount == 1 -> "1 системное сообщение"
                    else -> "$systemCount системных сообщений"
                },
                fontSize = 12.sp,
                lineHeight = 16.sp,
                fontWeight = FontWeight.Medium,
                color = F7Colors.TextPrimary,
            )
            AsyncImage(
                model = TalkAssets.spreed(session, "system-messages-chevron-down.svg"),
                contentDescription = null,
                modifier = Modifier
                    .size(12.dp)
                    .then(
                        if (!collapsed) Modifier.graphicsLayer { rotationZ = 180f }
                        else Modifier,
                    ),
            )
        }
    }
}

@Composable
fun TalkListToolbar(
    session: AuthSession,
    query: String,
    onQueryChange: (String) -> Unit,
    filterActive: Boolean,
    onFilterClick: () -> Unit,
    onCreateClick: () -> Unit,
    modifier: Modifier = Modifier,
) {
    Row(
        modifier = modifier.fillMaxWidth(),
        verticalAlignment = Alignment.CenterVertically,
        horizontalArrangement = Arrangement.spacedBy(8.dp),
    ) {
        TalkSearchBar(
            query = query,
            onQueryChange = onQueryChange,
            modifier = Modifier.weight(1f),
        )
        Box(
            modifier = Modifier
                .size(40.dp)
                .clip(CircleShape)
                .background(if (filterActive) F7Colors.PrimaryLight else Color.White.copy(alpha = 0.6f))
                .border(1.dp, F7Colors.Border, CircleShape)
                .clickable(onClick = onFilterClick),
            contentAlignment = Alignment.Center,
        ) {
            AsyncImage(
                model = TalkAssets.spreed(session, "filter-black-spreed.svg"),
                contentDescription = "Фильтр",
                modifier = Modifier.size(20.dp),
                contentScale = ContentScale.Fit,
            )
        }
        Box(
            modifier = Modifier
                .size(40.dp)
                .clip(CircleShape)
                .background(
                    brush = androidx.compose.ui.graphics.Brush.linearGradient(
                        listOf(Color(0xE8C0FF7B), Color(0xE870B62B)),
                    ),
                )
                .clickable(onClick = onCreateClick),
            contentAlignment = Alignment.Center,
        ) {
            AsyncImage(
                model = TalkAssets.theme(session, "plus.svg"),
                contentDescription = "Создать",
                modifier = Modifier.size(18.dp),
                contentScale = ContentScale.Fit,
            )
        }
    }
}

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun TalkFilterSheet(
    visible: Boolean,
    selected: TalkRoomFilter,
    onDismiss: () -> Unit,
    onFilterSelected: (TalkRoomFilter) -> Unit,
) {
    if (!visible) return
    val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true)
    ModalBottomSheet(onDismissRequest = onDismiss, sheetState = sheetState, containerColor = F7Colors.Surface) {
        Column(
            modifier = Modifier
                .fillMaxWidth()
                .padding(horizontal = 16.dp, vertical = 8.dp),
            verticalArrangement = Arrangement.spacedBy(8.dp),
        ) {
            Text("Фильтр", style = MaterialTheme.typography.titleMedium)
            TalkRoomFilter.entries.forEach { filter ->
                Row(
                    modifier = Modifier
                        .fillMaxWidth()
                        .clip(RoundedCornerShape(12.dp))
                        .background(if (filter == selected) F7Colors.PrimaryLight else Color.Transparent)
                        .clickable { onFilterSelected(filter) }
                        .padding(horizontal = 12.dp, vertical = 12.dp),
                    verticalAlignment = Alignment.CenterVertically,
                ) {
                    Text(filter.label, modifier = Modifier.weight(1f))
                    if (filter == selected) Text("✓", color = F7Colors.Primary)
                }
            }
            Spacer(Modifier.height(16.dp))
        }
    }
}

@Composable
fun TalkFilterChips(
    selected: TalkRoomFilter,
    onClear: () -> Unit,
    modifier: Modifier = Modifier,
) {
    if (selected == TalkRoomFilter.ALL) return
    LazyRow(modifier = modifier, horizontalArrangement = Arrangement.spacedBy(8.dp)) {
        item {
            Row(
                modifier = Modifier
                    .clip(RoundedCornerShape(100.dp))
                    .background(F7Colors.PrimaryLight)
                    .clickable(onClick = onClear)
                    .padding(horizontal = 12.dp, vertical = 6.dp),
                verticalAlignment = Alignment.CenterVertically,
            ) {
                Text(selected.label, style = MaterialTheme.typography.labelMedium)
                Spacer(Modifier.width(6.dp))
                Text("×", color = F7Colors.TextSecondary)
            }
        }
    }
}

@Composable
fun TalkSearchBar(
    query: String,
    onQueryChange: (String) -> Unit,
    modifier: Modifier = Modifier,
) {
    OutlinedTextField(
        value = query,
        onValueChange = onQueryChange,
        modifier = modifier
            .fillMaxWidth()
            .heightIn(min = 40.dp),
        placeholder = { Text("Поиск", color = F7Colors.TextSecondary, fontSize = 14.sp) },
        singleLine = true,
        shape = RoundedCornerShape(100.dp),
        colors = OutlinedTextFieldDefaults.colors(
            focusedContainerColor = Color.White.copy(alpha = 0.6f),
            unfocusedContainerColor = Color.White.copy(alpha = 0.6f),
            focusedBorderColor = F7Colors.Border,
            unfocusedBorderColor = F7Colors.Border,
        ),
    )
}

@Composable
fun TalkRoomRow(
    room: TalkRoom,
    session: AuthSession,
    modifier: Modifier = Modifier,
    onClick: () -> Unit,
    onToggleFavorite: () -> Unit = {},
    onMarkUnread: () -> Unit = {},
) {
    var menuExpanded by remember { mutableStateOf(false) }
    Row(
        modifier = modifier
            .fillMaxWidth()
            .clip(RoundedCornerShape(8.dp))
            .clickable(onClick = onClick)
            .padding(horizontal = 4.dp, vertical = 8.dp),
        verticalAlignment = Alignment.CenterVertically,
    ) {
        TalkAvatarImage(
            session = session,
            displayName = room.displayName,
            avatarUrl = TalkUrls.roomAvatar(session, room.token),
            modifier = Modifier.size(44.dp),
            showCallBadge = room.hasCall,
        )
        Spacer(Modifier.width(12.dp))
        Column(modifier = Modifier.weight(1f)) {
            Row(
                modifier = Modifier.fillMaxWidth(),
                verticalAlignment = Alignment.CenterVertically,
            ) {
                if (room.isFavorite) {
                    Text("★ ", fontSize = 12.sp, color = Color(0xFFF9CF3D))
                }
                Text(
                    room.displayName,
                    modifier = Modifier.weight(1f),
                    fontSize = 14.sp,
                    lineHeight = 20.sp,
                    fontWeight = if (room.hasUnread) FontWeight.SemiBold else FontWeight.Medium,
                    color = F7Colors.TextPrimary,
                    maxLines = 1,
                    overflow = TextOverflow.Ellipsis,
                )
                val ts = room.lastMessageTimestamp.takeIf { it > 0 } ?: room.lastActivity
                if (ts > 0) {
                    Text(
                        formatTalkTime(ts),
                        fontSize = 12.sp,
                        lineHeight = 16.sp,
                        color = F7Colors.TextSecondary,
                    )
                }
                Box {
                    IconButton(onClick = { menuExpanded = true }, modifier = Modifier.size(28.dp)) {
                        AsyncImage(
                            model = TalkAssets.spreed(session, "dots-with-lines-icon-black.svg"),
                            contentDescription = "Меню",
                            modifier = Modifier.size(16.dp),
                        )
                    }
                    DropdownMenu(expanded = menuExpanded, onDismissRequest = { menuExpanded = false }) {
                        DropdownMenuItem(
                            text = { Text(if (room.isFavorite) "Убрать из избранного" else "В избранное") },
                            onClick = { menuExpanded = false; onToggleFavorite() },
                        )
                        DropdownMenuItem(
                            text = { Text("Пометить непрочитанным") },
                            onClick = { menuExpanded = false; onMarkUnread() },
                        )
                    }
                }
            }
            Row(
                modifier = Modifier.fillMaxWidth(),
                verticalAlignment = Alignment.CenterVertically,
            ) {
                if (room.hasCall) {
                    AsyncImage(
                        model = TalkAssets.spreed(session, "call-icon-white.svg"),
                        contentDescription = null,
                        modifier = Modifier
                            .size(16.dp)
                            .clip(CircleShape)
                            .background(CallBadgeColor)
                            .padding(2.dp),
                    )
                    Spacer(Modifier.width(4.dp))
                }
                if (room.unreadMention) {
                    Text("@", color = F7Colors.Primary, fontWeight = FontWeight.Bold, fontSize = 12.sp)
                    Spacer(Modifier.width(4.dp))
                }
                Text(
                    room.lastMessagePreview.ifBlank { roomTypeLabel(room.type) },
                    modifier = Modifier.weight(1f),
                    fontSize = 12.sp,
                    lineHeight = 18.sp,
                    color = F7Colors.TextSecondary,
                    fontWeight = if (room.hasUnread) FontWeight.Medium else FontWeight.Normal,
                    maxLines = 1,
                    overflow = TextOverflow.Ellipsis,
                )
                if (room.unreadMessages > 0) {
                    Spacer(Modifier.width(8.dp))
                    Box(
                        modifier = Modifier
                            .size(if (room.unreadMessages > 9) 22.dp else 18.dp)
                            .clip(CircleShape)
                            .background(F7Colors.Primary),
                        contentAlignment = Alignment.Center,
                    ) {
                        Text(
                            if (room.unreadMessages > 99) "99+" else room.unreadMessages.toString(),
                            style = MaterialTheme.typography.labelSmall,
                            color = Color.White,
                            fontSize = 10.sp,
                        )
                    }
                } else if (room.unreadMention) {
                    Spacer(Modifier.width(8.dp))
                    Box(
                        modifier = Modifier
                            .size(8.dp)
                            .clip(CircleShape)
                            .background(F7Colors.Primary),
                    )
                }
            }
        }
    }
}

@Composable
fun TalkAvatarImage(
    session: AuthSession,
    displayName: String,
    avatarUrl: String?,
    modifier: Modifier = Modifier,
    showCallBadge: Boolean = false,
) {
    val context = LocalContext.current
    Box(modifier = modifier) {
        if (!avatarUrl.isNullOrBlank()) {
            val request = remember(session.serverUrl, session.username, avatarUrl) {
                ImageRequest.Builder(context)
                    .data(avatarUrl)
                    .crossfade(true)
                    .addHeader(
                        "Authorization",
                        Credentials.basic(session.username, session.appPassword),
                    )
                    .build()
            }
            SubcomposeAsyncImage(
                model = request,
                contentDescription = displayName,
                modifier = Modifier
                    .fillMaxSize()
                    .clip(CircleShape),
                contentScale = ContentScale.Crop,
                loading = { TalkAvatar(name = displayName, modifier = Modifier.fillMaxSize()) },
                error = { TalkAvatar(name = displayName, modifier = Modifier.fillMaxSize()) },
            )
        } else {
            TalkAvatar(name = displayName, modifier = Modifier.fillMaxSize())
        }
        if (showCallBadge) {
            Box(
                modifier = Modifier
                    .align(Alignment.BottomEnd)
                    .offset(x = 2.dp, y = 2.dp)
                    .size(16.dp)
                    .clip(CircleShape)
                    .background(CallBadgeColor)
                    .border(1.dp, Color.White, CircleShape),
                contentAlignment = Alignment.Center,
            ) {
                Text("📞", fontSize = 8.sp)
            }
        }
    }
}

@Composable
fun TalkAvatar(name: String, modifier: Modifier = Modifier) {
    val label = name.trim()
    val initials = label.split(Regex("\\s+"))
        .filter { it.isNotBlank() }
        .take(2)
        .joinToString("") { it.first().uppercaseChar().toString() }
        .ifBlank { "?" }
    val bg = talkAvatarColor(label)
    Box(
        modifier = modifier
            .clip(CircleShape)
            .background(bg),
        contentAlignment = Alignment.Center,
    ) {
        Text(
            initials,
            style = MaterialTheme.typography.labelMedium,
            color = Color.White,
            fontWeight = FontWeight.SemiBold,
        )
    }
}

@Composable
fun TalkCalendarPopup(
    session: AuthSession,
    visible: Boolean,
    onDismiss: () -> Unit,
    onScheduleMeeting: () -> Unit,
) {
    if (!visible) return
    val density = LocalDensity.current
    Popup(
        alignment = Alignment.TopEnd,
        offset = IntOffset(
            x = with(density) { (-16).dp.roundToPx() },
            y = with(density) { 52.dp.roundToPx() },
        ),
        onDismissRequest = onDismiss,
        properties = PopupProperties(focusable = true),
    ) {
        Surface(
            shape = RoundedCornerShape(12.dp),
            color = F7Colors.Surface,
            shadowElevation = 8.dp,
            modifier = Modifier
                .widthIn(min = 220.dp, max = 280.dp)
                .border(1.dp, F7Colors.Border, RoundedCornerShape(12.dp)),
        ) {
            Column(
                modifier = Modifier.padding(16.dp),
                horizontalAlignment = Alignment.CenterHorizontally,
                verticalArrangement = Arrangement.spacedBy(12.dp),
            ) {
                AsyncImage(
                    model = TalkAssets.spreed(session, "calendar-icon-gray.svg"),
                    contentDescription = null,
                    modifier = Modifier.size(48.dp),
                )
                Text(
                    "Нет предстоящих встреч",
                    style = MaterialTheme.typography.bodyMedium,
                    color = F7Colors.TextSecondary,
                )
                Row(
                    modifier = Modifier
                        .fillMaxWidth()
                        .clip(RoundedCornerShape(100.dp))
                        .border(1.dp, F7Colors.Border, RoundedCornerShape(100.dp))
                        .clickable {
                            onDismiss()
                            onScheduleMeeting()
                        }
                        .padding(horizontal = 14.dp, vertical = 10.dp),
                    horizontalArrangement = Arrangement.Center,
                    verticalAlignment = Alignment.CenterVertically,
                ) {
                    Text(
                        "+ Запланировать встречу",
                        style = MaterialTheme.typography.labelLarge,
                        color = F7Colors.TextPrimary,
                    )
                }
            }
        }
    }
}

@Composable
fun TalkChatHeader(
    session: AuthSession,
    room: TalkRoom,
    participantCount: Int?,
    onBackClick: () -> Unit,
    onStartCall: () -> Unit,
    onMenuClick: () -> Unit,
    onScheduleMeeting: () -> Unit,
    modifier: Modifier = Modifier,
) {
    var calendarOpen by remember { mutableStateOf(false) }
    TalkCalendarPopup(
        session = session,
        visible = calendarOpen,
        onDismiss = { calendarOpen = false },
        onScheduleMeeting = {
            calendarOpen = false
            onScheduleMeeting()
        },
    )
    Surface(
        modifier = modifier.fillMaxWidth(),
        shape = RoundedCornerShape(100.dp),
        color = Color(0xFDFDFDFF),
        shadowElevation = 0.dp,
        tonalElevation = 0.dp,
    ) {
        Row(
            modifier = Modifier
                .fillMaxWidth()
                .heightIn(min = 45.dp)
                .border(1.dp, F7Colors.TalkTopBarBorder, RoundedCornerShape(100.dp))
                .padding(horizontal = 8.dp, vertical = 4.dp),
            verticalAlignment = Alignment.CenterVertically,
        ) {
            Box(
                modifier = Modifier
                    .size(36.dp)
                    .clip(CircleShape)
                    .clickable(onClick = onBackClick),
                contentAlignment = Alignment.Center,
            ) {
                AsyncImage(
                    model = TalkAssets.spreed(session, "arror-back.svg"),
                    contentDescription = "Назад",
                    modifier = Modifier.size(20.dp),
                )
            }
            TalkAvatarImage(
                session = session,
                displayName = room.displayName,
                avatarUrl = TalkUrls.roomAvatar(session, room.token),
                modifier = Modifier
                    .size(36.dp)
                    .padding(horizontal = 4.dp),
                showCallBadge = room.hasCall,
            )
            Column(modifier = Modifier.weight(1f)) {
                Text(
                    room.displayName,
                    style = MaterialTheme.typography.titleSmall,
                    maxLines = 1,
                    overflow = TextOverflow.Ellipsis,
                )
                Text(
                    when {
                        participantCount != null -> "$participantCount участников"
                        room.type == 1 -> "Личный чат"
                        room.type == 2 -> "Групповой чат"
                        else -> roomTypeLabel(room.type)
                    },
                    style = MaterialTheme.typography.labelSmall,
                    color = F7Colors.TextSecondary,
                    maxLines = 1,
                    overflow = TextOverflow.Ellipsis,
                )
            }
            Box(
                modifier = Modifier
                    .size(36.dp)
                    .clip(CircleShape)
                    .clickable { calendarOpen = !calendarOpen },
                contentAlignment = Alignment.Center,
            ) {
                AsyncImage(
                    model = TalkAssets.spreed(session, "calendar-icon-gray.svg"),
                    contentDescription = "Календарь",
                    modifier = Modifier.size(20.dp),
                )
            }
            Box(
                modifier = Modifier
                    .size(36.dp)
                    .clip(CircleShape)
                    .clickable(onClick = onMenuClick),
                contentAlignment = Alignment.Center,
            ) {
                AsyncImage(
                    model = TalkAssets.spreed(session, "dots-with-lines-icon-black.svg"),
                    contentDescription = "Меню",
                    modifier = Modifier.size(16.dp),
                )
            }
            Box(
                modifier = Modifier
                    .padding(start = 4.dp)
                    .size(38.dp)
                    .clip(CircleShape)
                    .background(
                        brush = androidx.compose.ui.graphics.Brush.linearGradient(
                            listOf(Color(0xCC70B62B), Color(0xFF70B62B)),
                        ),
                    )
                    .clickable(onClick = onStartCall),
                contentAlignment = Alignment.Center,
            ) {
                AsyncImage(
                    model = TalkAssets.spreed(session, "call-icon-white.svg"),
                    contentDescription = if (room.hasCall) "Присоединиться к звонку" else "Начать звонок",
                    modifier = Modifier.size(18.dp),
                )
            }
        }
    }
}

private val TalkQuickEmojis = listOf(
    "😀", "😂", "😍", "👍", "🙏", "🔥", "❤️", "🎉", "😢", "👏", "✅", "🤔",
)

@Composable
fun TalkEmojiPicker(
    visible: Boolean,
    onDismiss: () -> Unit,
    onEmojiSelected: (String) -> Unit,
    modifier: Modifier = Modifier,
) {
    if (!visible) return
    Surface(
        modifier = modifier.fillMaxWidth(),
        shape = RoundedCornerShape(12.dp),
        color = F7Colors.Surface,
        shadowElevation = 4.dp,
    ) {
        Column(Modifier.padding(12.dp)) {
            Row(
                modifier = Modifier.fillMaxWidth(),
                horizontalArrangement = Arrangement.SpaceBetween,
                verticalAlignment = Alignment.CenterVertically,
            ) {
                Text("Смайлики", style = MaterialTheme.typography.labelMedium)
                F7TextButton(text = "Закрыть", onClick = onDismiss)
            }
            FlowRow(
                horizontalArrangement = Arrangement.spacedBy(6.dp),
                verticalArrangement = Arrangement.spacedBy(6.dp),
            ) {
                TalkQuickEmojis.forEach { emoji ->
                    Text(
                        emoji,
                        fontSize = 22.sp,
                        modifier = Modifier
                            .clip(RoundedCornerShape(8.dp))
                            .clickable {
                                onEmojiSelected(emoji)
                                onDismiss()
                            }
                            .padding(6.dp),
                    )
                }
            }
        }
    }
}

@Composable
fun TalkDateSeparator(label: String, modifier: Modifier = Modifier) {
    Box(
        modifier = modifier
            .fillMaxWidth()
            .padding(vertical = 4.dp),
        contentAlignment = Alignment.Center,
    ) {
        Text(
            label,
            modifier = Modifier
                .clip(RoundedCornerShape(100.dp))
                .background(F7Colors.ChatDatePill)
                .padding(horizontal = 12.dp, vertical = 4.dp),
            fontSize = 12.sp,
            lineHeight = 16.sp,
            color = F7Colors.TextSecondary,
        )
    }
}

@Composable
fun TalkUnreadMarker(modifier: Modifier = Modifier) {
    Row(
        modifier = modifier
            .fillMaxWidth()
            .padding(vertical = 6.dp),
        verticalAlignment = Alignment.CenterVertically,
    ) {
        Box(
            modifier = Modifier
                .weight(1f)
                .height(1.dp)
                .background(F7Colors.Primary.copy(alpha = 0.35f)),
        )
        Text(
            "Непрочитанные",
            modifier = Modifier.padding(horizontal = 8.dp),
            style = MaterialTheme.typography.labelSmall,
            color = F7Colors.Primary,
            fontWeight = FontWeight.Medium,
        )
        Box(
            modifier = Modifier
                .weight(1f)
                .height(1.dp)
                .background(F7Colors.Primary.copy(alpha = 0.35f)),
        )
    }
}

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun TalkMessageActionSheet(
    message: TalkMessage?,
    canModify: Boolean,
    onDismiss: () -> Unit,
    onReply: (TalkMessage) -> Unit,
    onEdit: (TalkMessage) -> Unit,
    onDelete: (TalkMessage) -> Unit,
    onReaction: (TalkMessage, String) -> Unit,
) {
    if (message == null) return
    val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true)
    ModalBottomSheet(onDismissRequest = onDismiss, sheetState = sheetState, containerColor = F7Colors.Surface) {
        Column(
            modifier = Modifier
                .fillMaxWidth()
                .padding(horizontal = 16.dp, vertical = 8.dp),
            verticalArrangement = Arrangement.spacedBy(4.dp),
        ) {
            Text(
                message.actorDisplayName,
                style = MaterialTheme.typography.labelMedium,
                color = F7Colors.TextSecondary,
            )
            Text(
                formatMessageText(message.text).take(120),
                style = MaterialTheme.typography.bodySmall,
                color = F7Colors.ChatText,
                modifier = Modifier.padding(bottom = 8.dp),
            )
            F7TextButton(text = "Ответить", onClick = { onReply(message) })
            Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
                listOf("👍", "❤️", "😂").forEach { emoji ->
                    F7TextButton(text = emoji, onClick = { onReaction(message, emoji) })
                }
            }
            if (canModify) {
                F7TextButton(text = "Изменить", onClick = { onEdit(message) })
                F7TextButton(text = "Удалить", onClick = { onDelete(message) })
            }
            F7TextButton(text = "Отмена", onClick = onDismiss)
            Spacer(modifier = Modifier.height(16.dp))
        }
    }
}

@Composable
fun TalkMessageBody(
    session: AuthSession,
    message: TalkMessage,
) {
    val context = LocalContext.current
    Column(verticalArrangement = Arrangement.spacedBy(6.dp)) {
        if (message.replyToId != null) {
            Text(
                "↩ ответ",
                style = MaterialTheme.typography.labelSmall,
                color = F7Colors.TextSecondary,
            )
        }
        when {
            message.isVoiceMessage -> {
                Row(
                    verticalAlignment = Alignment.CenterVertically,
                    horizontalArrangement = Arrangement.spacedBy(8.dp),
                ) {
                    AsyncImage(
                        model = TalkAssets.spreed(session, "micro-icon-black.svg"),
                        contentDescription = null,
                        modifier = Modifier.size(18.dp),
                    )
                    Text(
                        "Голосовое сообщение",
                        style = MaterialTheme.typography.bodyMedium,
                        color = F7Colors.ChatText,
                    )
                }
            }
            else -> {
                val previewUrl = when {
                    message.hasImageAttachment && !message.attachmentFileId.isNullOrBlank() ->
                        TalkUrls.filePreview(session, message.attachmentFileId!!)
                    else -> extractMarkdownImageUrl(message.text)
                }
                if (!previewUrl.isNullOrBlank()) {
                    val request = ImageRequest.Builder(context)
                        .data(previewUrl)
                        .crossfade(true)
                        .apply {
                            addHeader(
                                "Authorization",
                                Credentials.basic(session.username, session.appPassword),
                            )
                        }
                        .build()
                    SubcomposeAsyncImage(
                        model = request,
                        contentDescription = message.attachmentFileName,
                        modifier = Modifier
                            .fillMaxWidth()
                            .heightIn(max = 240.dp)
                            .clip(RoundedCornerShape(8.dp)),
                        contentScale = ContentScale.Crop,
                        loading = {
                            Box(
                                modifier = Modifier
                                    .fillMaxWidth()
                                    .height(120.dp),
                                contentAlignment = Alignment.Center,
                            ) {
                                CircularProgressIndicator(modifier = Modifier.size(24.dp))
                            }
                        },
                    )
                }
                if (!message.attachmentFileName.isNullOrBlank() && !message.hasImageAttachment) {
                    // Живая тема: карточка файла — круглая иконка типа 49dp + имя 14/500
                    // (иконки типов — общие assets/filetypes из модуля files, мержатся в APK)
                    Row(
                        verticalAlignment = Alignment.CenterVertically,
                        horizontalArrangement = Arrangement.spacedBy(10.dp),
                    ) {
                        AsyncImage(
                            model = "file:///android_asset/filetypes/${talkFileTypeIcon(message.attachmentFileName!!)}.svg",
                            contentDescription = null,
                            modifier = Modifier.size(49.dp),
                        )
                        Text(
                            message.attachmentFileName!!,
                            style = MaterialTheme.typography.bodyMedium,
                            color = F7Colors.ChatText,
                            fontWeight = FontWeight.Medium,
                            maxLines = 1,
                            overflow = TextOverflow.Ellipsis,
                        )
                    }
                }
                val display = buildMessageDisplayText(message.text)
                if (display.text.isNotBlank()) {
                    Text(
                        display,
                        style = MaterialTheme.typography.bodyMedium,
                        color = F7Colors.ChatText,
                    )
                }
            }
        }
    }
}

@OptIn(ExperimentalFoundationApi::class)
@Composable
fun TalkMessageGroupRow(
    session: AuthSession,
    group: TalkChatItem.MessageGroup,
    modifier: Modifier = Modifier,
    highlightMessageId: Long? = null,
    onLongPress: ((TalkMessage) -> Unit)? = null,
    onReaction: ((TalkMessage, String) -> Unit)? = null,
) {
    val bubbleShape = RoundedCornerShape(8.dp)
    Row(
        modifier = modifier.fillMaxWidth(),
        horizontalArrangement = if (group.outgoing) Arrangement.End else Arrangement.Start,
        verticalAlignment = Alignment.Bottom,
    ) {
        if (!group.outgoing && group.showAuthor) {
            TalkAvatarImage(
                session = session,
                displayName = group.messages.first().actorDisplayName,
                avatarUrl = TalkUrls.userAvatar(session, group.messages.first().actorId),
                modifier = Modifier
                    .size(36.dp)
                    .padding(end = 8.dp),
            )
        } else if (!group.outgoing) {
            Spacer(Modifier.width(44.dp))
        }
        Column(
            modifier = Modifier.fillMaxWidth(0.88f),
            horizontalAlignment = if (group.outgoing) Alignment.End else Alignment.Start,
        ) {
            group.messages.forEachIndexed { index, message ->
                val showAuthor = group.showAuthor && index == 0 && group.outgoing.not()
                Column(
                    // Живая тема: зазор между сообщениями 4px (--f7-msg-gap)
                    modifier = Modifier.padding(vertical = 2.dp),
                    horizontalAlignment = if (group.outgoing) Alignment.End else Alignment.Start,
                ) {
                    Box(
                        modifier = Modifier
                            .shadow(
                                elevation = 1.dp,
                                shape = bubbleShape,
                                spotColor = Color.Black.copy(alpha = 0.06f),
                            )
                            .clip(bubbleShape)
                            .background(
                                when {
                                    message.id == highlightMessageId -> F7Colors.Primary.copy(alpha = 0.15f)
                                    group.outgoing -> F7Colors.ChatBubbleOut
                                    else -> F7Colors.ChatBubbleIn
                                },
                            )
                            .then(
                                if (message.id == highlightMessageId) {
                                    Modifier.border(2.dp, F7Colors.Primary, bubbleShape)
                                } else {
                                    Modifier
                                },
                            )
                            .combinedClickable(
                                onClick = {},
                                onLongClick = { onLongPress?.invoke(message) },
                            )
                            // Живая тема: паддинг пузыря 8px 10px
                            .padding(horizontal = 10.dp, vertical = 8.dp),
                    ) {
                        Column {
                            if (showAuthor) {
                                // Живая тема: автор ВНУТРИ пузыря, 12/600 чёрным
                                Text(
                                    message.actorDisplayName,
                                    fontSize = 12.sp,
                                    color = F7Colors.TextPrimary,
                                    fontWeight = FontWeight.SemiBold,
                                    modifier = Modifier.padding(bottom = 2.dp),
                                )
                            }
                            TalkMessageBody(session = session, message = message)
                        }
                    }
                    if (message.reactions.isNotEmpty()) {
                        Row(
                            horizontalArrangement = Arrangement.spacedBy(4.dp),
                            modifier = Modifier.padding(top = 2.dp, start = 4.dp),
                        ) {
                            message.reactions.forEach { (emoji, count) ->
                                Text(
                                    "$emoji $count",
                                    style = MaterialTheme.typography.labelSmall,
                                    modifier = Modifier
                                        .clip(RoundedCornerShape(8.dp))
                                        .background(F7Colors.Surface)
                                        .clickable { onReaction?.invoke(message, emoji) }
                                        .padding(horizontal = 6.dp, vertical = 2.dp),
                                )
                            }
                        }
                    }
                    if (index == group.messages.lastIndex && message.timestamp > 0) {
                        Row(
                            horizontalArrangement = Arrangement.spacedBy(4.dp),
                            verticalAlignment = Alignment.CenterVertically,
                        ) {
                            Text(
                                formatTalkTime(message.timestamp),
                                fontSize = 12.sp,
                                color = F7Colors.TextMuted,
                            )
                            if (group.outgoing && message.status == TalkMessage.Status.SENT) {
                                AsyncImage(
                                    model = TalkAssets.spreed(session, "message-check-read.svg"),
                                    contentDescription = "Доставлено",
                                    modifier = Modifier.size(12.dp),
                                )
                            }
                        }
                    }
                }
            }
        }
    }
}

@Composable
fun TalkScrollToBottomFab(
    session: AuthSession,
    visible: Boolean,
    onClick: () -> Unit,
    modifier: Modifier = Modifier,
) {
    if (!visible) return
    Box(
        modifier = modifier
            .size(40.dp)
            .clip(CircleShape)
            .background(Color(0xFFECF9DE))
            .border(1.dp, F7Colors.Border, CircleShape)
            .clickable(onClick = onClick),
        contentAlignment = Alignment.Center,
    ) {
        AsyncImage(
            model = TalkAssets.spreed(session, "scroll-to-bottom-chevron.svg"),
            contentDescription = "Вниз",
            modifier = Modifier.size(18.dp),
        )
    }
}

@Composable
fun TalkComposer(
    session: AuthSession,
    value: String,
    onValueChange: (String) -> Unit,
    onSend: () -> Unit,
    onAttach: (() -> Unit)? = null,
    onVoiceToggle: (() -> Unit)? = null,
    voiceRecording: Boolean = false,
    mentionCandidates: List<TalkMention> = emptyList(),
    onMentionQuery: ((String?) -> Unit)? = null,
    onMentionSelected: ((TalkMention) -> Unit)? = null,
    sending: Boolean,
    uploading: Boolean = false,
    modifier: Modifier = Modifier,
) {
    val busy = sending || uploading
    var emojiOpen by remember { mutableStateOf(false) }

    LaunchedEffect(value) {
        if (onMentionQuery == null) return@LaunchedEffect
        val at = value.lastIndexOf('@')
        if (at < 0 || (at > 0 && !value[at - 1].isWhitespace())) {
            onMentionQuery(null)
            return@LaunchedEffect
        }
        val tail = value.substring(at + 1)
        if (tail.contains(' ') || tail.contains('\n')) {
            onMentionQuery(null)
        } else {
            onMentionQuery(tail)
        }
    }

    Column(modifier = modifier.fillMaxWidth(), verticalArrangement = Arrangement.spacedBy(4.dp)) {
        TalkEmojiPicker(
            visible = emojiOpen,
            onDismiss = { emojiOpen = false },
            onEmojiSelected = { onValueChange(value + it) },
        )
        if (mentionCandidates.isNotEmpty() && onMentionSelected != null) {
            Surface(
                shape = RoundedCornerShape(12.dp),
                color = F7Colors.Surface,
                shadowElevation = 2.dp,
                modifier = Modifier.fillMaxWidth(),
            ) {
                Column {
                    mentionCandidates.take(6).forEach { mention ->
                        Row(
                            modifier = Modifier
                                .fillMaxWidth()
                                .clickable { onMentionSelected(mention) }
                                .padding(horizontal = 12.dp, vertical = 10.dp),
                            verticalAlignment = Alignment.CenterVertically,
                            horizontalArrangement = Arrangement.spacedBy(8.dp),
                        ) {
                            Text(
                                mention.label,
                                style = MaterialTheme.typography.bodyMedium,
                                fontWeight = FontWeight.Medium,
                            )
                            Text(
                                "@${mention.mentionId}",
                                style = MaterialTheme.typography.labelSmall,
                                color = F7Colors.TextSecondary,
                            )
                        }
                    }
                }
            }
        }
        Row(
            modifier = Modifier
                .fillMaxWidth()
                .heightIn(min = 45.dp)
                .clip(RoundedCornerShape(100.dp))
                .background(Color(0xFDFDFDFF))
                .border(1.dp, F7Colors.TalkComposerBorder, RoundedCornerShape(100.dp))
                .padding(horizontal = 5.dp, vertical = 4.dp),
            verticalAlignment = Alignment.CenterVertically,
            horizontalArrangement = Arrangement.spacedBy(2.dp),
        ) {
            if (onAttach != null) {
                Box(
                    modifier = Modifier
                        .size(36.dp)
                        .clickable(enabled = !busy && !voiceRecording, onClick = onAttach),
                    contentAlignment = Alignment.Center,
                ) {
                    AsyncImage(
                        model = TalkAssets.spreed(session, "paramrts-black.svg"),
                        contentDescription = "Вложение",
                        modifier = Modifier.size(20.dp),
                    )
                }
            }
            Box(
                modifier = Modifier
                    .size(36.dp)
                    .clickable(enabled = !busy && !voiceRecording) { emojiOpen = !emojiOpen },
                contentAlignment = Alignment.Center,
            ) {
                AsyncImage(
                    model = TalkAssets.spreed(session, "smile-icon-black.svg"),
                    contentDescription = "Смайлики",
                    modifier = Modifier.size(18.dp),
                )
            }
            OutlinedTextField(
                value = value,
                onValueChange = onValueChange,
                modifier = Modifier.weight(1f),
                enabled = !voiceRecording,
                placeholder = {
                    Text(
                        if (voiceRecording) "Запись…" else "Напишите сообщение…",
                        color = F7Colors.TextSecondary,
                        fontSize = 14.sp,
                    )
                },
                minLines = 1,
                maxLines = 4,
                shape = RoundedCornerShape(100.dp),
                colors = OutlinedTextFieldDefaults.colors(
                    focusedContainerColor = Color.Transparent,
                    unfocusedContainerColor = Color.Transparent,
                    focusedBorderColor = Color.Transparent,
                    unfocusedBorderColor = Color.Transparent,
                    disabledBorderColor = Color.Transparent,
                ),
            )
            val hasText = value.isNotBlank()
            if (hasText) {
                Box(
                    modifier = Modifier
                        .size(38.dp)
                        .clip(CircleShape)
                        .background(
                            brush = androidx.compose.ui.graphics.Brush.linearGradient(
                                listOf(Color(0xCC70B62B), Color(0xFF70B62B)),
                            ),
                            shape = CircleShape,
                        )
                        .clickable(enabled = !busy, onClick = onSend),
                    contentAlignment = Alignment.Center,
                ) {
                    if (busy) {
                        Text("…", color = Color.White, fontWeight = FontWeight.Bold)
                    } else {
                        AsyncImage(
                            model = TalkAssets.spreed(session, "chevron-up-icon-white.svg"),
                            contentDescription = "Отправить",
                            modifier = Modifier.size(16.dp),
                        )
                    }
                }
            } else if (onVoiceToggle != null) {
                Box(
                    modifier = Modifier
                        .size(38.dp)
                        .clip(CircleShape)
                        .then(
                            if (voiceRecording) {
                                Modifier.background(Color(0xFFD74642), CircleShape)
                            } else {
                                Modifier.background(
                                    brush = androidx.compose.ui.graphics.Brush.linearGradient(
                                        listOf(Color(0xE8C0FF7B), Color(0xE870B62B)),
                                    ),
                                    shape = CircleShape,
                                )
                            },
                        )
                        .clickable(enabled = !busy, onClick = onVoiceToggle),
                    contentAlignment = Alignment.Center,
                ) {
                    AsyncImage(
                        model = TalkAssets.spreed(
                            session,
                            if (voiceRecording) "micro-off-gray.svg" else "micro-icon-white.svg",
                        ),
                        contentDescription = if (voiceRecording) "Остановить запись" else "Голосовое",
                        modifier = Modifier.size(18.dp),
                    )
                }
            }
        }
    }
}

@Composable
fun TalkMessageRow(
    message: TalkMessage,
    outgoing: Boolean,
    modifier: Modifier = Modifier,
) {
    Column(modifier = modifier.fillMaxWidth()) {
        if (message.isSystemMessage) {
            Text(
                message.displayText,
                modifier = Modifier
                    .fillMaxWidth()
                    .padding(vertical = 4.dp),
                style = MaterialTheme.typography.labelSmall,
                color = F7Colors.TextSecondary,
            )
        } else {
            ru.forbion.f7cloud.core.designsystem.F7ChatBubble(
                text = formatMessageText(message.text),
                outgoing = outgoing,
                subtitle = if (!outgoing) message.actorDisplayName else null,
            )
            if (message.timestamp > 0) {
                Text(
                    formatTalkTime(message.timestamp),
                    modifier = Modifier.padding(start = if (outgoing) 0.dp else 8.dp, top = 2.dp),
                    style = MaterialTheme.typography.labelSmall,
                    color = F7Colors.TextSecondary,
                )
            }
        }
    }
}

fun formatTalkTime(epochSeconds: Long): String {
    val date = Date(epochSeconds * 1000L)
    val now = Calendar.getInstance()
    val then = Calendar.getInstance().apply { time = date }
    return when {
        now.get(Calendar.YEAR) == then.get(Calendar.YEAR) &&
            now.get(Calendar.DAY_OF_YEAR) == then.get(Calendar.DAY_OF_YEAR) ->
            DateFormat.getTimeInstance(DateFormat.SHORT).format(date)
        abs(now.timeInMillis - then.timeInMillis) < 7L * 24 * 3600 * 1000 ->
            DateFormat.getDateInstance(DateFormat.SHORT).format(date)
        else ->
            DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT).format(date)
    }
}

internal fun roomTypeLabel(type: Int): String = when (type) {
    1 -> "Личный чат"
    2 -> "Групповой чат"
    3 -> "Публичный чат"
    4 -> "Обновления"
    else -> "Чат"
}

private fun talkAvatarColor(seed: String): Color {
    val palette = listOf(
        Color(0xFF0082C9),
        Color(0xFF46BA61),
        Color(0xFFAA66CC),
        Color(0xFFFFB300),
        Color(0xFFE53935),
        Color(0xFF00ACC1),
    )
    val idx = abs(seed.hashCode()) % palette.size
    return palette[idx]
}

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun TalkParticipantsSheet(
    visible: Boolean,
    session: AuthSession,
    participants: List<TalkParticipant>,
    loading: Boolean,
    onDismiss: () -> Unit,
) {
    if (!visible) return
    val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true)
    ModalBottomSheet(
        onDismissRequest = onDismiss,
        sheetState = sheetState,
        containerColor = F7Colors.Surface,
    ) {
        Column(
            modifier = Modifier
                .fillMaxWidth()
                .padding(horizontal = 16.dp, vertical = 8.dp),
            verticalArrangement = Arrangement.spacedBy(8.dp),
        ) {
            Text("Участники", style = MaterialTheme.typography.titleMedium)
            Text(
                "${participants.size} чел.",
                style = MaterialTheme.typography.bodySmall,
                color = F7Colors.TextSecondary,
            )
            Spacer(Modifier.height(4.dp))
            if (loading) {
                CircularProgressIndicator(color = F7Colors.Primary)
            } else if (participants.isEmpty()) {
                Text("Нет участников", color = F7Colors.TextSecondary)
            } else {
                participants.forEach { participant ->
                    TalkParticipantRow(session = session, participant = participant)
                }
            }
            Spacer(Modifier.height(16.dp))
        }
    }
}

@Composable
fun TalkParticipantRow(
    session: AuthSession,
    participant: TalkParticipant,
    modifier: Modifier = Modifier,
) {
    Row(
        modifier = modifier
            .fillMaxWidth()
            .clip(RoundedCornerShape(12.dp))
            .background(F7Colors.Background)
            .padding(horizontal = 12.dp, vertical = 10.dp),
        verticalAlignment = Alignment.CenterVertically,
    ) {
        TalkAvatarImage(
            session = session,
            displayName = participant.displayName,
            avatarUrl = if (participant.actorType == "users") {
                TalkUrls.userAvatar(session, participant.actorId)
            } else {
                null
            },
            modifier = Modifier.size(40.dp),
            showCallBadge = participant.isInCall,
        )
        Spacer(Modifier.width(12.dp))
        Column(modifier = Modifier.weight(1f)) {
            Text(
                participant.displayName,
                style = MaterialTheme.typography.bodyMedium,
                fontWeight = FontWeight.Medium,
                maxLines = 1,
                overflow = TextOverflow.Ellipsis,
            )
            Text(
                buildString {
                    append(participant.roleLabel)
                    append(" · ")
                    append(userStatusLabel(participant.status))
                    if (participant.isInCall) append(" · в звонке")
                },
                style = MaterialTheme.typography.labelSmall,
                color = F7Colors.TextSecondary,
            )
        }
        if (participant.isInCall) {
            Box(
                modifier = Modifier
                    .size(10.dp)
                    .clip(CircleShape)
                    .background(CallBadgeColor),
            )
        }
    }
}

@OptIn(ExperimentalMaterial3Api::class, ExperimentalLayoutApi::class)
@Composable
fun TalkCreateRoomSheet(
    visible: Boolean,
    session: AuthSession,
    mode: CreateRoomMode,
    roomName: String,
    userSearchQuery: String,
    userSearchResults: List<TalkUserCandidate>,
    selectedUsers: List<TalkUserCandidate>,
    userSearchLoading: Boolean,
    creating: Boolean,
    onDismiss: () -> Unit,
    onModeChange: (CreateRoomMode) -> Unit,
    onRoomNameChange: (String) -> Unit,
    onUserSearchChange: (String) -> Unit,
    onUserToggle: (TalkUserCandidate) -> Unit,
    onCreate: () -> Unit,
) {
    if (!visible) return
    val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true)
    ModalBottomSheet(
        onDismissRequest = onDismiss,
        sheetState = sheetState,
        containerColor = F7Colors.Surface,
    ) {
        Column(
            modifier = Modifier
                .fillMaxWidth()
                .padding(horizontal = 16.dp, vertical = 8.dp),
            verticalArrangement = Arrangement.spacedBy(12.dp),
        ) {
            Text("Новый чат", style = MaterialTheme.typography.titleMedium)
            Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
                val personalSelected = mode == CreateRoomMode.ONE_TO_ONE
                Row(
                    modifier = Modifier
                        .clip(RoundedCornerShape(100.dp))
                        .background(if (personalSelected) F7Colors.PrimaryLight else F7Colors.Background)
                        .clickable { onModeChange(CreateRoomMode.ONE_TO_ONE) }
                        .padding(horizontal = 16.dp, vertical = 10.dp),
                ) {
                    Text("Личный", fontWeight = if (personalSelected) FontWeight.SemiBold else FontWeight.Normal)
                }
                val groupSelected = mode == CreateRoomMode.GROUP
                Row(
                    modifier = Modifier
                        .clip(RoundedCornerShape(100.dp))
                        .background(if (groupSelected) F7Colors.PrimaryLight else F7Colors.Background)
                        .clickable { onModeChange(CreateRoomMode.GROUP) }
                        .padding(horizontal = 16.dp, vertical = 10.dp),
                ) {
                    Text("Группа", fontWeight = if (groupSelected) FontWeight.SemiBold else FontWeight.Normal)
                }
            }
            if (mode == CreateRoomMode.GROUP) {
                OutlinedTextField(
                    value = roomName,
                    onValueChange = onRoomNameChange,
                    modifier = Modifier.fillMaxWidth(),
                    placeholder = { Text("Название группы") },
                    singleLine = true,
                    shape = RoundedCornerShape(12.dp),
                    colors = OutlinedTextFieldDefaults.colors(
                        focusedContainerColor = F7Colors.Surface,
                        unfocusedContainerColor = F7Colors.Surface,
                    ),
                )
            }
            OutlinedTextField(
                value = userSearchQuery,
                onValueChange = onUserSearchChange,
                modifier = Modifier.fillMaxWidth(),
                placeholder = { Text("Поиск пользователя") },
                singleLine = true,
                shape = RoundedCornerShape(24.dp),
                colors = OutlinedTextFieldDefaults.colors(
                    focusedContainerColor = F7Colors.Surface,
                    unfocusedContainerColor = F7Colors.Surface,
                ),
            )
            if (selectedUsers.isNotEmpty()) {
                FlowRow(
                    horizontalArrangement = Arrangement.spacedBy(8.dp),
                    verticalArrangement = Arrangement.spacedBy(8.dp),
                ) {
                    selectedUsers.forEach { user ->
                        Row(
                            modifier = Modifier
                                .clip(RoundedCornerShape(100.dp))
                                .background(F7Colors.PrimaryLight)
                                .clickable { onUserToggle(user) }
                                .padding(horizontal = 12.dp, vertical = 6.dp),
                            verticalAlignment = Alignment.CenterVertically,
                        ) {
                            Text(user.displayName, style = MaterialTheme.typography.labelMedium)
                            Spacer(Modifier.width(6.dp))
                            Text("×", color = F7Colors.TextSecondary)
                        }
                    }
                }
            }
            if (userSearchLoading) {
                CircularProgressIndicator(color = F7Colors.Primary)
            } else if (userSearchQuery.trim().length >= 2) {
                LazyColumn(
                    modifier = Modifier.height(180.dp),
                    verticalArrangement = Arrangement.spacedBy(4.dp),
                ) {
                    items(userSearchResults, key = { it.userId }) { user ->
                        val selected = selectedUsers.any { it.userId == user.userId }
                        Row(
                            modifier = Modifier
                                .fillMaxWidth()
                                .clip(RoundedCornerShape(12.dp))
                                .background(if (selected) F7Colors.PrimaryLight else Color.Transparent)
                                .clickable { onUserToggle(user) }
                                .padding(horizontal = 12.dp, vertical = 10.dp),
                            verticalAlignment = Alignment.CenterVertically,
                        ) {
                            TalkAvatarImage(
                                session = session,
                                displayName = user.displayName,
                                avatarUrl = TalkUrls.userAvatar(session, user.userId),
                                modifier = Modifier.size(36.dp),
                            )
                            Spacer(Modifier.width(12.dp))
                            Column(modifier = Modifier.weight(1f)) {
                                Text(
                                    user.displayName,
                                    style = MaterialTheme.typography.bodyMedium,
                                    maxLines = 1,
                                    overflow = TextOverflow.Ellipsis,
                                )
                                Text(
                                    user.userId,
                                    style = MaterialTheme.typography.labelSmall,
                                    color = F7Colors.TextSecondary,
                                    maxLines = 1,
                                    overflow = TextOverflow.Ellipsis,
                                )
                            }
                            if (selected) Text("✓", color = F7Colors.Primary)
                        }
                    }
                }
            }
            F7PrimaryButton(
                text = if (mode == CreateRoomMode.ONE_TO_ONE) "Начать чат" else "Создать группу",
                onClick = onCreate,
                enabled = !creating && selectedUsers.isNotEmpty(),
            )
            Spacer(Modifier.height(16.dp))
        }
    }
}

/** Иконка типа файла для вложений чата (тот же набор assets/filetypes, что в Файлах). */
internal fun talkFileTypeIcon(name: String): String =
    when (name.substringAfterLast('.', "").lowercase()) {
        "doc", "docx", "dot", "dotx", "odt", "rtf" -> "word"
        "xls", "xlsx", "xlsm", "ods", "csv" -> "spreadsheet"
        "ppt", "pptx", "odp" -> "presentation"
        "pdf" -> "pdf"
        "jpg", "jpeg", "png", "gif", "webp", "bmp", "svg", "heic" -> "image"
        "mp3", "wav", "ogg", "flac", "aac" -> "audio"
        "mp4", "mkv", "avi", "mov", "webm" -> "video"
        "zip", "rar", "7z", "tar", "gz" -> "archive"
        "txt", "md", "log" -> "text"
        else -> "file"
    }
