package com.wisp.app.ui.component

import android.content.Intent
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.expandVertically
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.shrinkVertically
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.gestures.detectTransformGestures
import androidx.compose.foundation.interaction.MutableInteractionSource
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.aspectRatio
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.KeyboardArrowLeft
import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight
import androidx.compose.material.icons.filled.CheckCircle
import androidx.compose.material.icons.filled.Check
import androidx.compose.material.icons.filled.Close
import androidx.compose.material.icons.filled.ContentCopy
import androidx.compose.material.icons.filled.KeyboardArrowDown
import androidx.compose.material.icons.filled.KeyboardArrowUp
import androidx.compose.material.icons.filled.MoreVert
import androidx.compose.material.icons.filled.PlayArrow
import androidx.compose.material.icons.filled.Refresh
import androidx.compose.material.icons.outlined.Repeat
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.IconButtonDefaults
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalClipboardManager
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.font.FontWeight
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.graphics.asImageBitmap
import androidx.compose.ui.graphics.painter.BitmapPainter
import coil3.compose.AsyncImage
import androidx.compose.material3.CircularProgressIndicator
import com.wisp.app.R
import com.wisp.app.nostr.Nip13
import com.wisp.app.nostr.toNpub
import com.wisp.app.nostr.Nip19
import com.wisp.app.nostr.Nip30
import com.wisp.app.nostr.Nip68
import com.wisp.app.nostr.Nip71
import com.wisp.app.nostr.NostrEvent
import com.wisp.app.nostr.ProfileData
import com.wisp.app.nostr.hexToByteArray
import com.wisp.app.repo.EventRepository
import com.wisp.app.repo.Nip05Repository
import com.wisp.app.repo.Nip05Status
import com.wisp.app.repo.ZapDetail
import com.wisp.app.util.MediaDownloader
import kotlinx.coroutines.launch
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale

private val GALLERY_KINDS = setOf(20, 21, 22)

private val galleryDateTimeFormat = SimpleDateFormat("MMM d, HH:mm", Locale.US)
private val galleryDateTimeYearFormat = SimpleDateFormat("MMM d, yyyy", Locale.US)

@Composable
fun GalleryCard(
    event: NostrEvent,
    profile: ProfileData?,
    onReply: () -> Unit = {},
    onProfileClick: () -> Unit = {},
    onNavigateToProfile: ((String) -> Unit)? = null,
    onNoteClick: () -> Unit = {},
    onReact: (String) -> Unit = {},
    userReactionEmojis: Set<String> = emptySet(),
    onRepost: () -> Unit = {},
    onQuote: () -> Unit = {},
    hasUserReposted: Boolean = false,
    repostCount: Int = 0,
    onZap: () -> Unit = {},
    hasUserZapped: Boolean = false,
    likeCount: Int = 0,
    replyCount: Int = 0,
    zapSats: Long = 0,
    isZapAnimating: Boolean = false,
    isZapInProgress: Boolean = false,
    eventRepo: EventRepository? = null,
    relayIcons: List<Pair<String, String?>> = emptyList(),
    onRelayClick: (String) -> Unit = {},
    repostPubkeys: List<String> = emptyList(),
    repostTime: Long? = null,
    reactionDetails: Map<String, List<String>> = emptyMap(),
    zapDetails: List<ZapDetail> = emptyList(),
    repostDetails: List<String> = emptyList(),
    reactionEmojiUrls: Map<String, String> = emptyMap(),
    resolvedEmojis: Map<String, String> = emptyMap(),
    unicodeEmojis: List<String> = emptyList(),
    onOpenEmojiLibrary: (() -> Unit)? = null,
    onNavigateToProfileFromDetails: ((String) -> Unit)? = null,
    onFollowAuthor: () -> Unit = {},
    onBlockAuthor: () -> Unit = {},
    isFollowingAuthor: Boolean = false,
    isOwnEvent: Boolean = false,
    nip05Repo: Nip05Repository? = null,
    onQuotedNoteClick: ((String) -> Unit)? = null,
    noteActions: NoteActions? = null,
    onAddToList: () -> Unit = {},
    isInList: Boolean = false,
    onPin: () -> Unit = {},
    isPinned: Boolean = false,
    onDelete: () -> Unit = {},
    quoteDepth: Int = 0,
    modifier: Modifier = Modifier,
    showDivider: Boolean = true
) {
    val title = remember(event.id) {
        Nip68.getTitle(event) ?: Nip71.getTitle(event)
    }

    val contentWarning = remember(event.id) {
        event.tags.firstOrNull { it.size >= 1 && it[0] == "content-warning" }
    }
    var contentRevealed by remember { mutableStateOf(false) }

    // Parse media entries
    val imageEntries = remember(event.id) { Nip68.parseImetaEntries(event) }
    val videoEntries = remember(event.id) { Nip71.parseVideoMeta(event) }

    // Parse event emoji tags and combine with resolved emojis
    val eventEmojiMap = remember(event.id) { Nip30.parseEmojiTags(event) }
    val emojiMap = remember(eventEmojiMap, resolvedEmojis) {
        eventEmojiMap + resolvedEmojis
    }

    // If no imeta tags, fall back to PostCard
    if (imageEntries.isEmpty() && videoEntries.isEmpty()) {
        PostCard(
            event = event,
            profile = profile,
            onReply = onReply,
            onProfileClick = onProfileClick,
            onNavigateToProfile = onNavigateToProfile,
            onNoteClick = onNoteClick,
            onReact = onReact,
            userReactionEmojis = userReactionEmojis,
            onRepost = onRepost,
            onQuote = onQuote,
            hasUserReposted = hasUserReposted,
            repostCount = repostCount,
            onZap = onZap,
            hasUserZapped = hasUserZapped,
            likeCount = likeCount,
            replyCount = replyCount,
            zapSats = zapSats,
            isZapAnimating = isZapAnimating,
            isZapInProgress = isZapInProgress,
            eventRepo = eventRepo,
            relayIcons = relayIcons,
            repostPubkeys = repostPubkeys,
            repostTime = repostTime,
            reactionDetails = reactionDetails,
            zapDetails = zapDetails,
            repostDetails = repostDetails,
            reactionEmojiUrls = reactionEmojiUrls,
            resolvedEmojis = resolvedEmojis,
            unicodeEmojis = unicodeEmojis,
            onOpenEmojiLibrary = onOpenEmojiLibrary,
            onNavigateToProfileFromDetails = onNavigateToProfileFromDetails,
            onFollowAuthor = onFollowAuthor,
            onBlockAuthor = onBlockAuthor,
            isFollowingAuthor = isFollowingAuthor,
            isOwnEvent = isOwnEvent,
            nip05Repo = nip05Repo,
            onQuotedNoteClick = onQuotedNoteClick,
            noteActions = noteActions,
            onAddToList = onAddToList,
            isInList = isInList,
            onPin = onPin,
            isPinned = isPinned,
            onDelete = onDelete,
            quoteDepth = quoteDepth,
            modifier = modifier,
            showDivider = showDivider
        )
        return
    }

    val displayName = remember(event.pubkey, profile?.displayString) {
        profile?.displayString
            ?: event.pubkey.toNpub().let { "${it.take(12)}...${it.takeLast(4)}" }
    }
    val timestamp = remember(event.created_at) { formatGalleryTimestamp(event.created_at) }

    val displayIcons = remember(relayIcons) {
        if (relayIcons.size <= 5) relayIcons else relayIcons.take(5)
    }
    val clientName = remember(event.id) {
        event.tags.firstOrNull { it.size >= 2 && it[0] == "client" }?.get(1)
    }
    val hasReactionDetails = reactionDetails.isNotEmpty() || zapDetails.isNotEmpty() || repostDetails.isNotEmpty()
    var expandedDetails by remember { mutableStateOf(false) }

    var fullScreenInitialPage by remember { mutableIntStateOf(-1) }

    Column(
        modifier = modifier
            .fillMaxWidth()
            .clickable(onClick = onNoteClick)
            .padding(horizontal = 16.dp, vertical = 8.dp)
    ) {
        // Repost banner — matches PostCard exactly
        if (repostPubkeys.isNotEmpty()) {
            val maxAvatars = 10
            val displayPubkeys = repostPubkeys.take(maxAvatars)
            val overflow = repostPubkeys.size - maxAvatars
            val formattedRepostTime = repostTime?.let { formatGalleryTimestamp(it) }

            Row(
                verticalAlignment = Alignment.CenterVertically,
                horizontalArrangement = Arrangement.Center,
                modifier = Modifier.fillMaxWidth().padding(bottom = 4.dp)
            ) {
                Icon(
                    Icons.Outlined.Repeat,
                    contentDescription = null,
                    tint = MaterialTheme.colorScheme.onSurfaceVariant,
                    modifier = Modifier.size(14.dp)
                )
                Spacer(Modifier.width(4.dp))

                // Overlapping avatars
                Box(modifier = Modifier.height(20.dp).width((displayPubkeys.size * 14 + 6 + 4).dp)) {
                    displayPubkeys.forEachIndexed { index, pubkey ->
                        val avatarUrl = eventRepo?.getProfileData(pubkey)?.picture
                        Box(modifier = Modifier.offset(x = (index * 14).dp)) {
                            ProfilePicture(
                                url = avatarUrl,
                                size = 20,
                                showFollowBadge = false,
                                onClick = { onNavigateToProfileFromDetails?.invoke(pubkey) }
                            )
                        }
                    }
                }

                // Label text
                val labelText = if (repostPubkeys.size == 1) {
                    val name = eventRepo?.getProfileData(repostPubkeys.first())?.displayString
                        ?: repostPubkeys.first().toNpub().let { "${it.take(12)}...${it.takeLast(4)}" }
                    "$name reposted"
                } else if (overflow > 0) {
                    "and $overflow others reposted"
                } else {
                    "reposted"
                }
                Text(
                    text = labelText,
                    style = MaterialTheme.typography.labelSmall,
                    color = MaterialTheme.colorScheme.onSurfaceVariant,
                    maxLines = 1,
                    overflow = TextOverflow.Ellipsis
                )

                if (formattedRepostTime != null) {
                    Text(
                        text = " \u00B7 $formattedRepostTime",
                        style = MaterialTheme.typography.labelSmall,
                        color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.7f)
                    )
                }
            }
        }

        // Author header — matches PostCard exactly
        Row(verticalAlignment = Alignment.CenterVertically) {
            ProfilePicture(
                url = profile?.picture,
                showFollowBadge = isFollowingAuthor && !isOwnEvent,
                onClick = onProfileClick,
                onLongPress = if (!isOwnEvent) onFollowAuthor else null
            )
            Spacer(Modifier.width(10.dp))
            Column(modifier = Modifier.weight(1f)) {
                Row(verticalAlignment = Alignment.CenterVertically) {
                    Text(
                        text = displayName,
                        style = MaterialTheme.typography.titleMedium,
                        color = MaterialTheme.colorScheme.onSurface,
                        maxLines = 1,
                        overflow = TextOverflow.Ellipsis,
                        modifier = Modifier
                            .weight(1f, fill = false)
                            .clickable(onClick = onProfileClick)
                    )
                    profile?.nip05?.let { nip05 ->
                        Spacer(Modifier.width(4.dp))
                        Nip05Badge(
                            nip05 = nip05,
                            pubkey = event.pubkey,
                            nip05Repo = nip05Repo,
                            onClick = onProfileClick,
                            showHandle = false
                        )
                    }
                }
            }
            Text(
                text = timestamp,
                style = MaterialTheme.typography.labelSmall,
                color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.7f)
            )
            val powBits = remember(event.id) { Nip13.verifyDifficulty(event) }
            if (powBits >= 16) {
                Spacer(Modifier.width(4.dp))
                Surface(
                    shape = RoundedCornerShape(4.dp),
                    color = MaterialTheme.colorScheme.primary.copy(alpha = 0.15f)
                ) {
                    Text(
                        text = stringResource(R.string.post_pow_x, powBits),
                        style = MaterialTheme.typography.labelSmall,
                        color = MaterialTheme.colorScheme.primary,
                        modifier = Modifier.padding(horizontal = 4.dp, vertical = 1.dp)
                    )
                }
            }
            Box {
                var menuExpanded by remember { mutableStateOf(false) }
                val context = LocalContext.current
                val clipboardManager = LocalClipboardManager.current
                IconButton(
                    onClick = { menuExpanded = true },
                    modifier = Modifier.size(18.dp)
                ) {
                    Icon(
                        Icons.Default.MoreVert,
                        contentDescription = stringResource(R.string.cd_more_options),
                        tint = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.7f),
                        modifier = Modifier.size(18.dp)
                    )
                }
                DropdownMenu(
                    expanded = menuExpanded,
                    onDismissRequest = { menuExpanded = false }
                ) {
                    if (!isOwnEvent) {
                        DropdownMenuItem(
                            text = { Text(if (isFollowingAuthor) stringResource(R.string.btn_unfollow) else stringResource(R.string.btn_follow)) },
                            onClick = {
                                menuExpanded = false
                                onFollowAuthor()
                            }
                        )
                        DropdownMenuItem(
                            text = { Text(stringResource(R.string.btn_block)) },
                            onClick = {
                                menuExpanded = false
                                onBlockAuthor()
                            }
                        )
                    }
                    DropdownMenuItem(
                        text = { Text(stringResource(R.string.btn_add_to_list)) },
                        onClick = {
                            menuExpanded = false
                            onAddToList()
                        }
                    )
                    if (isOwnEvent) {
                        DropdownMenuItem(
                            text = { Text(if (isPinned) stringResource(R.string.btn_unpin_from_profile) else stringResource(R.string.btn_pin_to_profile)) },
                            onClick = {
                                menuExpanded = false
                                onPin()
                            }
                        )
                        DropdownMenuItem(
                            text = { Text(stringResource(R.string.btn_delete)) },
                            onClick = {
                                menuExpanded = false
                                onDelete()
                            }
                        )
                    }
                    DropdownMenuItem(
                        text = { Text(stringResource(R.string.btn_share)) },
                        onClick = {
                            menuExpanded = false
                            try {
                                val nevent = Nip19.neventEncode(event.id.hexToByteArray())
                                val url = "https://njump.me/$nevent"
                                val intent = Intent(Intent.ACTION_SEND).apply {
                                    type = "text/plain"
                                    putExtra(Intent.EXTRA_TEXT, url)
                                }
                                context.startActivity(Intent.createChooser(intent, null))
                            } catch (_: Exception) {}
                        }
                    )
                    DropdownMenuItem(
                        text = { Text(stringResource(R.string.btn_copy_note_id)) },
                        onClick = {
                            menuExpanded = false
                            try {
                                val relays = eventRepo?.getEventRelays(event.id)?.take(3)?.toList() ?: emptyList()
                                val neventId = Nip19.neventEncode(
                                    eventId = event.id.hexToByteArray(),
                                    relays = relays,
                                    author = event.pubkey.hexToByteArray()
                                )
                                clipboardManager.setText(AnnotatedString(neventId))
                            } catch (_: Exception) {}
                        }
                    )
                    DropdownMenuItem(
                        text = { Text(stringResource(R.string.btn_copy_note_json)) },
                        onClick = {
                            menuExpanded = false
                            clipboardManager.setText(AnnotatedString(event.toJson()))
                        }
                    )
                }
            }
        }

        // Title
        if (!title.isNullOrBlank()) {
            Spacer(Modifier.height(6.dp))
            Text(
                text = title,
                style = MaterialTheme.typography.titleMedium,
                fontWeight = FontWeight.Bold,
                maxLines = 2,
                overflow = TextOverflow.Ellipsis
            )
        }

        Spacer(Modifier.height(8.dp))

        // Content warning overlay
        if (contentWarning != null && !contentRevealed) {
            Box(
                modifier = Modifier
                    .fillMaxWidth()
                    .aspectRatio(4f / 3f)
                    .clip(RoundedCornerShape(12.dp))
                    .background(MaterialTheme.colorScheme.surfaceVariant)
                    .clickable { contentRevealed = true },
                contentAlignment = Alignment.Center
            ) {
                Column(horizontalAlignment = Alignment.CenterHorizontally) {
                    Text(
                        "Sensitive content",
                        style = MaterialTheme.typography.titleSmall,
                        color = MaterialTheme.colorScheme.onSurfaceVariant
                    )
                    Text(
                        "Tap to reveal",
                        style = MaterialTheme.typography.bodySmall,
                        color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.7f)
                    )
                }
            }
        } else if (event.kind == 20 && imageEntries.isNotEmpty()) {
            // Picture event — always use pager for swipe support
            val firstDim = imageEntries.firstOrNull()?.dim
            val aspectRatio = (parseAspectRatio(firstDim) ?: (4f / 3f)).coerceIn(0.5f, 2.5f)
            val pagerState = rememberPagerState(pageCount = { imageEntries.size })
            Column {
                HorizontalPager(
                    state = pagerState,
                    modifier = Modifier
                        .fillMaxWidth()
                        .aspectRatio(aspectRatio)
                        .clip(RoundedCornerShape(12.dp))
                ) { page ->
                    val entry = imageEntries[page]
                    val blurPainter = rememberMediaPlaceholderPainter(entry.thumbhash, entry.blurhash, entry.dim)
                    var isLoading by remember { mutableStateOf(true) }
                    Box(
                        modifier = Modifier
                            .fillMaxSize()
                            .clickable { fullScreenInitialPage = page }
                    ) {
                        AsyncImage(
                            model = entry.url,
                            contentDescription = entry.alt ?: title,
                            contentScale = ContentScale.Crop,
                            placeholder = blurPainter,
                            error = blurPainter,
                            onLoading = { isLoading = true },
                            onSuccess = { isLoading = false },
                            onError = { isLoading = false },
                            modifier = Modifier.fillMaxSize()
                        )
                        if (isLoading) {
                            Box(
                                modifier = Modifier.fillMaxSize(),
                                contentAlignment = Alignment.Center
                            ) {
                                CircularProgressIndicator(
                                    modifier = Modifier.size(24.dp),
                                    strokeWidth = 2.dp,
                                    color = if (blurPainter != null) Color.White else MaterialTheme.colorScheme.primary
                                )
                            }
                        }
                    }
                }
                if (imageEntries.size > 1) {
                    Spacer(Modifier.height(6.dp))
                    Row(
                        modifier = Modifier.fillMaxWidth(),
                        horizontalArrangement = Arrangement.Center
                    ) {
                        repeat(imageEntries.size) { index ->
                            Box(
                                modifier = Modifier
                                    .padding(horizontal = 3.dp)
                                    .size(6.dp)
                                    .clip(CircleShape)
                                    .background(
                                        if (index == pagerState.currentPage)
                                            MaterialTheme.colorScheme.primary
                                        else
                                            MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.3f)
                                    )
                            )
                        }
                    }
                }
            }
        } else if (videoEntries.isNotEmpty()) {
            // Video event (kind 21/22) — use inline video player, same as kind 1 feed
            val video = videoEntries[0]
            InlineVideoPlayerWithFullscreen(
                meta = MediaMeta(
                    url = video.url,
                    mime = video.mimeType,
                    dimension = video.dim,
                    thumbhash = video.thumbhash,
                    blurhash = video.blurhash
                ),
                onFullScreen = { positionMs ->
                    FullScreenVideoState.enter(video.url, positionMs)
                }
            )
        }

        // Description (event.content)
        if (event.content.isNotBlank()) {
            Spacer(Modifier.height(8.dp))
            RichContent(
                content = event.content,
                eventRepo = eventRepo,
                emojiMap = emojiMap,
                modifier = Modifier,
                style = MaterialTheme.typography.bodyMedium.copy(
                    color = MaterialTheme.colorScheme.onSurface
                )
            )
        }

        // Top zapper banner
        if (zapDetails.isNotEmpty()) {
            val topZap = remember(zapDetails) {
                zapDetails.maxByOrNull { it.sats }
            }
            if (topZap != null) {
                val zapperProfile = eventRepo?.getProfileData(topZap.pubkey)
                val zapperName = zapperProfile?.displayString
                    ?: topZap.pubkey.toNpub().let { "${it.take(12)}...${it.takeLast(4)}" }
                TopZapperBanner(
                    avatarUrl = zapperProfile?.picture,
                    name = zapperName,
                    sats = topZap.sats,
                    message = topZap.message,
                    onClick = {
                        val nav = onNavigateToProfileFromDetails ?: onNavigateToProfile
                        nav?.invoke(topZap.pubkey)
                    }
                )
            }
        }

        Spacer(Modifier.height(4.dp))

        // Action bar with expand/collapse
        Row(verticalAlignment = Alignment.CenterVertically) {
            ActionBar(
                onReply = onReply,
                onReact = onReact,
                userReactionEmojis = userReactionEmojis,
                onRepost = onRepost,
                onQuote = onQuote,
                hasUserReposted = hasUserReposted,
                repostCount = repostCount,
                onZap = onZap,
                hasUserZapped = hasUserZapped,
                onAddToList = onAddToList,
                isInList = isInList,
                likeCount = likeCount,
                replyCount = replyCount,
                zapSats = zapSats,
                isZapAnimating = isZapAnimating,
                isZapInProgress = isZapInProgress,
                reactionEmojiUrls = reactionEmojiUrls,
                resolvedEmojis = resolvedEmojis,
                unicodeEmojis = unicodeEmojis,
                onOpenEmojiLibrary = onOpenEmojiLibrary,
                modifier = Modifier.weight(1f)
            )
            Icon(
                imageVector = if (expandedDetails) Icons.Filled.KeyboardArrowUp
                    else Icons.Filled.KeyboardArrowDown,
                contentDescription = if (expandedDetails) stringResource(R.string.cd_collapse) else stringResource(R.string.cd_expand),
                tint = MaterialTheme.colorScheme.onSurfaceVariant,
                modifier = Modifier
                    .size(20.dp)
                    .clickable { expandedDetails = !expandedDetails }
            )
        }
        AnimatedVisibility(
            visible = expandedDetails,
            enter = expandVertically() + fadeIn(),
            exit = shrinkVertically() + fadeOut()
        ) {
            val profileResolver: (String) -> ProfileData? = { pubkey ->
                eventRepo?.getProfileData(pubkey)
            }
            val navToProfile = onNavigateToProfileFromDetails ?: onNavigateToProfile ?: {}
            Column {
                if (hasReactionDetails) {
                    ReactionDetailsSection(
                        reactionDetails = reactionDetails,
                        zapDetails = zapDetails,
                        repostDetails = repostDetails,
                        resolveProfile = profileResolver,
                        onProfileClick = navToProfile,
                        reactionEmojiUrls = reactionEmojiUrls,
                        eventRepo = eventRepo
                    )
                }
                if (displayIcons.isNotEmpty()) {
                    SeenOnSection(relayIcons = displayIcons, onRelayClick = onRelayClick)
                }
                if (clientName != null) {
                    ClientTagSection(clientName = clientName)
                }
            }
        }
    }

    if (showDivider) {
        HorizontalDivider(
            thickness = 0.5.dp,
            color = MaterialTheme.colorScheme.outlineVariant.copy(alpha = 0.5f)
        )
    }

    // Full-screen gallery viewer (images)
    if (fullScreenInitialPage >= 0) {
        FullScreenGalleryViewer(
            imageEntries = imageEntries,
            caption = event.content.takeIf { it.isNotBlank() },
            initialPage = fullScreenInitialPage,
            onDismiss = { fullScreenInitialPage = -1 }
        )
    }

}

@Composable
fun FullScreenGalleryViewer(
    imageEntries: List<Nip68.ImetaEntry>,
    caption: String?,
    initialPage: Int = 0,
    onDismiss: () -> Unit
) {
    if (imageEntries.isEmpty()) return

    Dialog(
        onDismissRequest = onDismiss,
        properties = DialogProperties(usePlatformDefaultWidth = false)
    ) {
        val context = LocalContext.current
        val clipboardManager = LocalClipboardManager.current
        val scope = rememberCoroutineScope()
        var currentPage by remember { mutableIntStateOf(initialPage.coerceIn(0, imageEntries.size - 1)) }

        val buttonColors = IconButtonDefaults.iconButtonColors(
            containerColor = Color.Black.copy(alpha = 0.5f),
            contentColor = Color.White
        )

        val entry = imageEntries[currentPage]

        var scale by remember(currentPage) { mutableFloatStateOf(1f) }
        var offset by remember(currentPage) { mutableStateOf(Offset.Zero) }


        Box(
            modifier = Modifier
                .fillMaxSize()
                .background(Color.Black)
        ) {
            // Zoomable image
            Box(
                modifier = Modifier
                    .fillMaxSize()
                    .clickable(
                        interactionSource = remember { MutableInteractionSource() },
                        indication = null,
                        onClick = { if (scale <= 1f) onDismiss() }
                    ),
                contentAlignment = Alignment.Center
            ) {
                AsyncImage(
                    model = entry.url,
                    contentDescription = entry.alt ?: "Image ${currentPage + 1} of ${imageEntries.size}",
                    contentScale = ContentScale.Fit,
                    modifier = Modifier
                        .fillMaxSize()
                        .graphicsLayer(
                            scaleX = scale,
                            scaleY = scale,
                            translationX = offset.x,
                            translationY = offset.y
                        )
                        .pointerInput(Unit) {
                            detectTransformGestures { _, pan, zoom, _ ->
                                val newScale = (scale * zoom).coerceIn(1f, 5f)
                                offset = if (newScale > 1f) offset + pan * scale else Offset.Zero
                                scale = newScale
                            }
                        }
                )
            }

            // Navigation arrows
            if (imageEntries.size > 1) {
                // Previous arrow
                if (currentPage > 0) {
                    IconButton(
                        onClick = { currentPage-- },
                        colors = buttonColors,
                        modifier = Modifier
                            .align(Alignment.CenterStart)
                            .padding(start = 8.dp)
                            .size(44.dp)
                    ) {
                        Icon(
                            Icons.AutoMirrored.Filled.KeyboardArrowLeft,
                            contentDescription = "Previous image"
                        )
                    }
                }

                // Next arrow
                if (currentPage < imageEntries.size - 1) {
                    IconButton(
                        onClick = { currentPage++ },
                        colors = buttonColors,
                        modifier = Modifier
                            .align(Alignment.CenterEnd)
                            .padding(end = 8.dp)
                            .size(44.dp)
                    ) {
                        Icon(
                            Icons.AutoMirrored.Filled.KeyboardArrowRight,
                            contentDescription = "Next image"
                        )
                    }
                }

                // Page counter
                Surface(
                    shape = RoundedCornerShape(16.dp),
                    color = Color.Black.copy(alpha = 0.5f),
                    modifier = Modifier
                        .align(Alignment.TopCenter)
                        .padding(top = 16.dp)
                ) {
                    Text(
                        text = "${currentPage + 1} / ${imageEntries.size}",
                        style = MaterialTheme.typography.labelMedium,
                        color = Color.White,
                        modifier = Modifier.padding(horizontal = 12.dp, vertical = 6.dp)
                    )
                }

                // Page indicator dots
                Row(
                    modifier = Modifier
                        .align(Alignment.BottomCenter)
                        .padding(bottom = if (caption != null) 60.dp else 16.dp),
                    horizontalArrangement = Arrangement.Center
                ) {
                    repeat(imageEntries.size) { index ->
                        Box(
                            modifier = Modifier
                                .padding(horizontal = 3.dp)
                                .size(8.dp)
                                .clip(CircleShape)
                                .background(
                                    if (index == currentPage)
                                        Color.White
                                    else
                                        Color.White.copy(alpha = 0.4f)
                                )
                        )
                    }
                }
            }

            // Current image URL for download/copy
            val currentUrl = entry.url

            // Top-right buttons
            Row(
                modifier = Modifier
                    .align(Alignment.TopEnd)
                    .padding(16.dp)
            ) {
                IconButton(
                    onClick = { scope.launch { MediaDownloader.downloadMedia(context, currentUrl) } },
                    colors = buttonColors,
                    modifier = Modifier.size(40.dp)
                ) {
                    Icon(
                        painter = painterResource(R.drawable.ic_download),
                        contentDescription = "Download"
                    )
                }
                Spacer(Modifier.width(8.dp))
                IconButton(
                    onClick = { clipboardManager.setText(AnnotatedString(currentUrl)) },
                    colors = buttonColors,
                    modifier = Modifier.size(40.dp)
                ) {
                    Icon(Icons.Default.ContentCopy, contentDescription = "Copy URL")
                }
                Spacer(Modifier.width(8.dp))
                IconButton(
                    onClick = onDismiss,
                    colors = buttonColors,
                    modifier = Modifier.size(40.dp)
                ) {
                    Icon(Icons.Default.Close, contentDescription = "Close")
                }
            }

            // Caption strip at bottom
            if (caption != null) {
                Box(
                    modifier = Modifier
                        .align(Alignment.BottomCenter)
                        .fillMaxWidth()
                        .background(Color.Black.copy(alpha = 0.6f))
                        .padding(horizontal = 16.dp, vertical = 12.dp)
                ) {
                    Text(
                        text = caption,
                        style = MaterialTheme.typography.bodyMedium,
                        color = Color.White,
                        maxLines = 4,
                        overflow = TextOverflow.Ellipsis
                    )
                }
            }
        }
    }
}

private fun parseAspectRatio(dim: String?): Float? {
    if (dim == null) return null
    val parts = dim.split("x")
    if (parts.size != 2) return null
    val w = parts[0].toFloatOrNull() ?: return null
    val h = parts[1].toFloatOrNull() ?: return null
    if (h == 0f) return null
    return w / h
}

private fun formatGalleryTimestamp(epoch: Long): String {
    val now = System.currentTimeMillis()
    val millis = epoch * 1000
    val diff = now - millis

    if (diff < 0) return galleryDateTimeFormat.format(Date(millis))

    val seconds = diff / 1000
    val minutes = seconds / 60
    val hours = minutes / 60

    if (seconds < 60) return "${seconds}s"
    if (minutes < 60) return "${minutes}m"
    if (hours < 24) return "${hours}h"

    val days = diff / (24 * 60 * 60 * 1000L)
    if (days < 7) return "${days}d"

    val date = Date(millis)
    val cal = java.util.Calendar.getInstance()
    val currentYear = cal.get(java.util.Calendar.YEAR)
    cal.time = date
    val dateYear = cal.get(java.util.Calendar.YEAR)

    return if (dateYear != currentYear) {
        galleryDateTimeYearFormat.format(date)
    } else {
        galleryDateTimeFormat.format(date)
    }
}

fun isGalleryEvent(event: NostrEvent): Boolean = event.kind in GALLERY_KINDS
