package com.swoosh.microblog.ui.feed

import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.animateColorAsState
import androidx.compose.animation.core.animateFloat
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.infiniteRepeatable
import androidx.compose.animation.core.rememberInfiniteTransition
import androidx.compose.animation.core.RepeatMode
import androidx.compose.animation.core.tween
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.expandVertically
import androidx.compose.animation.shrinkVertically
import androidx.compose.animation.slideInHorizontally
import androidx.compose.animation.slideOutVertically
import androidx.compose.animation.scaleIn
import androidx.compose.animation.slideInVertically
import androidx.compose.animation.togetherWith
import kotlinx.coroutines.delay
import androidx.compose.foundation.gestures.detectTapGestures
import com.swoosh.microblog.ui.animation.SwooshMotion
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.gestures.detectTransformGestures
import androidx.compose.foundation.horizontalScroll
import androidx.compose.foundation.layout.*
import kotlinx.coroutines.launch
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.filled.*
import androidx.compose.material.icons.outlined.FilterList
import androidx.compose.material.icons.outlined.PushPin
import androidx.compose.material.pullrefresh.PullRefreshIndicator
import androidx.compose.material.pullrefresh.pullRefresh
import androidx.compose.material.pullrefresh.rememberPullRefreshState
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.semantics.CustomAccessibilityAction
import androidx.compose.ui.semantics.contentDescription
import androidx.compose.ui.semantics.customActions
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.text.withStyle
import androidx.compose.ui.unit.DpOffset
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import android.content.Intent
import androidx.compose.ui.window.Dialog
import androidx.compose.ui.window.DialogProperties
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel
import coil.compose.AsyncImage
import com.swoosh.microblog.data.CredentialsManager
import com.swoosh.microblog.data.toDisplayUrl
import com.swoosh.microblog.data.ShareUtils
import com.swoosh.microblog.data.SiteMetadataCache
import com.swoosh.microblog.data.model.FeedPost
import com.swoosh.microblog.data.model.GhostAccount
import com.swoosh.microblog.data.model.GhostTagFull
import com.swoosh.microblog.data.model.PostFilter
import com.swoosh.microblog.data.model.PostStats
import com.swoosh.microblog.data.model.QueueStatus
import com.swoosh.microblog.data.model.SortOrder
import com.swoosh.microblog.ui.components.AudioPlayer
import com.swoosh.microblog.ui.components.ConfirmationDialog
import com.swoosh.microblog.ui.components.VideoPlayer

@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterialApi::class)
@Composable
fun FeedScreen(
    onPostClick: (FeedPost) -> Unit,
    onCompose: () -> Unit,
    onEditPost: (FeedPost) -> Unit,
    onAddAccount: () -> Unit = {},
    viewModel: FeedViewModel = viewModel()
) {
    val state by viewModel.uiState.collectAsStateWithLifecycle()
    val activeFilter by viewModel.activeFilter.collectAsStateWithLifecycle()
    val sortOrder by viewModel.sortOrder.collectAsStateWithLifecycle()
    val searchQuery by viewModel.searchQuery.collectAsStateWithLifecycle()
    val searchResults by viewModel.searchResults.collectAsStateWithLifecycle()
    val isSearchActive by viewModel.isSearchActive.collectAsStateWithLifecycle()
    val isSearching by viewModel.isSearching.collectAsStateWithLifecycle()
    val searchResultCount by viewModel.searchResultCount.collectAsStateWithLifecycle()
    val recentSearches by viewModel.recentSearches.collectAsStateWithLifecycle()
    val accounts by viewModel.accounts.collectAsStateWithLifecycle()
    val activeAccount by viewModel.activeAccount.collectAsStateWithLifecycle()
    val popularTags by viewModel.popularTags.collectAsStateWithLifecycle()
    val tagsEnabled by viewModel.tagsEnabled.collectAsStateWithLifecycle()
    val listState = rememberLazyListState()
    val context = LocalContext.current
    val snackbarHostState = remember { SnackbarHostState() }
    val baseUrl = remember { CredentialsManager(context).ghostUrl }
    val siteMetadataCache = remember { SiteMetadataCache(context) }
    val siteData = remember(activeAccount?.id) {
        activeAccount?.let { siteMetadataCache.get(it.id) }
    }

    // Track which post is pending delete confirmation
    var postPendingDelete by remember { mutableStateOf<FeedPost?>(null) }

    // Determine display posts based on search state
    val displayPosts = if (isSearchActive && searchQuery.isNotBlank()) searchResults else state.posts

    // Split posts into pinned and regular (only when not searching)
    val pinnedPosts = displayPosts.filter { it.featured }
    val regularPosts = displayPosts.filter { !it.featured }

    var showAccountSwitcher by remember { mutableStateOf(false) }
    var showDeleteConfirmation by remember { mutableStateOf<GhostAccount?>(null) }
    var showRenameDialog by remember { mutableStateOf<GhostAccount?>(null) }

    // Staggered entrance tracking
    // Stagger animations removed for smooth scrolling performance

    // FAB entrance animation
    var fabVisible by remember { mutableStateOf(false) }
    val fabScale by animateFloatAsState(
        targetValue = if (fabVisible) 1f else 0f,
        animationSpec = SwooshMotion.bouncy(),
        label = "fabEntrance"
    )
    LaunchedEffect(Unit) { fabVisible = true }

    // FAB press animation
    var fabPressed by remember { mutableStateOf(false) }
    val fabPressScale by animateFloatAsState(
        targetValue = if (fabPressed) 0.85f else 1f,
        animationSpec = SwooshMotion.bouncyQuick(),
        label = "fabPress"
    )

    // Pull-to-refresh
    val pullRefreshState = rememberPullRefreshState(
        refreshing = state.isRefreshing,
        onRefresh = { viewModel.refresh() }
    )

    val focusRequester = remember { FocusRequester() }

    // Infinite scroll trigger
    val shouldLoadMore by remember {
        derivedStateOf {
            val lastVisibleItem = listState.layoutInfo.visibleItemsInfo.lastOrNull()?.index ?: 0
            lastVisibleItem >= state.posts.size - 3
        }
    }

    LaunchedEffect(shouldLoadMore) {
        if (shouldLoadMore && state.posts.isNotEmpty() && !isSearchActive) {
            viewModel.loadMore()
        }
    }

    // Listen for snackbar events from the ViewModel
    LaunchedEffect(Unit) {
        viewModel.snackbarEvent.collect { event ->
            val result = snackbarHostState.showSnackbar(
                message = event.message,
                actionLabel = event.actionLabel,
                duration = SnackbarDuration.Short
            )
            if (result == SnackbarResult.ActionPerformed && event.onAction != null) {
                event.onAction.invoke()
            }
        }
    }

    Scaffold(
        topBar = {
            if (isSearchActive) {
                SearchTopBar(
                    query = searchQuery,
                    onQueryChange = viewModel::onSearchQueryChange,
                    onClose = viewModel::deactivateSearch,
                    onClear = viewModel::clearSearchQuery,
                    focusRequester = focusRequester
                )
            } else {
                TopAppBar(
                    title = {
                        Row(
                            verticalAlignment = Alignment.CenterVertically,
                            modifier = Modifier.clickable { showAccountSwitcher = true }
                        ) {
                            // Site icon or account avatar
                            val siteIconUrl = siteData?.icon ?: siteData?.logo
                            if (siteIconUrl != null) {
                                AsyncImage(
                                    model = siteIconUrl,
                                    contentDescription = "Site icon",
                                    modifier = Modifier
                                        .size(24.dp)
                                        .clip(CircleShape),
                                    contentScale = ContentScale.Crop
                                )
                                Spacer(modifier = Modifier.width(8.dp))
                            } else if (activeAccount != null) {
                                AccountAvatar(
                                    account = activeAccount!!,
                                    size = 28
                                )
                                Spacer(modifier = Modifier.width(8.dp))
                            }

                            Column {
                                // Use blog name from site metadata, truncate to ~20 chars
                                val displayName = siteData?.title?.let {
                                    if (it.length > 20) it.take(20) + "\u2026" else it
                                } ?: activeAccount?.name ?: "Swoosh"
                                Text(
                                    text = displayName,
                                    style = MaterialTheme.typography.titleMedium,
                                    maxLines = 1,
                                    overflow = TextOverflow.Ellipsis
                                )
                                if (activeAccount != null) {
                                    Text(
                                        text = activeAccount!!.blogUrl.toDisplayUrl(),
                                        style = MaterialTheme.typography.labelSmall,
                                        color = MaterialTheme.colorScheme.onSurfaceVariant,
                                        maxLines = 1,
                                        overflow = TextOverflow.Ellipsis
                                    )
                                }
                                if (activeFilter != PostFilter.ALL) {
                                    Text(
                                        text = activeFilter.displayName,
                                        style = MaterialTheme.typography.labelSmall,
                                        color = MaterialTheme.colorScheme.primary
                                    )
                                }
                            }

                            if (accounts.size > 1) {
                                Icon(
                                    Icons.Default.KeyboardArrowDown,
                                    contentDescription = "Switch account",
                                    modifier = Modifier.size(20.dp),
                                    tint = MaterialTheme.colorScheme.onSurfaceVariant
                                )
                            }
                        }
                    },
                    actions = {
                        IconButton(onClick = { viewModel.activateSearch() }) {
                            Icon(Icons.Default.Search, contentDescription = "Search")
                        }
                        SortButton(
                            currentSort = sortOrder,
                            onSortSelected = { viewModel.setSortOrder(it) }
                        )
                        IconButton(onClick = { viewModel.refresh() }) {
                            Icon(Icons.Default.Refresh, contentDescription = "Refresh")
                        }
                    }
                )
            }
        },
        floatingActionButton = {
            if (!isSearchActive) {
                FloatingActionButton(
                    onClick = onCompose,
                    modifier = Modifier
                        .graphicsLayer {
                            scaleX = fabScale * fabPressScale
                            scaleY = fabScale * fabPressScale
                        }
                        .pointerInput(Unit) {
                            detectTapGestures(
                                onPress = {
                                    fabPressed = true
                                    tryAwaitRelease()
                                    fabPressed = false
                                }
                            )
                        }
                ) {
                    Icon(Icons.Default.Add, contentDescription = "New post")
                }
            }
        },
        snackbarHost = { SnackbarHost(snackbarHostState) }
    ) { padding ->
        Column(
            modifier = Modifier
                .fillMaxSize()
                .padding(padding)
        ) {
            // Filter chips bar (only when not searching)
            AnimatedVisibility(
                visible = !isSearchActive,
                enter = fadeIn(SwooshMotion.quick()) + expandVertically(),
                exit = fadeOut(SwooshMotion.quick()) + shrinkVertically()
            ) {
                FilterChipsBar(
                    activeFilter = activeFilter,
                    onFilterSelected = { viewModel.setFilter(it) }
                )
            }

            // Tag filter chips
            AnimatedVisibility(
                visible = !isSearchActive && tagsEnabled && popularTags.isNotEmpty(),
                enter = fadeIn(SwooshMotion.quick()) + expandVertically(),
                exit = fadeOut(SwooshMotion.quick()) + shrinkVertically()
            ) {
                TagFilterChipsBar(
                    tags = popularTags,
                    activeTagFilter = state.activeTagFilter,
                    onTagSelected = { viewModel.filterByTag(it) },
                    onClearFilter = { viewModel.clearTagFilter() }
                )
            }

            // Loading overlay during account switch
            AnimatedVisibility(
                visible = state.isSwitchingAccount,
                enter = fadeIn(SwooshMotion.quick()),
                exit = fadeOut(SwooshMotion.quick())
            ) {
                Box(
                    modifier = Modifier.fillMaxSize(),
                    contentAlignment = Alignment.Center
                ) {
                    Column(horizontalAlignment = Alignment.CenterHorizontally) {
                        CircularProgressIndicator()
                        Spacer(modifier = Modifier.height(16.dp))
                        Text(
                            text = "Switching account...",
                            style = MaterialTheme.typography.bodyMedium,
                            color = MaterialTheme.colorScheme.onSurfaceVariant
                        )
                    }
                }
            }
            if (!state.isSwitchingAccount && isSearchActive && searchQuery.isBlank() && recentSearches.isNotEmpty()) {
                // Show recent searches when search is active but query is empty
                RecentSearchesList(
                    recentSearches = recentSearches,
                    onSearchTap = viewModel::onRecentSearchTap,
                    onRemove = viewModel::removeRecentSearch
                )
            } else if (isSearchActive && searchQuery.isNotBlank() && isSearching) {
                // Searching indicator
                AnimatedVisibility(
                    visible = true,
                    enter = fadeIn(SwooshMotion.quick()) + scaleIn(
                        initialScale = 0.9f,
                        animationSpec = SwooshMotion.quick()
                    )
                ) {
                    Box(
                        modifier = Modifier.fillMaxSize(),
                        contentAlignment = Alignment.Center
                    ) {
                        Column(horizontalAlignment = Alignment.CenterHorizontally) {
                            CircularProgressIndicator(modifier = Modifier.size(32.dp))
                            Spacer(modifier = Modifier.height(12.dp))
                            Text(
                                text = "Searching...",
                                style = MaterialTheme.typography.bodyMedium,
                                color = MaterialTheme.colorScheme.onSurfaceVariant
                            )
                        }
                    }
                }
            } else if (isSearchActive && searchQuery.isNotBlank() && searchResults.isEmpty() && !isSearching) {
                // No results empty state
                AnimatedVisibility(
                    visible = true,
                    enter = fadeIn(SwooshMotion.quick()) + scaleIn(
                        initialScale = 0.9f,
                        animationSpec = SwooshMotion.quick()
                    )
                ) {
                    Box(
                        modifier = Modifier.fillMaxSize(),
                        contentAlignment = Alignment.Center
                    ) {
                        Column(
                            horizontalAlignment = Alignment.CenterHorizontally,
                            modifier = Modifier.padding(horizontal = 32.dp)
                        ) {
                            Icon(
                                imageVector = Icons.Default.SearchOff,
                                contentDescription = null,
                                modifier = Modifier.size(48.dp),
                                tint = MaterialTheme.colorScheme.onSurfaceVariant
                            )
                            Spacer(modifier = Modifier.height(16.dp))
                            Text(
                                text = "No results found",
                                style = MaterialTheme.typography.titleMedium,
                                color = MaterialTheme.colorScheme.onSurfaceVariant
                            )
                            Spacer(modifier = Modifier.height(8.dp))
                            Text(
                                text = "No posts matching \"$searchQuery\"",
                                style = MaterialTheme.typography.bodyMedium,
                                color = MaterialTheme.colorScheme.onSurfaceVariant,
                                textAlign = TextAlign.Center
                            )
                        }
                    }
                }
            } else if (!isSearchActive && displayPosts.isEmpty() && !state.isRefreshing) {
                Box(
                    modifier = Modifier
                        .fillMaxSize()
                        .pullRefresh(pullRefreshState)
                ) {
                    if (state.isConnectionError && state.error != null) {
                        // Connection error empty state
                        Column(
                            modifier = Modifier.fillMaxSize(),
                            verticalArrangement = Arrangement.Center,
                            horizontalAlignment = Alignment.CenterHorizontally
                        ) {
                            AnimatedVisibility(
                                visible = true,
                                enter = fadeIn(SwooshMotion.quick()) + scaleIn(
                                    initialScale = 0.9f,
                                    animationSpec = SwooshMotion.quick()
                                )
                            ) {
                                Column(
                                    modifier = Modifier.padding(horizontal = 32.dp),
                                    verticalArrangement = Arrangement.Center,
                                    horizontalAlignment = Alignment.CenterHorizontally
                                ) {
                                    Icon(
                                        imageVector = Icons.Default.WifiOff,
                                        contentDescription = null,
                                        modifier = Modifier.size(48.dp),
                                        tint = MaterialTheme.colorScheme.error
                                    )
                                    Spacer(modifier = Modifier.height(16.dp))
                                    Text(
                                        text = state.error!!,
                                        style = MaterialTheme.typography.bodyMedium,
                                        color = MaterialTheme.colorScheme.onSurfaceVariant,
                                        textAlign = TextAlign.Center
                                    )
                                    Spacer(modifier = Modifier.height(16.dp))
                                    FilledTonalButton(onClick = { viewModel.refresh() }) {
                                        Icon(
                                            Icons.Default.Refresh,
                                            contentDescription = null,
                                            modifier = Modifier.size(18.dp)
                                        )
                                        Spacer(modifier = Modifier.width(8.dp))
                                        Text("Retry")
                                    }
                                }
                            }
                        }
                    } else {
                        // Filter-aware empty state
                        Column(
                            modifier = Modifier.fillMaxSize(),
                            verticalArrangement = Arrangement.Center,
                            horizontalAlignment = Alignment.CenterHorizontally
                        ) {
                            AnimatedVisibility(
                                visible = true,
                                enter = fadeIn(SwooshMotion.quick()) + scaleIn(
                                    initialScale = 0.9f,
                                    animationSpec = SwooshMotion.quick()
                                )
                            ) {
                                Column(
                                    horizontalAlignment = Alignment.CenterHorizontally
                                ) {
                                    Text(
                                        text = activeFilter.emptyMessage(),
                                        style = MaterialTheme.typography.titleMedium,
                                        color = MaterialTheme.colorScheme.onSurfaceVariant
                                    )
                                    Spacer(modifier = Modifier.height(8.dp))
                                    if (activeFilter == PostFilter.ALL) {
                                        Text(
                                            text = "Tap + to write your first post",
                                            style = MaterialTheme.typography.bodyMedium,
                                            color = MaterialTheme.colorScheme.onSurfaceVariant
                                        )
                                    } else {
                                        Text(
                                            text = "Try a different filter or create a new post",
                                            style = MaterialTheme.typography.bodyMedium,
                                            color = MaterialTheme.colorScheme.onSurfaceVariant
                                        )
                                    }
                                }
                            }
                        }
                    }

                    PullRefreshIndicator(
                        refreshing = state.isRefreshing,
                        state = pullRefreshState,
                        modifier = Modifier.align(Alignment.TopCenter)
                    )
                }
            } else {
                // Main content: posts list
                Box(
                    modifier = Modifier
                        .fillMaxSize()
                        .then(if (!isSearchActive) Modifier.pullRefresh(pullRefreshState) else Modifier)
                ) {
                    LazyColumn(
                        state = listState,
                        modifier = Modifier.fillMaxSize(),
                        contentPadding = PaddingValues(vertical = 8.dp)
                    ) {
                        // Show result count badge when searching
                        if (isSearchActive && searchQuery.isNotBlank() && !isSearching && searchResults.isNotEmpty()) {
                            item {
                                SearchResultsHeader(count = searchResultCount, query = searchQuery)
                            }
                        }

                        if (isSearchActive && searchQuery.isNotBlank()) {
                            // Search results: flat list with highlighting, no swipe actions
                            items(
                                displayPosts,
                                key = { it.ghostId ?: "local_${it.localId}" },
                                contentType = { "search_post" }
                            ) { post ->
                                PostCard(
                                    post = post,
                                    onClick = { onPostClick(post) },
                                    onCancelQueue = { viewModel.cancelQueuedPost(post) },
                                    highlightQuery = searchQuery
                                )
                            }
                        } else {
                            // Normal feed: pinned section + swipe actions
                            // Pinned posts (pin icon on each post card is sufficient)
                            if (pinnedPosts.isNotEmpty()) {
                                items(
                                    pinnedPosts,
                                    key = { "pinned_${it.ghostId ?: "local_${it.localId}"}" },
                                    contentType = { "pinned_post" }
                                ) { post ->
                                    SwipeablePostCard(
                                        post = post,
                                        onClick = { onPostClick(post) },
                                        onCancelQueue = { viewModel.cancelQueuedPost(post) },
                                        onShare = {
                                            val postUrl = ShareUtils.resolvePostUrl(post, baseUrl)
                                            if (postUrl != null) {
                                                val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
                                                clipboard.setPrimaryClip(ClipData.newPlainText("Post URL", postUrl))
                                            }
                                        },
                                        onEdit = { onEditPost(post) },
                                        onDelete = { postPendingDelete = post },
                                        onTogglePin = { viewModel.toggleFeatured(post) },
                                        onTagClick = { tag -> if (tagsEnabled) viewModel.filterByTag(tag) },
                                        snackbarHostState = snackbarHostState
                                    )
                                }
                                // No extra separator — thick dividers built into each post
                            }

                            items(
                                regularPosts,
                                key = { it.ghostId ?: "local_${it.localId}" },
                                contentType = { "regular_post" }
                            ) { post ->
                                SwipeablePostCard(
                                    post = post,
                                    onClick = { onPostClick(post) },
                                    onCancelQueue = { viewModel.cancelQueuedPost(post) },
                                    onShare = {
                                        val postUrl = ShareUtils.resolvePostUrl(post, baseUrl)
                                        if (postUrl != null) {
                                            val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
                                            clipboard.setPrimaryClip(ClipData.newPlainText("Post URL", postUrl))
                                        }
                                    },
                                    onEdit = { onEditPost(post) },
                                    onDelete = { postPendingDelete = post },
                                    onTogglePin = { viewModel.toggleFeatured(post) },
                                    onTagClick = { tag -> if (tagsEnabled) viewModel.filterByTag(tag) },
                                    snackbarHostState = snackbarHostState
                                )
                            }
                        }

                        if (!isSearchActive && state.isLoadingMore) {
                            item {
                                Box(
                                    modifier = Modifier.fillMaxWidth().padding(16.dp),
                                    contentAlignment = Alignment.Center
                                ) {
                                    CircularProgressIndicator(modifier = Modifier.size(24.dp))
                                }
                            }
                        }
                    }

                    if (!isSearchActive) {
                        PullRefreshIndicator(
                            refreshing = state.isRefreshing,
                            state = pullRefreshState,
                            modifier = Modifier.align(Alignment.TopCenter)
                        )
                    }

                    // Show snackbar for pin/unpin confirmation
                    if (state.snackbarMessage != null) {
                        Snackbar(
                            modifier = Modifier.align(Alignment.BottomCenter).padding(16.dp),
                            dismissAction = {
                                TextButton(onClick = viewModel::clearSnackbar) { Text("OK") }
                            }
                        ) {
                            Text(state.snackbarMessage!!)
                        }
                        LaunchedEffect(state.snackbarMessage) {
                            kotlinx.coroutines.delay(3000)
                            viewModel.clearSnackbar()
                        }
                    }

                    // Show non-connection errors as snackbar (when posts are visible)
                    if (state.error != null && (!state.isConnectionError || state.posts.isNotEmpty())) {
                        Snackbar(
                            modifier = Modifier.align(Alignment.BottomCenter).padding(16.dp),
                            action = {
                                TextButton(onClick = { viewModel.refresh() }) { Text("Retry") }
                            },
                            dismissAction = {
                                TextButton(onClick = viewModel::clearError) { Text("Dismiss") }
                            }
                        ) {
                            Text(state.error!!)
                        }
                    }
                }
            }
        }
    }

    // Delete confirmation dialog
    if (postPendingDelete != null) {
        ConfirmationDialog(
            title = "Delete this post?",
            message = "This action cannot be undone.",
            confirmLabel = "Delete",
            onConfirm = {
                val post = postPendingDelete!!
                postPendingDelete = null
                viewModel.deletePostWithUndo(post)
            },
            onDismiss = { postPendingDelete = null }
        )
    }

    // Account switcher bottom sheet
    if (showAccountSwitcher) {
        AccountSwitcherBottomSheet(
            accounts = accounts,
            activeAccountId = activeAccount?.id,
            onAccountSelected = { accountId ->
                showAccountSwitcher = false
                viewModel.switchAccount(accountId)
            },
            onAddAccount = {
                showAccountSwitcher = false
                onAddAccount()
            },
            onDeleteAccount = { account ->
                showDeleteConfirmation = account
            },
            onRenameAccount = { account ->
                showRenameDialog = account
            },
            onDismiss = { showAccountSwitcher = false }
        )
    }

    // Account delete confirmation dialog
    showDeleteConfirmation?.let { account ->
        ConfirmationDialog(
            title = "Remove Account",
            message = "Remove \"${account.name}\"? Local drafts for this account will be kept.",
            confirmLabel = "Remove",
            onConfirm = {
                viewModel.removeAccount(account.id)
                showDeleteConfirmation = null
                if (accounts.size <= 1) showAccountSwitcher = false
            },
            onDismiss = { showDeleteConfirmation = null }
        )
    }

    // Account rename dialog
    showRenameDialog?.let { account ->
        var newName by remember { mutableStateOf(account.name) }
        AlertDialog(
            onDismissRequest = { showRenameDialog = null },
            title = { Text("Rename Account") },
            text = {
                OutlinedTextField(
                    value = newName,
                    onValueChange = { newName = it },
                    label = { Text("Account Name") },
                    singleLine = true,
                    modifier = Modifier.fillMaxWidth()
                )
            },
            confirmButton = {
                TextButton(
                    onClick = {
                        if (newName.isNotBlank()) {
                            viewModel.renameAccount(account.id, newName)
                            showRenameDialog = null
                        }
                    }
                ) { Text("Save") }
            },
            dismissButton = {
                TextButton(onClick = { showRenameDialog = null }) { Text("Cancel") }
            }
        )
    }
}


@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun FilterChipsBar(
    activeFilter: PostFilter,
    onFilterSelected: (PostFilter) -> Unit
) {
    val context = LocalContext.current
    val newsletterEnabled = remember {
        com.swoosh.microblog.data.NewsletterPreferences(context).isNewsletterEnabled()
    }
    val sentColor = Color(0xFF6A1B9A) // magenta

    Row(
        modifier = Modifier
            .fillMaxWidth()
            .horizontalScroll(rememberScrollState())
            .padding(horizontal = 16.dp, vertical = 4.dp),
        horizontalArrangement = Arrangement.spacedBy(8.dp)
    ) {
        PostFilter.values().forEach { filter ->
            // Only show SENT chip when newsletter is enabled
            if (filter == PostFilter.SENT && !newsletterEnabled) return@forEach

            val selected = filter == activeFilter
            val containerColor by animateColorAsState(
                targetValue = when {
                    selected && filter == PostFilter.SENT -> sentColor.copy(alpha = 0.2f)
                    selected -> MaterialTheme.colorScheme.primaryContainer
                    else -> MaterialTheme.colorScheme.surface
                },
                animationSpec = SwooshMotion.quick(),
                label = "chipColor"
            )
            FilterChip(
                selected = selected,
                onClick = { onFilterSelected(filter) },
                label = {
                    Text(
                        filter.displayName,
                        color = if (selected && filter == PostFilter.SENT) sentColor
                                else Color.Unspecified
                    )
                },
                colors = FilterChipDefaults.filterChipColors(
                    selectedContainerColor = containerColor
                )
            )
        }
    }
}

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun TagFilterChipsBar(
    tags: List<GhostTagFull>,
    activeTagFilter: String?,
    onTagSelected: (String) -> Unit,
    onClearFilter: () -> Unit
) {
    LazyRow(
        modifier = Modifier
            .fillMaxWidth()
            .padding(vertical = 4.dp),
        contentPadding = PaddingValues(horizontal = 16.dp),
        horizontalArrangement = Arrangement.spacedBy(8.dp)
    ) {
        // "All tags" chip
        item {
            val isAllSelected = activeTagFilter == null
            FilterChip(
                selected = isAllSelected,
                onClick = { onClearFilter() },
                label = { Text("All tags") },
                colors = FilterChipDefaults.filterChipColors(
                    selectedContainerColor = MaterialTheme.colorScheme.primaryContainer
                )
            )
        }

        // Tag chips
        items(tags, key = { it.id ?: it.name }) { tag ->
            val isSelected = activeTagFilter != null && activeTagFilter.equals(tag.name, ignoreCase = true)
            FilterChip(
                selected = isSelected,
                onClick = {
                    if (isSelected) onClearFilter() else onTagSelected(tag.name)
                },
                label = {
                    val postCount = tag.count?.posts
                    if (postCount != null) {
                        Text("${tag.name} ($postCount)")
                    } else {
                        Text(tag.name)
                    }
                },
                colors = FilterChipDefaults.filterChipColors(
                    selectedContainerColor = MaterialTheme.colorScheme.primaryContainer
                )
            )
        }
    }
}

@Composable
fun SortButton(
    currentSort: SortOrder,
    onSortSelected: (SortOrder) -> Unit
) {
    var expanded by remember { mutableStateOf(false) }

    Box {
        IconButton(onClick = { expanded = true }) {
            Icon(
                imageVector = Icons.Outlined.FilterList,
                contentDescription = "Sort: ${currentSort.displayName}",
                tint = if (currentSort != SortOrder.NEWEST)
                    MaterialTheme.colorScheme.primary
                else
                    LocalContentColor.current
            )
        }

        DropdownMenu(
            expanded = expanded,
            onDismissRequest = { expanded = false }
        ) {
            SortOrder.values().forEach { order ->
                DropdownMenuItem(
                    text = {
                        Text(
                            text = order.displayName,
                            color = if (order == currentSort)
                                MaterialTheme.colorScheme.primary
                            else
                                MaterialTheme.colorScheme.onSurface
                        )
                    },
                    onClick = {
                        onSortSelected(order)
                        expanded = false
                    },
                    leadingIcon = if (order == currentSort) {
                        {
                            Icon(
                                imageVector = Icons.Outlined.FilterList,
                                contentDescription = null,
                                tint = MaterialTheme.colorScheme.primary,
                                modifier = Modifier.size(18.dp)
                            )
                        }
                    } else null
                )
            }
        }
    }
}

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun PinnedSectionHeader() {
    Row(
        modifier = Modifier
            .fillMaxWidth()
            .padding(horizontal = 16.dp, vertical = 4.dp),
        verticalAlignment = Alignment.CenterVertically
    ) {
        Icon(
            imageVector = Icons.Filled.PushPin,
            contentDescription = null,
            modifier = Modifier.size(16.dp),
            tint = MaterialTheme.colorScheme.primary
        )
        Spacer(modifier = Modifier.width(6.dp))
        Text(
            text = "Pinned",
            style = MaterialTheme.typography.labelMedium.copy(fontWeight = FontWeight.SemiBold),
            color = MaterialTheme.colorScheme.primary
        )
    }
}

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun SwipeablePostCard(
    post: FeedPost,
    onClick: () -> Unit,
    onCancelQueue: () -> Unit,
    onShare: () -> Unit = {},
    onEdit: () -> Unit,
    onDelete: () -> Unit,
    onTogglePin: () -> Unit = {},
    onTagClick: (String) -> Unit = {},
    snackbarHostState: SnackbarHostState? = null
) {
    val dismissState = rememberSwipeToDismissBoxState(
        confirmValueChange = { value ->
            when (value) {
                SwipeToDismissBoxValue.StartToEnd -> {
                    // Swipe right -> Edit
                    onEdit()
                    false // Don't settle in dismissed state; snap back
                }
                SwipeToDismissBoxValue.EndToStart -> {
                    // Swipe left -> Delete confirmation
                    onDelete()
                    false // Don't settle; snap back and show dialog
                }
                SwipeToDismissBoxValue.Settled -> true
            }
        },
        positionalThreshold = { totalDistance -> totalDistance * 0.4f }
    )

    SwipeToDismissBox(
        state = dismissState,
        backgroundContent = {
            SwipeBackground(dismissState)
        },
        modifier = Modifier
            .semantics {
                customActions = listOf(
                    CustomAccessibilityAction("Edit post") {
                        onEdit()
                        true
                    },
                    CustomAccessibilityAction("Delete post") {
                        onDelete()
                        true
                    }
                )
            }
    ) {
        Surface(
            color = MaterialTheme.colorScheme.surface,
            modifier = Modifier.fillMaxWidth()
        ) {
            PostCardContent(
                post = post,
                onClick = onClick,
                onCancelQueue = onCancelQueue,
                onShare = onShare,
                onEdit = onEdit,
                onDelete = onDelete,
                onTogglePin = onTogglePin,
                onTagClick = onTagClick,
                snackbarHostState = snackbarHostState
            )
        }
    }
}

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun SwipeBackground(dismissState: SwipeToDismissBoxState) {
    val direction = dismissState.dismissDirection

    val color by animateColorAsState(
        when (direction) {
            SwipeToDismissBoxValue.StartToEnd -> Color(0xFF1565C0) // Bold blue
            SwipeToDismissBoxValue.EndToStart -> Color(0xFFC62828) // Bold red
            SwipeToDismissBoxValue.Settled -> Color.Transparent
        },
        animationSpec = SwooshMotion.quick(),
        label = "swipe_bg_color"
    )

    val icon = when (direction) {
        SwipeToDismissBoxValue.StartToEnd -> Icons.Default.Edit
        SwipeToDismissBoxValue.EndToStart -> Icons.Default.Delete
        SwipeToDismissBoxValue.Settled -> null
    }

    val label = when (direction) {
        SwipeToDismissBoxValue.StartToEnd -> "Edit"
        SwipeToDismissBoxValue.EndToStart -> "Delete"
        SwipeToDismissBoxValue.Settled -> null
    }

    val alignment = when (direction) {
        SwipeToDismissBoxValue.StartToEnd -> Alignment.CenterStart
        SwipeToDismissBoxValue.EndToStart -> Alignment.CenterEnd
        SwipeToDismissBoxValue.Settled -> Alignment.Center
    }

    Box(
        modifier = Modifier
            .fillMaxSize()
            .background(color)
            .padding(horizontal = 24.dp),
        contentAlignment = alignment
    ) {
        if (icon != null && label != null) {
            Row(
                verticalAlignment = Alignment.CenterVertically,
                horizontalArrangement = Arrangement.spacedBy(8.dp)
            ) {
                if (direction == SwipeToDismissBoxValue.StartToEnd) {
                    Icon(
                        imageVector = icon,
                        contentDescription = label,
                        tint = Color.White
                    )
                    Text(
                        text = label,
                        color = Color.White,
                        style = MaterialTheme.typography.labelLarge
                    )
                } else {
                    Text(
                        text = label,
                        color = Color.White,
                        style = MaterialTheme.typography.labelLarge
                    )
                    Icon(
                        imageVector = icon,
                        contentDescription = label,
                        tint = Color.White
                    )
                }
            }
        }
    }
}

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun AccountSwitcherBottomSheet(
    accounts: List<GhostAccount>,
    activeAccountId: String?,
    onAccountSelected: (String) -> Unit,
    onAddAccount: () -> Unit,
    onDeleteAccount: (GhostAccount) -> Unit,
    onRenameAccount: (GhostAccount) -> Unit,
    onDismiss: () -> Unit
) {
    val sheetState = rememberModalBottomSheetState()

    ModalBottomSheet(
        onDismissRequest = onDismiss,
        sheetState = sheetState
    ) {
        Column(
            modifier = Modifier
                .fillMaxWidth()
                .padding(bottom = 32.dp)
        ) {
            Text(
                text = "Accounts",
                style = MaterialTheme.typography.titleMedium,
                modifier = Modifier.padding(horizontal = 24.dp, vertical = 8.dp)
            )

            accounts.forEachIndexed { index, account ->
                var itemVisible by remember { mutableStateOf(false) }
                LaunchedEffect(account.id) {
                    delay(SwooshMotion.StaggerDelayMs * index)
                    itemVisible = true
                }
                AnimatedVisibility(
                    visible = itemVisible,
                    enter = slideInHorizontally(
                        initialOffsetX = { -it / 4 },
                        animationSpec = SwooshMotion.gentle()
                    ) + fadeIn(SwooshMotion.quick())
                ) {
                    AccountListItem(
                        account = account,
                        isActive = account.id == activeAccountId,
                        onClick = { onAccountSelected(account.id) },
                        onDelete = { onDeleteAccount(account) },
                        onRename = { onRenameAccount(account) }
                    )
                }
            }

            if (accounts.size < 5) {
                HorizontalDivider(modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp))

                ListItem(
                    headlineContent = { Text("Add account") },
                    leadingContent = {
                        Icon(
                            Icons.Default.Add,
                            contentDescription = "Add account",
                            tint = MaterialTheme.colorScheme.primary
                        )
                    },
                    modifier = Modifier.clickable(onClick = onAddAccount)
                )
            }
        }
    }
}

@Composable
fun AccountListItem(
    account: GhostAccount,
    isActive: Boolean,
    onClick: () -> Unit,
    onDelete: () -> Unit,
    onRename: () -> Unit
) {
    var showMenu by remember { mutableStateOf(false) }

    ListItem(
        headlineContent = {
            Text(
                account.name,
                style = MaterialTheme.typography.bodyLarge,
                color = if (isActive) MaterialTheme.colorScheme.primary
                        else MaterialTheme.colorScheme.onSurface
            )
        },
        supportingContent = {
            Text(
                account.blogUrl.toDisplayUrl(),
                style = MaterialTheme.typography.bodySmall,
                color = MaterialTheme.colorScheme.onSurfaceVariant
            )
        },
        leadingContent = {
            AccountAvatar(account = account, size = 36)
        },
        trailingContent = {
            Row(verticalAlignment = Alignment.CenterVertically) {
                if (isActive) {
                    Icon(
                        Icons.Default.Check,
                        contentDescription = "Active",
                        tint = MaterialTheme.colorScheme.primary,
                        modifier = Modifier.size(20.dp)
                    )
                    Spacer(modifier = Modifier.width(4.dp))
                }
                Box {
                    IconButton(onClick = { showMenu = true }) {
                        Icon(
                            Icons.Default.Edit,
                            contentDescription = "More options",
                            modifier = Modifier.size(18.dp)
                        )
                    }
                    DropdownMenu(
                        expanded = showMenu,
                        onDismissRequest = { showMenu = false }
                    ) {
                        DropdownMenuItem(
                            text = { Text("Rename") },
                            onClick = {
                                showMenu = false
                                onRename()
                            },
                            leadingIcon = {
                                Icon(Icons.Default.Edit, contentDescription = null, modifier = Modifier.size(18.dp))
                            }
                        )
                        DropdownMenuItem(
                            text = { Text("Remove", color = MaterialTheme.colorScheme.error) },
                            onClick = {
                                showMenu = false
                                onDelete()
                            },
                            leadingIcon = {
                                Icon(
                                    Icons.Default.Delete,
                                    contentDescription = null,
                                    modifier = Modifier.size(18.dp),
                                    tint = MaterialTheme.colorScheme.error
                                )
                            }
                        )
                    }
                }
            }
        },
        modifier = Modifier.clickable(onClick = onClick)
    )
}

@Composable
fun AccountAvatar(
    account: GhostAccount,
    size: Int = 36
) {
    if (!account.avatarUrl.isNullOrBlank()) {
        AsyncImage(
            model = account.avatarUrl,
            contentDescription = account.name,
            modifier = Modifier
                .size(size.dp)
                .clip(CircleShape),
            contentScale = ContentScale.Crop
        )
    } else {
        val color = Color(GhostAccount.colorForIndex(account.colorIndex))
        val initial = account.name.firstOrNull()?.uppercase() ?: "?"
        Box(
            modifier = Modifier
                .size(size.dp)
                .clip(CircleShape)
                .background(color),
            contentAlignment = Alignment.Center
        ) {
            Text(
                text = initial,
                color = Color.White,
                style = if (size <= 28) MaterialTheme.typography.labelSmall
                        else MaterialTheme.typography.labelLarge
            )
        }
    }
}

@OptIn(ExperimentalMaterial3Api::class, ExperimentalLayoutApi::class)
@Composable
fun SearchTopBar(
    query: String,
    onQueryChange: (String) -> Unit,
    onClose: () -> Unit,
    onClear: () -> Unit,
    focusRequester: FocusRequester
) {
    TopAppBar(
        title = {
            TextField(
                value = query,
                onValueChange = onQueryChange,
                placeholder = { Text("Search posts...") },
                singleLine = true,
                colors = TextFieldDefaults.colors(
                    focusedContainerColor = MaterialTheme.colorScheme.surface,
                    unfocusedContainerColor = MaterialTheme.colorScheme.surface,
                    focusedIndicatorColor = MaterialTheme.colorScheme.primary,
                    unfocusedIndicatorColor = MaterialTheme.colorScheme.surfaceVariant
                ),
                modifier = Modifier
                    .fillMaxWidth()
                    .focusRequester(focusRequester),
                trailingIcon = {
                    if (query.isNotEmpty()) {
                        IconButton(onClick = onClear) {
                            Icon(Icons.Default.Close, contentDescription = "Clear search")
                        }
                    }
                }
            )
        },
        navigationIcon = {
            IconButton(onClick = onClose) {
                Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Close search")
            }
        }
    )

    LaunchedEffect(Unit) {
        focusRequester.requestFocus()
    }
}

@Composable
fun SearchResultsHeader(count: Int, query: String) {
    Row(
        modifier = Modifier
            .fillMaxWidth()
            .padding(horizontal = 16.dp, vertical = 8.dp),
        verticalAlignment = Alignment.CenterVertically
    ) {
        Surface(
            shape = MaterialTheme.shapes.small,
            color = MaterialTheme.colorScheme.primaryContainer
        ) {
            Text(
                text = "$count",
                style = MaterialTheme.typography.labelMedium,
                color = MaterialTheme.colorScheme.onPrimaryContainer,
                modifier = Modifier.padding(horizontal = 8.dp, vertical = 4.dp)
            )
        }
        Spacer(modifier = Modifier.width(8.dp))
        Text(
            text = if (count == 1) "result for \"$query\"" else "results for \"$query\"",
            style = MaterialTheme.typography.bodySmall,
            color = MaterialTheme.colorScheme.onSurfaceVariant
        )
    }
}

@Composable
fun RecentSearchesList(
    recentSearches: List<String>,
    onSearchTap: (String) -> Unit,
    onRemove: (String) -> Unit
) {
    Column(
        modifier = Modifier
            .fillMaxWidth()
            .padding(top = 8.dp)
    ) {
        Text(
            text = "Recent searches",
            style = MaterialTheme.typography.titleSmall,
            color = MaterialTheme.colorScheme.onSurfaceVariant,
            modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp)
        )
        recentSearches.forEach { query ->
            ListItem(
                headlineContent = { Text(query) },
                leadingContent = {
                    Icon(
                        Icons.Default.History,
                        contentDescription = null,
                        tint = MaterialTheme.colorScheme.onSurfaceVariant
                    )
                },
                trailingContent = {
                    IconButton(onClick = { onRemove(query) }) {
                        Icon(
                            Icons.Default.Close,
                            contentDescription = "Remove",
                            modifier = Modifier.size(18.dp)
                        )
                    }
                },
                modifier = Modifier.clickable { onSearchTap(query) }
            )
        }
    }
}

@Composable
private fun PulsingAssistChip(
    label: String,
    isUploading: Boolean,
    modifier: Modifier = Modifier
) {
    if (isUploading) {
        val infiniteTransition = rememberInfiniteTransition(label = "queuePulse")
        val chipAlpha by infiniteTransition.animateFloat(
            initialValue = 0.6f,
            targetValue = 1f,
            animationSpec = infiniteRepeatable(
                animation = tween(500),
                repeatMode = RepeatMode.Reverse
            ),
            label = "uploadPulse"
        )
        AssistChip(
            onClick = {},
            label = { Text(label, style = MaterialTheme.typography.labelSmall) },
            modifier = modifier.graphicsLayer { alpha = chipAlpha }
        )
    } else {
        AssistChip(
            onClick = {},
            label = { Text(label, style = MaterialTheme.typography.labelSmall) },
            modifier = modifier
        )
    }
}

@OptIn(ExperimentalFoundationApi::class)
@Composable
fun PostCardContent(
    post: FeedPost,
    onClick: () -> Unit,
    onCancelQueue: () -> Unit,
    onShare: () -> Unit = {},
    onEdit: () -> Unit = {},
    onDelete: () -> Unit = {},
    onTogglePin: () -> Unit = {},
    onTagClick: (String) -> Unit = {},
    snackbarHostState: SnackbarHostState? = null,
    highlightQuery: String? = null
) {
    var expanded by remember { mutableStateOf(false) }
    var showContextMenu by remember { mutableStateOf(false) }
    val coroutineScope = rememberCoroutineScope()

    val isPublished = post.status == "published" && post.queueStatus == QueueStatus.NONE
    val hasShareableUrl = !post.slug.isNullOrBlank() || !post.url.isNullOrBlank()

    // Gallery viewer state
    var showGallery by remember { mutableStateOf(false) }
    var galleryStartIndex by remember { mutableIntStateOf(0) }

    // Determine which images to show
    val allImages = if (post.imageUrls.isNotEmpty()) {
        post.imageUrls
    } else if (post.imageUrl != null) {
        listOf(post.imageUrl)
    } else {
        emptyList()
    }

    Column(
        modifier = Modifier
            .fillMaxWidth()
            .combinedClickable(
                onClick = onClick,
                onClickLabel = "View post details",
                onLongClick = { showContextMenu = true }
            )
    ) {
        // Padded content area
        Column(
            modifier = Modifier.padding(horizontal = 20.dp, vertical = 16.dp)
        ) {
            // Top row: pin indicator (if pinned) + timestamp
            Row(
                modifier = Modifier.fillMaxWidth(),
                horizontalArrangement = Arrangement.SpaceBetween,
                verticalAlignment = Alignment.CenterVertically
            ) {
                if (post.featured) {
                    Icon(
                        imageVector = Icons.Filled.PushPin,
                        contentDescription = "Pinned",
                        modifier = Modifier.size(14.dp),
                        tint = MaterialTheme.colorScheme.primary
                    )
                } else {
                    Spacer(modifier = Modifier.width(1.dp))
                }
                Text(
                    text = formatRelativeTime(post.publishedAt ?: post.createdAt),
                    style = MaterialTheme.typography.labelMedium,
                    color = MaterialTheme.colorScheme.onSurfaceVariant
                )
            }

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

            // Content -- the star of the show
            if (highlightQuery != null && highlightQuery.isNotBlank()) {
                HighlightedText(
                    text = if (expanded || post.textContent.length <= 280) post.textContent
                           else post.textContent.take(280) + "...",
                    query = highlightQuery,
                    maxLines = if (expanded) Int.MAX_VALUE else 8
                )
            } else {
                AnimatedContent(
                    targetState = expanded,
                    transitionSpec = {
                        (fadeIn(SwooshMotion.quick()) + expandVertically(animationSpec = SwooshMotion.snappy()))
                            .togetherWith(fadeOut(SwooshMotion.quick()) + shrinkVertically(animationSpec = SwooshMotion.snappy()))
                    },
                    label = "expandText"
                ) { isExpanded ->
                    Column {
                        Text(
                            text = if (isExpanded || post.textContent.length <= 280) post.textContent
                                   else post.textContent.take(280) + "...",
                            style = MaterialTheme.typography.bodyMedium,
                            maxLines = if (isExpanded) Int.MAX_VALUE else 8,
                            overflow = TextOverflow.Ellipsis
                        )
                        if (!isExpanded && post.textContent.length > 280) {
                            TextButton(
                                onClick = { expanded = true },
                                contentPadding = PaddingValues(0.dp)
                            ) {
                                Text("Show more", style = MaterialTheme.typography.labelMedium)
                            }
                        }
                    }
                }
            }

            // Image grid
            if (allImages.isNotEmpty()) {
                Spacer(modifier = Modifier.height(12.dp))
                PostImageGrid(
                    images = allImages,
                    onImageClick = { index ->
                        galleryStartIndex = index
                        showGallery = true
                    }
                )
                if (!post.imageAlt.isNullOrBlank()) {
                    var showAltPopup by remember { mutableStateOf(false) }
                    Text(
                        text = "ALT",
                        modifier = Modifier
                            .padding(top = 4.dp)
                            .clip(RoundedCornerShape(4.dp))
                            .background(MaterialTheme.colorScheme.inverseSurface.copy(alpha = 0.8f))
                            .clickable { showAltPopup = !showAltPopup }
                            .padding(horizontal = 6.dp, vertical = 2.dp),
                        color = MaterialTheme.colorScheme.inverseOnSurface,
                        fontSize = 11.sp,
                        fontWeight = FontWeight.Bold
                    )
                    if (showAltPopup) {
                        Text(
                            text = post.imageAlt,
                            modifier = Modifier.padding(top = 4.dp),
                            style = MaterialTheme.typography.bodySmall,
                            color = MaterialTheme.colorScheme.onSurfaceVariant
                        )
                    }
                }
            }

            // Video player (compact)
            if (post.videoUrl != null) {
                Spacer(modifier = Modifier.height(12.dp))
                VideoPlayer(url = post.videoUrl, compact = true)
            }

            // Audio player (compact)
            if (post.audioUrl != null) {
                Spacer(modifier = Modifier.height(12.dp))
                AudioPlayer(url = post.audioUrl)
            }

            // Link preview
            if (post.linkUrl != null && post.linkTitle != null) {
                Spacer(modifier = Modifier.height(12.dp))
                OutlinedCard(modifier = Modifier.fillMaxWidth()) {
                    Column(modifier = Modifier.padding(12.dp)) {
                        if (post.linkImageUrl != null) {
                            AsyncImage(
                                model = post.linkImageUrl,
                                contentDescription = null,
                                modifier = Modifier
                                    .fillMaxWidth()
                                    .height(120.dp)
                                    .clip(MaterialTheme.shapes.small),
                                contentScale = ContentScale.Crop
                            )
                            Spacer(modifier = Modifier.height(8.dp))
                        }
                        Text(
                            text = post.linkTitle,
                            style = MaterialTheme.typography.titleSmall,
                            maxLines = 2,
                            overflow = TextOverflow.Ellipsis
                        )
                        if (post.linkDescription != null) {
                            Text(
                                text = post.linkDescription,
                                style = MaterialTheme.typography.bodySmall,
                                color = MaterialTheme.colorScheme.onSurfaceVariant,
                                maxLines = 2,
                                overflow = TextOverflow.Ellipsis
                            )
                        }
                    }
                }
            }

            // File attachment
            if (post.fileUrl != null) {
                Spacer(modifier = Modifier.height(12.dp))
                FileAttachmentCard(
                    fileUrl = post.fileUrl,
                    fileName = post.fileName ?: "File"
                )
            }

            // Tags display
            if (post.tags.isNotEmpty()) {
                Spacer(modifier = Modifier.height(10.dp))
                Text(
                    text = post.tags.joinToString(" \u00B7 ") { "#$it" },
                    style = MaterialTheme.typography.labelSmall,
                    color = MaterialTheme.colorScheme.primary,
                    maxLines = 1,
                    overflow = TextOverflow.Ellipsis,
                    modifier = Modifier.clickable {
                        post.tags.firstOrNull()?.let { onTagClick(it) }
                    }
                )
            }

            // Queue status
            if (post.queueStatus != QueueStatus.NONE) {
                Spacer(modifier = Modifier.height(8.dp))
                val queueLabel = when (post.queueStatus) {
                    QueueStatus.QUEUED_PUBLISH, QueueStatus.QUEUED_SCHEDULED -> "Pending upload"
                    QueueStatus.QUEUED_EMAIL_ONLY -> "Pending email send"
                    QueueStatus.UPLOADING -> "Uploading..."
                    QueueStatus.FAILED -> "Upload failed"
                    else -> ""
                }
                val isUploading = post.queueStatus == QueueStatus.UPLOADING
                Row(verticalAlignment = Alignment.CenterVertically) {
                    PulsingAssistChip(
                        label = queueLabel,
                        isUploading = isUploading
                    )
                    if (post.queueStatus == QueueStatus.QUEUED_PUBLISH || post.queueStatus == QueueStatus.QUEUED_SCHEDULED || post.queueStatus == QueueStatus.QUEUED_EMAIL_ONLY) {
                        Spacer(modifier = Modifier.width(8.dp))
                        TextButton(onClick = onCancelQueue) {
                            Text("Cancel", style = MaterialTheme.typography.labelSmall)
                        }
                    }
                }
            }

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

            // Status line: colored dot + status text + reading time
            val stats = remember(post.textContent, post.imageUrl, post.linkUrl) {
                PostStats.fromFeedPost(post)
            }
            val isSent = post.status == "sent" || post.emailOnly
            val statusLabel = when {
                post.queueStatus != QueueStatus.NONE -> "Pending"
                isSent -> "Sent"
                else -> post.status.replaceFirstChar { it.uppercase() }
            }
            val statusColor = when {
                post.queueStatus != QueueStatus.NONE -> Color(0xFFE65100)
                isSent -> Color(0xFF6A1B9A)
                post.status == "published" -> Color(0xFF2E7D32)
                post.status == "scheduled" -> Color(0xFF1565C0)
                else -> Color(0xFF7B1FA2)
            }
            Row(
                verticalAlignment = Alignment.CenterVertically,
                horizontalArrangement = Arrangement.spacedBy(6.dp)
            ) {
                if (isSent) {
                    Icon(
                        Icons.Default.Email,
                        contentDescription = "Sent",
                        modifier = Modifier.size(12.dp),
                        tint = statusColor
                    )
                } else {
                    Box(
                        modifier = Modifier
                            .size(8.dp)
                            .clip(CircleShape)
                            .background(statusColor)
                    )
                }
                Text(
                    text = statusLabel,
                    style = MaterialTheme.typography.labelSmall.copy(fontWeight = FontWeight.Bold),
                    color = statusColor
                )
                Text(
                    text = "\u00B7",
                    style = MaterialTheme.typography.labelSmall,
                    color = MaterialTheme.colorScheme.onSurfaceVariant
                )
                Text(
                    text = PostStats.formatReadingTime(stats.readingTimeMinutes),
                    style = MaterialTheme.typography.labelSmall,
                    color = MaterialTheme.colorScheme.onSurfaceVariant
                )
            }

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

            // Action bar separator
            HorizontalDivider(color = MaterialTheme.colorScheme.outlineVariant.copy(alpha = 0.5f))

            // Action bar -- evenly spaced icons with labels
            Row(
                modifier = Modifier
                    .fillMaxWidth()
                    .padding(top = 8.dp),
                horizontalArrangement = Arrangement.SpaceEvenly
            ) {
                // Edit action
                Column(
                    horizontalAlignment = Alignment.CenterHorizontally,
                    modifier = Modifier.clickable(onClick = onEdit)
                ) {
                    Icon(
                        Icons.Default.Edit,
                        contentDescription = "Edit",
                        modifier = Modifier.size(24.dp),
                        tint = MaterialTheme.colorScheme.onSurfaceVariant
                    )
                    Text(
                        text = "Edit",
                        style = MaterialTheme.typography.labelSmall,
                        color = MaterialTheme.colorScheme.onSurfaceVariant
                    )
                }

                // Share / Copy content action
                if (isSent) {
                    // For sent (email-only) posts, show "Copy content" instead of "Share"
                    val copyContext = LocalContext.current
                    Column(
                        horizontalAlignment = Alignment.CenterHorizontally,
                        modifier = Modifier.clickable {
                            val clipboard = copyContext.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
                            clipboard.setPrimaryClip(ClipData.newPlainText("Post content", post.textContent))
                            snackbarHostState?.let { host ->
                                coroutineScope.launch {
                                    host.showSnackbar("Content copied to clipboard")
                                }
                            }
                        }
                    ) {
                        Icon(
                            Icons.Default.ContentCopy,
                            contentDescription = "Copy content",
                            modifier = Modifier.size(24.dp),
                            tint = MaterialTheme.colorScheme.onSurfaceVariant
                        )
                        Text(
                            text = "Copy",
                            style = MaterialTheme.typography.labelSmall,
                            color = MaterialTheme.colorScheme.onSurfaceVariant
                        )
                    }
                } else if (isPublished && hasShareableUrl) {
                    Column(
                        horizontalAlignment = Alignment.CenterHorizontally,
                        modifier = Modifier.clickable {
                            onShare()
                            snackbarHostState?.let { host ->
                                coroutineScope.launch {
                                    host.showSnackbar("Link copied to clipboard")
                                }
                            }
                        }
                    ) {
                        Icon(
                            Icons.Default.Share,
                            contentDescription = "Share",
                            modifier = Modifier.size(24.dp),
                            tint = MaterialTheme.colorScheme.onSurfaceVariant
                        )
                        Text(
                            text = "Share",
                            style = MaterialTheme.typography.labelSmall,
                            color = MaterialTheme.colorScheme.onSurfaceVariant
                        )
                    }
                }

                // Pin/Unpin action
                Column(
                    horizontalAlignment = Alignment.CenterHorizontally,
                    modifier = Modifier.clickable(onClick = onTogglePin)
                ) {
                    Icon(
                        imageVector = if (post.featured) Icons.Filled.PushPin else Icons.Outlined.PushPin,
                        contentDescription = if (post.featured) "Unpin" else "Pin",
                        modifier = Modifier.size(24.dp),
                        tint = if (post.featured) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onSurfaceVariant
                    )
                    Text(
                        text = if (post.featured) "Unpin" else "Pin",
                        style = MaterialTheme.typography.labelSmall,
                        color = if (post.featured) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onSurfaceVariant
                    )
                }
            }

            // Context menu (long-press) -- only Delete, other actions are in the action bar
            DropdownMenu(
                expanded = showContextMenu,
                onDismissRequest = { showContextMenu = false }
            ) {
                DropdownMenuItem(
                    text = { Text("Delete") },
                    onClick = { showContextMenu = false; onDelete() },
                    leadingIcon = {
                        Icon(Icons.Default.Delete, null, tint = MaterialTheme.colorScheme.error)
                    }
                )
            }
        }

        // Full-width thick divider between posts (outside padded column)
        HorizontalDivider(
            thickness = 1.dp,
            color = MaterialTheme.colorScheme.outline.copy(alpha = 0.3f)
        )
    }

    // Gallery viewer
    if (showGallery && allImages.isNotEmpty()) {
        FullScreenGallery(
            images = allImages,
            startIndex = galleryStartIndex,
            onDismiss = { showGallery = false }
        )
    }
}

/**
 * Social media-style image grid layout:
 * - 1 image: full width
 * - 2 images: side by side
 * - 3 images: one large + two small stacked
 * - 4+ images: 2x2 grid (with +N overlay on last if more than 4)
 */
@Composable
fun PostImageGrid(
    images: List<String>,
    onImageClick: (Int) -> Unit
) {
    val shape = MaterialTheme.shapes.medium

    when (images.size) {
        1 -> {
            // Full width single image
            AsyncImage(
                model = images[0],
                contentDescription = "Post image",
                modifier = Modifier
                    .fillMaxWidth()
                    .height(180.dp)
                    .clip(shape)
                    .clickable { onImageClick(0) },
                contentScale = ContentScale.Crop
            )
        }
        2 -> {
            // Side by side
            Row(
                modifier = Modifier.fillMaxWidth(),
                horizontalArrangement = Arrangement.spacedBy(4.dp)
            ) {
                AsyncImage(
                    model = images[0],
                    contentDescription = "Post image 1",
                    modifier = Modifier
                        .weight(1f)
                        .height(180.dp)
                        .clip(shape)
                        .clickable { onImageClick(0) },
                    contentScale = ContentScale.Crop
                )
                AsyncImage(
                    model = images[1],
                    contentDescription = "Post image 2",
                    modifier = Modifier
                        .weight(1f)
                        .height(180.dp)
                        .clip(shape)
                        .clickable { onImageClick(1) },
                    contentScale = ContentScale.Crop
                )
            }
        }
        3 -> {
            // One large + two small stacked
            Row(
                modifier = Modifier
                    .fillMaxWidth()
                    .height(200.dp),
                horizontalArrangement = Arrangement.spacedBy(4.dp)
            ) {
                AsyncImage(
                    model = images[0],
                    contentDescription = "Post image 1",
                    modifier = Modifier
                        .weight(1f)
                        .fillMaxHeight()
                        .clip(shape)
                        .clickable { onImageClick(0) },
                    contentScale = ContentScale.Crop
                )
                Column(
                    modifier = Modifier
                        .weight(1f)
                        .fillMaxHeight(),
                    verticalArrangement = Arrangement.spacedBy(4.dp)
                ) {
                    AsyncImage(
                        model = images[1],
                        contentDescription = "Post image 2",
                        modifier = Modifier
                            .weight(1f)
                            .fillMaxWidth()
                            .clip(shape)
                            .clickable { onImageClick(1) },
                        contentScale = ContentScale.Crop
                    )
                    AsyncImage(
                        model = images[2],
                        contentDescription = "Post image 3",
                        modifier = Modifier
                            .weight(1f)
                            .fillMaxWidth()
                            .clip(shape)
                            .clickable { onImageClick(2) },
                        contentScale = ContentScale.Crop
                    )
                }
            }
        }
        else -> {
            // 2x2 grid with +N overlay on last cell
            val remaining = images.size - 4
            Column(
                modifier = Modifier.fillMaxWidth(),
                verticalArrangement = Arrangement.spacedBy(4.dp)
            ) {
                Row(
                    modifier = Modifier.fillMaxWidth(),
                    horizontalArrangement = Arrangement.spacedBy(4.dp)
                ) {
                    AsyncImage(
                        model = images[0],
                        contentDescription = "Post image 1",
                        modifier = Modifier
                            .weight(1f)
                            .height(120.dp)
                            .clip(shape)
                            .clickable { onImageClick(0) },
                        contentScale = ContentScale.Crop
                    )
                    AsyncImage(
                        model = images[1],
                        contentDescription = "Post image 2",
                        modifier = Modifier
                            .weight(1f)
                            .height(120.dp)
                            .clip(shape)
                            .clickable { onImageClick(1) },
                        contentScale = ContentScale.Crop
                    )
                }
                Row(
                    modifier = Modifier.fillMaxWidth(),
                    horizontalArrangement = Arrangement.spacedBy(4.dp)
                ) {
                    AsyncImage(
                        model = images[2],
                        contentDescription = "Post image 3",
                        modifier = Modifier
                            .weight(1f)
                            .height(120.dp)
                            .clip(shape)
                            .clickable { onImageClick(2) },
                        contentScale = ContentScale.Crop
                    )
                    Box(
                        modifier = Modifier
                            .weight(1f)
                            .height(120.dp)
                            .clip(shape)
                            .clickable { onImageClick(3) }
                    ) {
                        AsyncImage(
                            model = images[3],
                            contentDescription = "Post image 4",
                            modifier = Modifier.fillMaxSize(),
                            contentScale = ContentScale.Crop
                        )
                        if (remaining > 0) {
                            Box(
                                modifier = Modifier
                                    .fillMaxSize()
                                    .background(Color.Black.copy(alpha = 0.5f)),
                                contentAlignment = Alignment.Center
                            ) {
                                Text(
                                    text = "+$remaining",
                                    style = MaterialTheme.typography.headlineSmall,
                                    color = Color.White
                                )
                            }
                        }
                    }
                }
            }
        }
    }
}

/**
 * Full-screen gallery viewer with paging and pinch-to-zoom.
 */
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun FullScreenGallery(
    images: List<String>,
    startIndex: Int,
    onDismiss: () -> Unit
) {
    Dialog(
        onDismissRequest = onDismiss,
        properties = DialogProperties(
            usePlatformDefaultWidth = false,
            decorFitsSystemWindows = false
        )
    ) {
        Box(
            modifier = Modifier
                .fillMaxSize()
                .background(Color.Black)
        ) {
            val pagerState = rememberPagerState(
                initialPage = startIndex,
                pageCount = { images.size }
            )

            HorizontalPager(
                state = pagerState,
                modifier = Modifier.fillMaxSize()
            ) { page ->
                ZoomableImage(
                    model = images[page],
                    contentDescription = "Image ${page + 1} of ${images.size}"
                )
            }

            // Close button
            IconButton(
                onClick = onDismiss,
                modifier = Modifier
                    .align(Alignment.TopEnd)
                    .padding(16.dp),
                colors = IconButtonDefaults.iconButtonColors(
                    containerColor = Color.Black.copy(alpha = 0.5f),
                    contentColor = Color.White
                )
            ) {
                Icon(Icons.Default.Close, contentDescription = "Close gallery")
            }

            // Page indicator
            if (images.size > 1) {
                Text(
                    text = "${pagerState.currentPage + 1} / ${images.size}",
                    style = MaterialTheme.typography.labelLarge,
                    color = Color.White,
                    modifier = Modifier
                        .align(Alignment.BottomCenter)
                        .padding(16.dp)
                        .background(
                            Color.Black.copy(alpha = 0.5f),
                            MaterialTheme.shapes.small
                        )
                        .padding(horizontal = 12.dp, vertical = 4.dp)
                )
            }
        }
    }
}

/**
 * Image with pinch-to-zoom support.
 */
@Composable
fun ZoomableImage(
    model: Any?,
    contentDescription: String?
) {
    var scale by remember { mutableFloatStateOf(1f) }
    var offsetX by remember { mutableFloatStateOf(0f) }
    var offsetY by remember { mutableFloatStateOf(0f) }

    Box(
        modifier = Modifier
            .fillMaxSize()
            .pointerInput(Unit) {
                detectTransformGestures { _, pan, zoom, _ ->
                    scale = (scale * zoom).coerceIn(1f, 5f)
                    if (scale > 1f) {
                        offsetX += pan.x
                        offsetY += pan.y
                    } else {
                        offsetX = 0f
                        offsetY = 0f
                    }
                }
            },
        contentAlignment = Alignment.Center
    ) {
        AsyncImage(
            model = model,
            contentDescription = contentDescription,
            modifier = Modifier
                .fillMaxSize()
                .graphicsLayer(
                    scaleX = scale,
                    scaleY = scale,
                    translationX = offsetX,
                    translationY = offsetY
                ),
            contentScale = ContentScale.Fit
        )
    }
}

// Keep the old PostCard signature for backward compatibility (used in tests/other screens)
@Composable
fun PostCard(
    post: FeedPost,
    onClick: () -> Unit,
    onCancelQueue: () -> Unit,
    highlightQuery: String? = null
) {
    PostCardContent(
        post = post,
        onClick = onClick,
        onCancelQueue = onCancelQueue,
        onEdit = {},
        onDelete = {},
        highlightQuery = highlightQuery
    )
}

/**
 * Displays text with matching substrings highlighted in bold.
 * Case-insensitive matching.
 */
@Composable
fun HighlightedText(
    text: String,
    query: String,
    maxLines: Int = Int.MAX_VALUE
) {
    val annotatedString = buildHighlightedString(text, query)
    Text(
        text = annotatedString,
        style = MaterialTheme.typography.bodyMedium,
        maxLines = maxLines,
        overflow = TextOverflow.Ellipsis
    )
}

/**
 * Builds an AnnotatedString with all case-insensitive occurrences of [query] in [text]
 * highlighted with bold + primary color styling.
 */
fun buildHighlightedString(
    text: String,
    query: String
) = buildAnnotatedString {
    if (query.isBlank()) {
        append(text)
        return@buildAnnotatedString
    }

    val textLower = text.lowercase()
    val queryLower = query.lowercase()
    var currentIndex = 0

    while (currentIndex < text.length) {
        val matchIndex = textLower.indexOf(queryLower, currentIndex)
        if (matchIndex == -1) {
            append(text.substring(currentIndex))
            break
        }

        // Add text before match
        if (matchIndex > currentIndex) {
            append(text.substring(currentIndex, matchIndex))
        }

        // Add highlighted match
        withStyle(SpanStyle(fontWeight = FontWeight.Bold)) {
            append(text.substring(matchIndex, matchIndex + query.length))
        }

        currentIndex = matchIndex + query.length
    }
}

@Composable
fun StatusBadge(post: FeedPost) {
    val isSent = post.status == "sent" || post.emailOnly
    val (label, containerColor, labelColor) = when {
        post.queueStatus != QueueStatus.NONE -> Triple("Pending", Color(0xFFFFF3E0), Color(0xFFE65100))
        isSent -> Triple("Sent", Color(0xFFF3E5F5), Color(0xFF6A1B9A))
        post.status == "published" -> Triple("Published", Color(0xFFE8F5E9), Color(0xFF2E7D32))
        post.status == "scheduled" -> Triple("Scheduled", Color(0xFFE3F2FD), Color(0xFF1565C0))
        else -> Triple("Draft", Color(0xFFF3E5F5), Color(0xFF7B1FA2))
    }

    SuggestionChip(
        onClick = {},
        label = {
            Text(label, style = MaterialTheme.typography.labelSmall.copy(fontWeight = FontWeight.Bold))
        },
        colors = SuggestionChipDefaults.suggestionChipColors(
            containerColor = containerColor,
            labelColor = labelColor
        ),
        border = null
    )
}


/**
 * Card displaying a file attachment in Feed/Detail screens.
 * Tapping opens the file URL in an external viewer.
 */
@Composable
fun FileAttachmentCard(
    fileUrl: String,
    fileName: String
) {
    val context = LocalContext.current
    val iconTint = com.swoosh.microblog.ui.components.fileTypeColor(fileName = fileName)

    OutlinedCard(
        onClick = {
            try {
                val intent = Intent(Intent.ACTION_VIEW, android.net.Uri.parse(fileUrl))
                context.startActivity(intent)
            } catch (_: Exception) {
                // No handler available for this file type
            }
        },
        modifier = Modifier.fillMaxWidth()
    ) {
        Row(
            modifier = Modifier
                .fillMaxWidth()
                .padding(12.dp),
            verticalAlignment = Alignment.CenterVertically
        ) {
            Icon(
                Icons.Default.InsertDriveFile,
                contentDescription = "File attachment",
                modifier = Modifier.size(28.dp),
                tint = iconTint
            )
            Spacer(modifier = Modifier.width(12.dp))
            Column(modifier = Modifier.weight(1f)) {
                Text(
                    text = fileName,
                    style = MaterialTheme.typography.bodyMedium,
                    maxLines = 1,
                    overflow = TextOverflow.Ellipsis
                )
                Text(
                    text = "Tap to download",
                    style = MaterialTheme.typography.labelSmall,
                    color = MaterialTheme.colorScheme.onSurfaceVariant
                )
            }
        }
    }
}
