package com.seven.ikar.kotlin.feature.stories

import android.net.Uri
import androidx.activity.compose.BackHandler
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.border
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.WindowInsetsSides
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.imePadding
import androidx.compose.foundation.layout.only
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.safeDrawing
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.BasicTextField
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.icons.automirrored.outlined.Send
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Add
import androidx.compose.material.icons.outlined.Close
import androidx.compose.material.icons.outlined.Delete
import androidx.compose.material.icons.outlined.Schedule
import androidx.compose.material3.Button
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.LinearProgressIndicator
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog
import androidx.compose.ui.window.DialogProperties
import androidx.compose.ui.viewinterop.AndroidView
import androidx.media3.common.MediaItem
import androidx.media3.common.Player
import androidx.media3.datasource.DefaultHttpDataSource
import androidx.media3.exoplayer.ExoPlayer
import androidx.media3.exoplayer.source.ProgressiveMediaSource
import androidx.media3.ui.AspectRatioFrameLayout
import androidx.media3.ui.PlayerView
import coil.compose.AsyncImage
import com.seven.ikar.kotlin.core.model.AttachmentDto
import com.seven.ikar.kotlin.core.model.StoryDto
import com.seven.ikar.kotlin.core.model.StoryViewDto
import com.seven.ikar.kotlin.core.model.StoryVisibility
import com.seven.ikar.kotlin.core.network.ServerConfig
import com.seven.ikar.kotlin.ui.AuthenticatedAsyncImage
import com.seven.ikar.kotlin.ui.AvatarView
import com.seven.ikar.kotlin.ui.IkarHeaderIconBubble
import com.seven.ikar.kotlin.ui.IkarRowDivider
import com.seven.ikar.kotlin.ui.IkarScreenSurface
import com.seven.ikar.kotlin.ui.IkarSectionCard
import com.seven.ikar.kotlin.ui.IkarSectionTitle
import com.seven.ikar.kotlin.ui.IkarSimpleHeader
import com.seven.ikar.kotlin.ui.IkarToggleRow
import com.seven.ikar.kotlin.ui.SecureWindowEffect
import com.seven.ikar.kotlin.ui.theme.TelegramBlue
import com.seven.ikar.kotlin.ui.theme.TelegramInkMuted
import kotlinx.coroutines.delay
import java.io.File

private const val StoryAutoAdvanceDurationMillis = 5_000L
private const val StoryAutoAdvanceTickMillis = 50L

@Composable
fun StoriesScreen(
    state: StoriesUiState,
    onBackClick: () -> Unit,
    onComposeClick: () -> Unit,
    onRefreshClick: () -> Unit,
    onStoryClick: (StoryDto) -> Unit,
    onDeleteStory: (StoryDto) -> Unit,
    onCloseStoryPreview: () -> Unit,
    onNextStory: () -> Unit,
    onPreviousStory: () -> Unit,
    onStoryReplyTextChanged: (String) -> Unit,
    onSendStoryReply: (StoryDto) -> Unit,
    onSendStoryReaction: (StoryDto, String) -> Unit,
    onShowStoryViews: (StoryDto) -> Unit,
    onCloseStoryViews: () -> Unit,
    onRetryTransfer: (String) -> Unit,
    onCancelTransfer: (String) -> Unit
) {
    SecureWindowEffect(enabled = state.selectedStory?.hasProtectedContent == true)

    state.selectedStory?.let { story ->
        StoryViewerDialog(
            story = story,
            stories = state.stories,
            accessToken = state.accessToken,
            isOwnStory = story.author.id == state.currentUserId,
            replyText = state.storyReplyText,
            isSendingReply = state.isSendingStoryReply,
            replyErrorMessage = state.storyReplyErrorMessage,
            replySent = state.storyReplySentStoryId == story.id,
            storyViews = state.storyViews.takeIf { state.storyViewsStoryId == story.id }.orEmpty(),
            isLoadingStoryViews = state.isLoadingStoryViews && state.storyViewsStoryId == story.id,
            storyViewsErrorMessage = state.storyViewsErrorMessage.takeIf { state.storyViewsStoryId == story.id },
            showStoryViews = state.storyViewsStoryId == story.id,
            onClose = onCloseStoryPreview,
            onNextStory = onNextStory,
            onPreviousStory = onPreviousStory,
            onReplyTextChanged = onStoryReplyTextChanged,
            onSendReply = { onSendStoryReply(story) },
            onSendReaction = { emoji -> onSendStoryReaction(story, emoji) },
            onShowStoryViews = { onShowStoryViews(story) },
            onCloseStoryViews = onCloseStoryViews,
            onDeleteStory = { onDeleteStory(story) }
        )
    }

    IkarScreenSurface(modifier = Modifier.fillMaxSize()) {
        Column(
            modifier = Modifier
                .fillMaxSize()
                .windowInsetsPadding(WindowInsets.safeDrawing.only(WindowInsetsSides.Vertical))
                .verticalScroll(rememberScrollState())
                .padding(horizontal = 18.dp, vertical = 16.dp),
            verticalArrangement = Arrangement.spacedBy(16.dp)
        ) {
            IkarSimpleHeader(
                title = "Истории",
                onBackClick = onBackClick,
                rightContent = {
                    IkarHeaderIconBubble(onClick = onComposeClick) {
                        Icon(Icons.Outlined.Add, contentDescription = null, tint = TelegramBlue)
                    }
                }
            )

            if (state.activeTransfers.isNotEmpty()) {
                StoryTransfersCard(
                    transfers = state.activeTransfers,
                    onRetryTransfer = onRetryTransfer,
                    onCancelTransfer = onCancelTransfer
                )
            }

            state.errorMessage?.let { message ->
                IkarSectionCard {
                    Text("Ошибка", style = MaterialTheme.typography.titleMedium, color = MaterialTheme.colorScheme.error)
                    Text(message, modifier = Modifier.padding(top = 6.dp), style = MaterialTheme.typography.bodySmall, color = TelegramInkMuted)
                }
            }

            IkarSectionCard {
                Row(
                    modifier = Modifier.fillMaxWidth(),
                    horizontalArrangement = Arrangement.SpaceBetween,
                    verticalAlignment = Alignment.CenterVertically
                ) {
                    IkarSectionTitle("Сегодня")
                    TextButton(onClick = onRefreshClick) {
                        Text(if (state.isLoading) "Загрузка..." else "Обновить")
                    }
                }

                if (state.stories.isEmpty()) {
                    EmptyStoriesState(onComposeClick = onComposeClick)
                } else {
                    state.stories.forEachIndexed { index, story ->
                        StoryPreviewRow(story = story, accessToken = state.accessToken, onClick = { onStoryClick(story) })
                        if (index != state.stories.lastIndex) {
                            IkarRowDivider()
                        }
                    }
                }
            }

            IkarSectionCard {
                Row(
                    modifier = Modifier.fillMaxWidth(),
                    horizontalArrangement = Arrangement.spacedBy(12.dp),
                    verticalAlignment = Alignment.CenterVertically
                ) {
                    Icon(Icons.Outlined.Schedule, contentDescription = null, tint = TelegramBlue)
                    Column(verticalArrangement = Arrangement.spacedBy(4.dp)) {
                        Text("Медиаистории подключены", style = MaterialTheme.typography.titleLarge)
                        Text(
                            "Текстовые истории публикуются сразу, а медиаистории уходят через очередь фоновой отправки с прогрессом, повтором и отменой.",
                            style = MaterialTheme.typography.bodySmall,
                            color = TelegramInkMuted
                        )
                    }
                }
            }
        }
    }
}

@Composable
fun StoryComposerScreen(
    state: StoriesUiState,
    onBackClick: () -> Unit,
    onTextChanged: (String) -> Unit,
    onVisibilityChanged: (StoryVisibility) -> Unit,
    onProtectedChanged: (Boolean) -> Unit,
    onTtlChanged: (Int) -> Unit,
    onMediaSelected: (List<Uri>) -> Unit,
    onRemoveMedia: (String) -> Unit,
    onClearMedia: () -> Unit,
    onCreateClick: () -> Unit,
    onRetryTransfer: (String) -> Unit,
    onCancelTransfer: (String) -> Unit
) {
    val mediaPicker = rememberLauncherForActivityResult(ActivityResultContracts.OpenMultipleDocuments()) { uris ->
        onMediaSelected(uris)
    }

    IkarScreenSurface(modifier = Modifier.fillMaxSize()) {
        Column(
            modifier = Modifier
                .fillMaxSize()
                .windowInsetsPadding(WindowInsets.safeDrawing.only(WindowInsetsSides.Vertical))
                .verticalScroll(rememberScrollState())
                .padding(horizontal = 18.dp, vertical = 16.dp),
            verticalArrangement = Arrangement.spacedBy(16.dp)
        ) {
            IkarSimpleHeader(title = "Новая история", onBackClick = onBackClick)

            if (state.activeTransfers.isNotEmpty()) {
                StoryTransfersCard(
                    transfers = state.activeTransfers,
                    onRetryTransfer = onRetryTransfer,
                    onCancelTransfer = onCancelTransfer
                )
            }

            IkarSectionCard {
                Row(
                    modifier = Modifier.fillMaxWidth(),
                    horizontalArrangement = Arrangement.SpaceBetween,
                    verticalAlignment = Alignment.CenterVertically
                ) {
                    IkarSectionTitle("Медиа")
                    Text("${state.pendingMedia.size}/10", style = MaterialTheme.typography.bodySmall, color = TelegramInkMuted)
                }
                OutlinedButton(
                    onClick = { mediaPicker.launch(arrayOf("image/*", "video/*")) },
                    enabled = !state.isImportingMedia && state.pendingMedia.size < 10,
                    modifier = Modifier
                        .fillMaxWidth()
                        .padding(top = 10.dp)
                ) {
                    Text(if (state.isImportingMedia) "Импортируем..." else "Добавить фото или видео")
                }
                if (state.pendingMedia.isNotEmpty()) {
                    MediaPreviewGrid(
                        media = state.pendingMedia,
                        onRemoveMedia = onRemoveMedia,
                        modifier = Modifier.padding(top = 12.dp)
                    )
                    TextButton(onClick = onClearMedia, modifier = Modifier.fillMaxWidth()) {
                        Text("Очистить медиа")
                    }
                }
            }

            IkarSectionCard {
                Text("Текст", style = MaterialTheme.typography.titleLarge)
                BasicTextField(
                    value = state.draftText,
                    onValueChange = onTextChanged,
                    modifier = Modifier
                        .fillMaxWidth()
                        .padding(top = 12.dp)
                        .background(Color(0xFFF2F6FA), RoundedCornerShape(18.dp))
                        .padding(14.dp),
                    textStyle = MaterialTheme.typography.bodyLarge.copy(color = MaterialTheme.colorScheme.onSurface),
                    decorationBox = { inner ->
                        if (state.draftText.isBlank()) {
                            Text("Что происходит?", color = TelegramInkMuted, style = MaterialTheme.typography.bodyLarge)
                        }
                        inner()
                    }
                )
                Text("${state.draftText.length}/500", modifier = Modifier.padding(top = 8.dp), style = MaterialTheme.typography.bodySmall, color = TelegramInkMuted)
            }

            IkarSectionCard {
                IkarSectionTitle("Кто увидит", modifier = Modifier.padding(bottom = 10.dp))
                StoryVisibility.entries.forEachIndexed { index, visibility ->
                    StoryOptionRow(
                        title = visibility.label(),
                        subtitle = visibility.subtitle(),
                        selected = state.visibility == visibility,
                        onClick = { onVisibilityChanged(visibility) }
                    )
                    if (index != StoryVisibility.entries.lastIndex) {
                        IkarRowDivider(startIndent = 0.dp)
                    }
                }
            }

            IkarSectionCard {
                IkarSectionTitle("Срок жизни", modifier = Modifier.padding(bottom = 10.dp))
                Row(horizontalArrangement = Arrangement.spacedBy(8.dp), modifier = Modifier.fillMaxWidth()) {
                    listOf(3_600, 43_200, 86_400, 604_800).forEach { ttl ->
                        Surface(
                            modifier = Modifier
                                .weight(1f)
                                .clickable { onTtlChanged(ttl) },
                            color = if (state.ttlSeconds == ttl) Color(0xFFEAF4FF) else Color(0xFFF2F6FA),
                            shape = RoundedCornerShape(16.dp)
                        ) {
                            Text(
                                ttl.labelTtl(),
                                modifier = Modifier.padding(vertical = 12.dp),
                                style = MaterialTheme.typography.bodyMedium,
                                color = if (state.ttlSeconds == ttl) TelegramBlue else MaterialTheme.colorScheme.onSurface,
                                fontWeight = if (state.ttlSeconds == ttl) FontWeight.SemiBold else FontWeight.Normal
                            )
                        }
                    }
                }
            }

            IkarSectionCard {
                IkarToggleRow(
                    "Защитить контент",
                    "Флаг передаётся серверу; клиент должен блокировать пересылку, сохранение и скриншоты там, где это возможно.",
                    state.hasProtectedContent,
                    onProtectedChanged
                )
            }

            state.errorMessage?.let { message ->
                Text(message, color = MaterialTheme.colorScheme.error, style = MaterialTheme.typography.bodySmall)
            }

            Button(
                onClick = onCreateClick,
                enabled = (state.draftText.isNotBlank() || state.pendingMedia.isNotEmpty()) && !state.isSaving,
                modifier = Modifier.fillMaxWidth()
            ) {
                val hasMedia = state.pendingMedia.isNotEmpty()
                Text(
                    when {
                        state.isSaving -> "Публикуем..."
                        hasMedia -> "Поставить в очередь"
                        else -> "Опубликовать"
                    }
                )
            }
        }
    }
}

@Composable
private fun StoryViewerDialog(
    story: StoryDto,
    stories: List<StoryDto>,
    accessToken: String?,
    isOwnStory: Boolean,
    replyText: String,
    isSendingReply: Boolean,
    replyErrorMessage: String?,
    replySent: Boolean,
    storyViews: List<StoryViewDto>,
    isLoadingStoryViews: Boolean,
    storyViewsErrorMessage: String?,
    showStoryViews: Boolean,
    onClose: () -> Unit,
    onNextStory: () -> Unit,
    onPreviousStory: () -> Unit,
    onReplyTextChanged: (String) -> Unit,
    onSendReply: () -> Unit,
    onSendReaction: (String) -> Unit,
    onShowStoryViews: () -> Unit,
    onCloseStoryViews: () -> Unit,
    onDeleteStory: () -> Unit
) {
    Dialog(
        onDismissRequest = onClose,
        properties = DialogProperties(usePlatformDefaultWidth = false)
    ) {
        BackHandler(onBack = onClose)
        var selectedMediaIndex by remember(story.id, story.attachments.size) { mutableIntStateOf(0) }
        val lastMediaIndex = (story.attachments.size - 1).coerceAtLeast(0)
        val safeMediaIndex = selectedMediaIndex.coerceIn(0, lastMediaIndex)
        var autoProgress by remember(story.id, safeMediaIndex) { mutableFloatStateOf(0f) }
        val autoAdvancePaused = showStoryViews || replyText.isNotBlank() || isSendingReply

        LaunchedEffect(story.id, safeMediaIndex, autoAdvancePaused) {
            autoProgress = 0f
            if (autoAdvancePaused) {
                return@LaunchedEffect
            }

            var elapsedMillis = 0L
            while (elapsedMillis < StoryAutoAdvanceDurationMillis) {
                delay(StoryAutoAdvanceTickMillis)
                elapsedMillis += StoryAutoAdvanceTickMillis
                autoProgress = (elapsedMillis.toFloat() / StoryAutoAdvanceDurationMillis)
                    .coerceIn(0f, 1f)
            }

            if (story.attachments.isNotEmpty() && safeMediaIndex < story.attachments.lastIndex) {
                selectedMediaIndex = safeMediaIndex + 1
            } else {
                onNextStory()
            }
        }

        Box(
            modifier = Modifier
                .fillMaxSize()
                .background(Color.Black)
        ) {
            StoryViewerContent(story = story, accessToken = accessToken, mediaIndex = safeMediaIndex)

            Row(modifier = Modifier.fillMaxSize()) {
                Box(
                    modifier = Modifier
                        .weight(1f)
                        .fillMaxSize()
                        .clickable {
                            if (safeMediaIndex > 0) {
                                selectedMediaIndex = safeMediaIndex - 1
                            } else {
                                onPreviousStory()
                            }
                        }
                )
                Box(
                    modifier = Modifier
                        .weight(1f)
                        .fillMaxSize()
                        .clickable {
                            if (story.attachments.isNotEmpty() && safeMediaIndex < story.attachments.lastIndex) {
                                selectedMediaIndex = safeMediaIndex + 1
                            } else {
                                onNextStory()
                            }
                        }
                )
            }

            StoryViewerTopBar(
                story = story,
                stories = stories,
                accessToken = accessToken,
                isOwnStory = isOwnStory,
                mediaIndex = safeMediaIndex,
                mediaCount = story.attachments.size,
                progress = autoProgress,
                onClose = onClose,
                onDeleteStory = onDeleteStory
            )

            StoryViewerBottomBar(
                story = story,
                isOwnStory = isOwnStory,
                replyText = replyText,
                isSendingReply = isSendingReply,
                replyErrorMessage = replyErrorMessage,
                replySent = replySent,
                storyViews = storyViews,
                isLoadingStoryViews = isLoadingStoryViews,
                storyViewsErrorMessage = storyViewsErrorMessage,
                showStoryViews = showStoryViews,
                accessToken = accessToken,
                onReplyTextChanged = onReplyTextChanged,
                onSendReply = onSendReply,
                onSendReaction = onSendReaction,
                onShowStoryViews = onShowStoryViews,
                onCloseStoryViews = onCloseStoryViews,
                modifier = Modifier.align(Alignment.BottomCenter)
            )
        }
    }
}

@Composable
private fun StoryViewerContent(story: StoryDto, accessToken: String?, mediaIndex: Int) {
    val attachment = story.attachments.getOrNull(mediaIndex) ?: story.attachments.firstOrNull()
    if (attachment != null && attachment.contentType.startsWith("image/", ignoreCase = true)) {
        AuthenticatedAsyncImage(
            imageUrl = ServerConfig.normalizeMediaUrl(attachment.downloadPath),
            accessToken = accessToken,
            contentDescription = attachment.fileName,
            modifier = Modifier.fillMaxSize(),
            contentScale = ContentScale.Crop
        )
        return
    }

    if (attachment != null && attachment.contentType.startsWith("video/", ignoreCase = true)) {
        StoryVideoPlayer(attachment = attachment, accessToken = accessToken)
        return
    }

    Box(
        modifier = Modifier
            .fillMaxSize()
            .padding(28.dp),
        contentAlignment = Alignment.Center
    ) {
        if (attachment != null) {
            Column(
                horizontalAlignment = Alignment.CenterHorizontally,
                verticalArrangement = Arrangement.spacedBy(10.dp)
            ) {
                Text("Видео", style = MaterialTheme.typography.headlineMedium, color = Color.White)
                Text(
                    attachment.fileName,
                    style = MaterialTheme.typography.bodyMedium,
                    color = Color.White.copy(alpha = 0.72f),
                    textAlign = TextAlign.Center,
                    maxLines = 2,
                    overflow = TextOverflow.Ellipsis
                )
            }
        } else {
            Text(
                story.text.ifBlank { "История без подписи" },
                style = MaterialTheme.typography.headlineMedium,
                color = Color.White,
                textAlign = TextAlign.Center
            )
        }
    }
}

@Composable
private fun StoryVideoPlayer(attachment: AttachmentDto, accessToken: String?) {
    val context = LocalContext.current
    val videoUrl = remember(attachment.downloadPath) {
        ServerConfig.normalizeMediaUrl(attachment.downloadPath)
    }
    if (videoUrl.isNullOrBlank()) {
        return
    }

    val player = remember(videoUrl, accessToken) {
        val dataSourceFactory = DefaultHttpDataSource.Factory().apply {
            accessToken?.takeIf { it.isNotBlank() }?.let { token ->
                setDefaultRequestProperties(mapOf("Authorization" to "Bearer $token"))
            }
        }
        ExoPlayer.Builder(context).build().apply {
            repeatMode = Player.REPEAT_MODE_ONE
            playWhenReady = true
            setMediaSource(ProgressiveMediaSource.Factory(dataSourceFactory).createMediaSource(MediaItem.fromUri(videoUrl)))
            prepare()
        }
    }

    DisposableEffect(player) {
        onDispose { player.release() }
    }

    AndroidView(
        modifier = Modifier.fillMaxSize(),
        factory = { viewContext ->
            PlayerView(viewContext).apply {
                useController = false
                resizeMode = AspectRatioFrameLayout.RESIZE_MODE_ZOOM
                this.player = player
            }
        },
        update = { view ->
            view.player = player
        }
    )
}

@Composable
private fun StoryViewerTopBar(
    story: StoryDto,
    stories: List<StoryDto>,
    accessToken: String?,
    isOwnStory: Boolean,
    mediaIndex: Int,
    mediaCount: Int,
    progress: Float,
    onClose: () -> Unit,
    onDeleteStory: () -> Unit
) {
    Column(
        modifier = Modifier
            .fillMaxWidth()
            .background(Color.Black.copy(alpha = 0.42f))
            .padding(horizontal = 14.dp, vertical = 12.dp),
        verticalArrangement = Arrangement.spacedBy(12.dp)
    ) {
        StoryProgressSegments(
            story = story,
            stories = stories,
            mediaIndex = mediaIndex,
            mediaCount = mediaCount,
            progress = progress
        )
        Row(
            modifier = Modifier.fillMaxWidth(),
            verticalAlignment = Alignment.CenterVertically
        ) {
            AvatarView(
                imageUrl = ServerConfig.normalizeMediaUrl(story.author.avatarPath),
                title = story.author.displayName,
                accessToken = accessToken,
                size = 42.dp
            )
            Spacer(modifier = Modifier.width(10.dp))
            Column(modifier = Modifier.weight(1f), verticalArrangement = Arrangement.spacedBy(2.dp)) {
                Text(
                    story.author.displayName,
                    style = MaterialTheme.typography.titleMedium,
                    color = Color.White,
                    maxLines = 1,
                    overflow = TextOverflow.Ellipsis
                )
                Text(
                    story.createdAt.shortDateTime(),
                    style = MaterialTheme.typography.bodySmall,
                    color = Color.White.copy(alpha = 0.72f)
                )
            }
            if (isOwnStory) {
                IconButton(onClick = onDeleteStory) {
                    Icon(Icons.Outlined.Delete, contentDescription = "Удалить историю", tint = Color.White)
                }
            }
            IconButton(onClick = onClose) {
                Icon(Icons.Outlined.Close, contentDescription = "Закрыть", tint = Color.White)
            }
        }
    }
}

@Composable
private fun StoryProgressSegments(
    story: StoryDto,
    stories: List<StoryDto>,
    mediaIndex: Int,
    mediaCount: Int,
    progress: Float
) {
    if (mediaCount > 1) {
        Row(horizontalArrangement = Arrangement.spacedBy(4.dp), modifier = Modifier.fillMaxWidth()) {
            repeat(mediaCount.coerceAtMost(10)) { index ->
                StoryProgressSegment(
                    progress = when {
                        index < mediaIndex -> 1f
                        index == mediaIndex -> progress
                        else -> 0f
                    },
                    modifier = Modifier.weight(1f)
                )
            }
        }
        return
    }

    val selectedIndex = stories.indexOfFirst { it.id == story.id }
    val firstIndex = if (selectedIndex < 0) 0 else (selectedIndex - 6).coerceAtLeast(0)
    val segmentStories = stories.drop(firstIndex).take(12).ifEmpty { listOf(story) }
    val activeSegmentIndex = segmentStories.indexOfFirst { it.id == story.id }.coerceAtLeast(0)
    Row(horizontalArrangement = Arrangement.spacedBy(4.dp), modifier = Modifier.fillMaxWidth()) {
        segmentStories.forEachIndexed { index, _ ->
            StoryProgressSegment(
                progress = when {
                    index < activeSegmentIndex -> 1f
                    index == activeSegmentIndex -> progress
                    else -> 0f
                },
                modifier = Modifier.weight(1f)
            )
        }
    }
}

@Composable
private fun StoryProgressSegment(progress: Float, modifier: Modifier = Modifier) {
    Box(
        modifier = modifier
            .height(3.dp)
            .clip(RoundedCornerShape(2.dp))
            .background(Color.White.copy(alpha = 0.34f))
    ) {
        Box(
            modifier = Modifier
                .fillMaxWidth(progress.coerceIn(0f, 1f))
                .height(3.dp)
                .background(Color.White)
        )
    }
}

@Composable
private fun StoryViewerBottomBar(
    story: StoryDto,
    isOwnStory: Boolean,
    replyText: String,
    isSendingReply: Boolean,
    replyErrorMessage: String?,
    replySent: Boolean,
    storyViews: List<StoryViewDto>,
    isLoadingStoryViews: Boolean,
    storyViewsErrorMessage: String?,
    showStoryViews: Boolean,
    accessToken: String?,
    onReplyTextChanged: (String) -> Unit,
    onSendReply: () -> Unit,
    onSendReaction: (String) -> Unit,
    onShowStoryViews: () -> Unit,
    onCloseStoryViews: () -> Unit,
    modifier: Modifier = Modifier
) {
    Column(
        modifier = modifier
            .fillMaxWidth()
            .imePadding()
            .background(Color.Black.copy(alpha = 0.54f))
            .padding(horizontal = 18.dp, vertical = 16.dp),
        verticalArrangement = Arrangement.spacedBy(10.dp)
    ) {
        if (story.attachments.isNotEmpty() && story.text.isNotBlank()) {
            Text(story.text, style = MaterialTheme.typography.bodyLarge, color = Color.White)
        }
        Row(verticalAlignment = Alignment.CenterVertically) {
            if (isOwnStory) {
                TextButton(onClick = if (showStoryViews) onCloseStoryViews else onShowStoryViews) {
                    Text(
                        if (showStoryViews) "Скрыть просмотры" else "${story.viewCount} просмотров",
                        style = MaterialTheme.typography.bodySmall,
                        color = Color.White
                    )
                }
            } else {
                Text(
                    "${story.viewCount} просмотров",
                    style = MaterialTheme.typography.bodySmall,
                    color = Color.White.copy(alpha = 0.72f)
                )
            }
            if (story.hasProtectedContent) {
                Spacer(modifier = Modifier.width(10.dp))
                Text(
                    "защищено",
                    style = MaterialTheme.typography.labelSmall,
                    color = Color.White.copy(alpha = 0.72f)
                )
            }
        }
        if (isOwnStory && showStoryViews) {
            StoryViewsPanel(
                views = storyViews,
                isLoading = isLoadingStoryViews,
                errorMessage = storyViewsErrorMessage,
                accessToken = accessToken
            )
        }
        if (!isOwnStory) {
            StoryReplyComposer(
                replyText = replyText,
                isSendingReply = isSendingReply,
                replySent = replySent,
                replyErrorMessage = replyErrorMessage,
                onReplyTextChanged = onReplyTextChanged,
                onSendReply = onSendReply,
                onSendReaction = onSendReaction
            )
        }
    }
}

@Composable
private fun StoryReplyComposer(
    replyText: String,
    isSendingReply: Boolean,
    replySent: Boolean,
    replyErrorMessage: String?,
    onReplyTextChanged: (String) -> Unit,
    onSendReply: () -> Unit,
    onSendReaction: (String) -> Unit
) {
    val canSend = replyText.isNotBlank() && !isSendingReply
    Column(verticalArrangement = Arrangement.spacedBy(6.dp)) {
        StoryQuickReactionRow(
            enabled = !isSendingReply,
            onSendReaction = onSendReaction
        )
        Surface(
            color = Color.White.copy(alpha = 0.14f),
            shape = RoundedCornerShape(24.dp),
            modifier = Modifier.fillMaxWidth()
        ) {
            Row(
                modifier = Modifier
                    .fillMaxWidth()
                    .padding(start = 16.dp, top = 6.dp, bottom = 6.dp, end = 4.dp),
                verticalAlignment = Alignment.CenterVertically
            ) {
                BasicTextField(
                    value = replyText,
                    onValueChange = onReplyTextChanged,
                    enabled = !isSendingReply,
                    singleLine = true,
                    keyboardOptions = KeyboardOptions(imeAction = ImeAction.Send),
                    keyboardActions = KeyboardActions(onSend = { if (canSend) onSendReply() }),
                    modifier = Modifier.weight(1f),
                    textStyle = MaterialTheme.typography.bodyLarge.copy(color = Color.White),
                    decorationBox = { inner ->
                        if (replyText.isBlank()) {
                            Text(
                                "Сообщение",
                                color = Color.White.copy(alpha = 0.62f),
                                style = MaterialTheme.typography.bodyLarge
                            )
                        }
                        inner()
                    }
                )
                IconButton(
                    onClick = onSendReply,
                    enabled = canSend
                ) {
                    Icon(
                        imageVector = Icons.AutoMirrored.Outlined.Send,
                        contentDescription = "Отправить",
                        tint = if (canSend) Color.White else Color.White.copy(alpha = 0.34f)
                    )
                }
            }
        }
        replyErrorMessage?.let { message ->
            Text(message, style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.error)
        }
        if (replySent) {
            Text("Отправлено", style = MaterialTheme.typography.bodySmall, color = Color.White.copy(alpha = 0.72f))
        }
    }
}

@Composable
private fun StoryQuickReactionRow(
    enabled: Boolean,
    onSendReaction: (String) -> Unit
) {
    Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
        StoryQuickReactions.forEach { emoji ->
            Surface(
                color = Color.White.copy(alpha = if (enabled) 0.16f else 0.08f),
                shape = CircleShape,
                modifier = Modifier
                    .size(40.dp)
                    .clickable(enabled = enabled) { onSendReaction(emoji) }
            ) {
                Box(contentAlignment = Alignment.Center) {
                    Text(emoji, style = MaterialTheme.typography.titleMedium)
                }
            }
        }
    }
}

private val StoryQuickReactions = listOf("❤️", "👍", "🔥", "👏", "😂", "😮")

@Composable
private fun StoryViewsPanel(
    views: List<StoryViewDto>,
    isLoading: Boolean,
    errorMessage: String?,
    accessToken: String?
) {
    Surface(
        color = Color.White.copy(alpha = 0.12f),
        shape = RoundedCornerShape(18.dp),
        modifier = Modifier.fillMaxWidth()
    ) {
        Column(
            modifier = Modifier.padding(horizontal = 12.dp, vertical = 10.dp),
            verticalArrangement = Arrangement.spacedBy(8.dp)
        ) {
            Text(
                text = "Просмотрели",
                style = MaterialTheme.typography.labelLarge,
                color = Color.White.copy(alpha = 0.84f)
            )
            when {
                isLoading -> Text(
                    text = "Загрузка...",
                    style = MaterialTheme.typography.bodySmall,
                    color = Color.White.copy(alpha = 0.72f)
                )

                !errorMessage.isNullOrBlank() -> Text(
                    text = errorMessage,
                    style = MaterialTheme.typography.bodySmall,
                    color = MaterialTheme.colorScheme.error
                )

                views.isEmpty() -> Text(
                    text = "Пока никто не посмотрел",
                    style = MaterialTheme.typography.bodySmall,
                    color = Color.White.copy(alpha = 0.72f)
                )

                else -> {
                    views.take(8).forEach { view ->
                        StoryViewRow(view = view, accessToken = accessToken)
                    }
                    if (views.size > 8) {
                        Text(
                            text = "И ещё ${views.size - 8}",
                            style = MaterialTheme.typography.bodySmall,
                            color = Color.White.copy(alpha = 0.72f)
                        )
                    }
                }
            }
        }
    }
}

@Composable
private fun StoryViewRow(view: StoryViewDto, accessToken: String?) {
    Row(
        modifier = Modifier.fillMaxWidth(),
        horizontalArrangement = Arrangement.spacedBy(10.dp),
        verticalAlignment = Alignment.CenterVertically
    ) {
        AvatarView(
            imageUrl = ServerConfig.normalizeMediaUrl(view.viewer.avatarPath),
            title = view.viewer.displayName,
            accessToken = accessToken,
            size = 34.dp
        )
        Column(modifier = Modifier.weight(1f), verticalArrangement = Arrangement.spacedBy(1.dp)) {
            Text(
                text = view.viewer.displayName.ifBlank { "@${view.viewer.username}" },
                style = MaterialTheme.typography.bodyMedium,
                color = Color.White,
                maxLines = 1,
                overflow = TextOverflow.Ellipsis
            )
            Text(
                text = view.viewedAt.shortDateTime(),
                style = MaterialTheme.typography.bodySmall,
                color = Color.White.copy(alpha = 0.68f)
            )
        }
    }
}

@Composable
private fun StoryTransfersCard(
    transfers: List<StoryTransferUiState>,
    onRetryTransfer: (String) -> Unit,
    onCancelTransfer: (String) -> Unit
) {
    IkarSectionCard {
        IkarSectionTitle("Очередь историй", modifier = Modifier.padding(bottom = 8.dp))
        transfers.forEachIndexed { index, transfer ->
            Column(verticalArrangement = Arrangement.spacedBy(8.dp), modifier = Modifier.padding(vertical = 8.dp)) {
                Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) {
                    Text(transfer.title, style = MaterialTheme.typography.titleMedium, maxLines = 1, overflow = TextOverflow.Ellipsis)
                    Text("${transfer.progressPercent}%", style = MaterialTheme.typography.bodySmall, color = TelegramInkMuted)
                }
                LinearProgressIndicator(
                    progress = { transfer.progressPercent / 100f },
                    modifier = Modifier.fillMaxWidth(),
                    color = TelegramBlue
                )
                Text(transfer.errorMessage ?: transfer.status, style = MaterialTheme.typography.bodySmall, color = TelegramInkMuted)
                Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
                    TextButton(onClick = { onRetryTransfer(transfer.groupId) }) { Text("Повторить") }
                    TextButton(onClick = { onCancelTransfer(transfer.groupId) }) { Text("Отменить") }
                }
            }
            if (index != transfers.lastIndex) {
                IkarRowDivider(startIndent = 0.dp)
            }
        }
    }
}

@Composable
private fun MediaPreviewGrid(
    media: List<StoryMediaPreviewUiState>,
    onRemoveMedia: (String) -> Unit,
    modifier: Modifier = Modifier
) {
    Column(modifier = modifier, verticalArrangement = Arrangement.spacedBy(10.dp)) {
        media.chunked(2).forEach { row ->
            Row(horizontalArrangement = Arrangement.spacedBy(10.dp), modifier = Modifier.fillMaxWidth()) {
                row.forEach { item ->
                    StoryMediaTile(
                        item = item,
                        onRemoveMedia = onRemoveMedia,
                        modifier = Modifier.weight(1f)
                    )
                }
                if (row.size == 1) {
                    Box(modifier = Modifier.weight(1f))
                }
            }
        }
    }
}

@Composable
private fun StoryMediaTile(
    item: StoryMediaPreviewUiState,
    onRemoveMedia: (String) -> Unit,
    modifier: Modifier = Modifier
) {
    Surface(modifier = modifier, color = Color(0xFFF2F6FA), shape = RoundedCornerShape(18.dp)) {
        Column(verticalArrangement = Arrangement.spacedBy(8.dp), modifier = Modifier.padding(10.dp)) {
            Box(
                modifier = Modifier
                    .fillMaxWidth()
                    .aspectRatio(1f)
                    .clip(RoundedCornerShape(14.dp))
                    .background(Color(0xFFEAF4FF)),
                contentAlignment = Alignment.Center
            ) {
                if (item.contentType.startsWith("image/")) {
                    AsyncImage(
                        model = File(item.localPath),
                        contentDescription = null,
                        modifier = Modifier.fillMaxSize(),
                        contentScale = ContentScale.Crop
                    )
                } else {
                    Text("ВИДЕО", color = TelegramBlue, fontWeight = FontWeight.SemiBold)
                }
            }
            Text(item.fileName, maxLines = 1, overflow = TextOverflow.Ellipsis, style = MaterialTheme.typography.bodySmall)
            Text(item.fileSizeBytes.formatBytes(), style = MaterialTheme.typography.bodySmall, color = TelegramInkMuted)
            TextButton(onClick = { onRemoveMedia(item.localPath) }, modifier = Modifier.fillMaxWidth()) {
                Text("Удалить")
            }
        }
    }
}

@Composable
private fun EmptyStoriesState(onComposeClick: () -> Unit) {
    Column(
        modifier = Modifier
            .fillMaxWidth()
            .padding(vertical = 18.dp),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.spacedBy(10.dp)
    ) {
        Box(
            modifier = Modifier
                .size(62.dp)
                .clip(CircleShape)
                .background(Color(0xFFEAF4FF)),
            contentAlignment = Alignment.Center
        ) {
            Icon(Icons.Outlined.Add, contentDescription = null, tint = TelegramBlue)
        }
        Text("Пока нет активных историй", style = MaterialTheme.typography.titleMedium)
        Text("Опубликуйте первую историю со сроком жизни, приватностью и медиа.", style = MaterialTheme.typography.bodySmall, color = TelegramInkMuted)
        TextButton(onClick = onComposeClick) { Text("Создать историю") }
    }
}

@Composable
private fun StoryPreviewRow(
    story: StoryDto,
    accessToken: String?,
    onClick: () -> Unit
) {
    Row(
        modifier = Modifier
            .fillMaxWidth()
            .clickable(onClick = onClick)
            .padding(vertical = 12.dp),
        horizontalArrangement = Arrangement.spacedBy(14.dp),
        verticalAlignment = Alignment.CenterVertically
    ) {
        Surface(
            modifier = Modifier.size(48.dp),
            color = if (story.viewedByMe) Color(0xFFF1F3F5) else Color(0xFFEAF4FF),
            shape = CircleShape
        ) {
            Box(contentAlignment = Alignment.Center) {
                val preview = story.attachments.firstOrNull { it.contentType.startsWith("image/") }
                if (preview != null) {
                    AuthenticatedAsyncImage(
                        imageUrl = ServerConfig.normalizeMediaUrl(preview.downloadPath),
                        accessToken = accessToken,
                        contentDescription = preview.fileName,
                        modifier = Modifier.fillMaxSize(),
                        contentScale = ContentScale.Crop
                    )
                } else {
                    Text(
                        text = story.author.displayName.firstOrNull()?.uppercaseChar()?.toString()
                            ?: story.author.username.firstOrNull()?.uppercaseChar()?.toString().orEmpty(),
                        style = MaterialTheme.typography.titleLarge,
                        color = TelegramBlue,
                        fontWeight = FontWeight.SemiBold
                    )
                }
            }
        }
        Column(modifier = Modifier.weight(1f), verticalArrangement = Arrangement.spacedBy(3.dp)) {
            Text(story.author.displayName, style = MaterialTheme.typography.titleLarge)
            Text(story.text.ifBlank { "${story.attachments.size} медиа" }, style = MaterialTheme.typography.bodySmall, color = TelegramInkMuted, maxLines = 1, overflow = TextOverflow.Ellipsis)
            Text("до ${story.expiresAt.shortDateTime()} · ${story.viewCount} просмотров", style = MaterialTheme.typography.bodySmall, color = TelegramInkMuted)
        }
        if (story.hasProtectedContent) {
            Text("защищено", style = MaterialTheme.typography.labelSmall, color = TelegramBlue)
        }
    }
}

@Composable
private fun StoryAttachmentStrip(story: StoryDto, accessToken: String?) {
    if (story.attachments.isEmpty()) {
        return
    }

    Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
        story.attachments.take(4).forEach { attachment ->
            StoryAttachmentPreview(attachment = attachment, accessToken = accessToken)
        }
        if (story.attachments.size > 4) {
            Text("+${story.attachments.size - 4} медиа", style = MaterialTheme.typography.bodySmall, color = TelegramInkMuted)
        }
    }
}

@Composable
private fun StoryAttachmentPreview(attachment: AttachmentDto, accessToken: String?) {
    if (attachment.contentType.startsWith("image/")) {
        AuthenticatedAsyncImage(
            imageUrl = ServerConfig.normalizeMediaUrl(attachment.downloadPath),
            accessToken = accessToken,
            contentDescription = attachment.fileName,
            modifier = Modifier
                .fillMaxWidth()
                .aspectRatio(16f / 10f)
                .clip(RoundedCornerShape(18.dp)),
            contentScale = ContentScale.Crop
        )
    } else {
        Surface(color = Color(0xFFEAF4FF), shape = RoundedCornerShape(18.dp), modifier = Modifier.fillMaxWidth()) {
            Column(modifier = Modifier.padding(14.dp), verticalArrangement = Arrangement.spacedBy(4.dp)) {
                Text("Видео", color = TelegramBlue, fontWeight = FontWeight.SemiBold)
                Text(attachment.fileName, maxLines = 1, overflow = TextOverflow.Ellipsis, style = MaterialTheme.typography.bodySmall, color = TelegramInkMuted)
            }
        }
    }
}

@Composable
private fun StoryOptionRow(
    title: String,
    subtitle: String,
    selected: Boolean,
    onClick: () -> Unit
) {
    Row(
        modifier = Modifier
            .fillMaxWidth()
            .clickable(onClick = onClick)
            .padding(vertical = 12.dp),
        horizontalArrangement = Arrangement.spacedBy(12.dp),
        verticalAlignment = Alignment.CenterVertically
    ) {
        Box(
            modifier = Modifier
                .size(20.dp)
                .clip(CircleShape)
                .background(if (selected) TelegramBlue else Color(0xFFDDE7F0))
        )
        Column(modifier = Modifier.weight(1f), verticalArrangement = Arrangement.spacedBy(2.dp)) {
            Text(title, style = MaterialTheme.typography.titleMedium)
            Text(subtitle, style = MaterialTheme.typography.bodySmall, color = TelegramInkMuted)
        }
    }
}

private fun StoryVisibility.label(): String = when (this) {
    StoryVisibility.Everyone -> "Все"
    StoryVisibility.Contacts -> "Контакты"
    StoryVisibility.CloseFriends -> "Близкие друзья"
    StoryVisibility.Private -> "Только я"
}

private fun StoryVisibility.subtitle(): String = when (this) {
    StoryVisibility.Everyone -> "История доступна всем пользователям."
    StoryVisibility.Contacts -> "Показывать только контактам."
    StoryVisibility.CloseFriends -> "Использовать приватный круг близких."
    StoryVisibility.Private -> "Скрыть от всех кроме автора."
}

private fun Int.labelTtl(): String = when (this) {
    3_600 -> "1 ч"
    43_200 -> "12 ч"
    86_400 -> "24 ч"
    604_800 -> "7 д"
    else -> "${this / 3_600} ч"
}

private fun Long.formatBytes(): String = when {
    this >= 1024L * 1024L -> "${this / (1024L * 1024L)} MB"
    this >= 1024L -> "${this / 1024L} KB"
    else -> "$this B"
}

private fun String.shortDateTime(): String =
    take(16).replace('T', ' ')
