@file:Suppress("HardCodedStringLiteral", "AssignedValueIsNeverRead", "UnusedMaterial3ScaffoldPaddingParameter")

package eu.gaudian.translator.view.vocabulary

import android.annotation.SuppressLint
import androidx.compose.animation.animateContentSize
import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.FastOutSlowInEasing
import androidx.compose.animation.core.Spring
import androidx.compose.animation.core.VisibilityThreshold
import androidx.compose.animation.core.spring
import androidx.compose.animation.core.tween
import androidx.compose.foundation.gestures.detectDragGestures
import androidx.compose.foundation.gestures.scrollBy
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp
import androidx.compose.ui.zIndex
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import androidx.navigation.NavController
import androidx.navigation.compose.rememberNavController
import eu.gaudian.translator.R
import eu.gaudian.translator.model.VocabularyStage
import eu.gaudian.translator.model.WidgetType
import eu.gaudian.translator.utils.findActivity
import eu.gaudian.translator.view.composable.AppCard
import eu.gaudian.translator.view.composable.AppIcons
import eu.gaudian.translator.view.composable.AppOutlinedCard
import eu.gaudian.translator.view.dialogs.MissingLanguageDialog
import eu.gaudian.translator.view.vocabulary.widgets.AllVocabularyWidget
import eu.gaudian.translator.view.vocabulary.widgets.CategoryProgressWidget
import eu.gaudian.translator.view.vocabulary.widgets.DueTodayWidget
import eu.gaudian.translator.view.vocabulary.widgets.LevelWidget
import eu.gaudian.translator.view.vocabulary.widgets.StatusWidget
import eu.gaudian.translator.view.vocabulary.widgets.StreakWidget
import eu.gaudian.translator.view.vocabulary.widgets.WeeklyActivityChartWidget
import eu.gaudian.translator.viewmodel.LanguageViewModel
import eu.gaudian.translator.viewmodel.ProgressViewModel
import eu.gaudian.translator.viewmodel.SettingsViewModel
import eu.gaudian.translator.viewmodel.VocabularyViewModel
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.launch

@SuppressLint("FrequentlyChangingValue")
@Composable
fun DashboardContent(
    navController: NavController,
    onShowCustomExerciseDialog: () -> Unit,
    startDailyExercise: (Boolean) -> Unit,
    onNavigateToCategoryDetail: (Int) -> Unit,
    onNavigateToCategoryList: () -> Unit,
    onShowWordPairExerciseDialog: () -> Unit,
    onScroll: (Boolean) -> Unit = {},
) {
    val activity = LocalContext.current.findActivity()
    val languageViewModel: LanguageViewModel = hiltViewModel(viewModelStoreOwner = activity)
    val settingsViewModel: SettingsViewModel = hiltViewModel(viewModelStoreOwner = activity)
    val progressViewModel: ProgressViewModel = hiltViewModel(viewModelStoreOwner = activity)

    var showMissingLanguageDialog by remember { mutableStateOf(false) }
    var selectedMissingLanguageId by remember { mutableStateOf<Int?>(null) }
    val vocabularyViewModel: VocabularyViewModel = hiltViewModel(viewModelStoreOwner = activity)

    val affectedItems by remember(selectedMissingLanguageId) {
        selectedMissingLanguageId?.let {
            vocabularyViewModel.getItemsForLanguage(it)
        } ?: flowOf(emptyList())
    }.collectAsState(initial = emptyList())

    if (showMissingLanguageDialog && selectedMissingLanguageId != null) {
        MissingLanguageDialog(
            showDialog = true,
            missingLanguageId = selectedMissingLanguageId!!,
            affectedItems = affectedItems,
            onDismiss = { showMissingLanguageDialog = false },
            onDelete = { items ->
                vocabularyViewModel.deleteVocabularyItemsById(items.map { it.id })
                showMissingLanguageDialog = false
            },
            onReplace = { oldId, newId ->
                vocabularyViewModel.replaceLanguageId(oldId, newId)
                showMissingLanguageDialog = false
            },
            onCreate = { newLanguage ->
                languageViewModel.addCustomLanguage(newLanguage)
            },
            languageViewModel = languageViewModel
        )
    }

    AppOutlinedCard {
        // We collect the order from DB initially
        val initialWidgetOrder by settingsViewModel.widgetOrder.collectAsState(initial = null)
        val collapsedWidgetIds by settingsViewModel.collapsedWidgetIds.collectAsState(initial = emptySet())
        val dashboardScrollState by settingsViewModel.dashboardScrollState.collectAsState()
        val scope = rememberCoroutineScope()

        if (initialWidgetOrder == null) {
            Box(
                modifier = Modifier
                    .fillMaxSize()
                    .padding(vertical = 64.dp),
                contentAlignment = Alignment.Center
            ) {
                CircularProgressIndicator()
            }
        } else {
            // BEST PRACTICE: Use a SnapshotStateList for immediate UI updates.
            // We only initialize this once, so DB updates don't reset the list while dragging.
            val orderedWidgets = remember { mutableStateListOf<WidgetType>() }

            // Sync with DB only on first load
            LaunchedEffect(initialWidgetOrder) {
                if (orderedWidgets.isEmpty() && !initialWidgetOrder.isNullOrEmpty()) {
                    orderedWidgets.addAll(initialWidgetOrder!!)
                } else if (orderedWidgets.isEmpty()) {
                    orderedWidgets.addAll(WidgetType.DEFAULT_ORDER)
                }
            }

            val lazyListState = rememberLazyListState(
                initialFirstVisibleItemIndex = dashboardScrollState.first,
                initialFirstVisibleItemScrollOffset = dashboardScrollState.second
            )

            // Save scroll state
            LaunchedEffect(lazyListState.firstVisibleItemIndex, lazyListState.firstVisibleItemScrollOffset) {
                settingsViewModel.saveDashboardScrollState(
                    lazyListState.firstVisibleItemIndex,
                    lazyListState.firstVisibleItemScrollOffset
                )
            }

            // Detect scroll and notify parent
            LaunchedEffect(lazyListState.isScrollInProgress) {
                onScroll(lazyListState.isScrollInProgress)
            }
            DisposableEffect(Unit) {
                onDispose {
                    settingsViewModel.saveDashboardScrollState(
                        lazyListState.firstVisibleItemIndex,
                        lazyListState.firstVisibleItemScrollOffset
                    )
                }
            }

            // --- Robust Drag and Drop State ---
            val dragDropState = rememberDragDropState(
                lazyListState = lazyListState,
                onSwap = { fromIndex, toIndex ->
                    // Swap data immediately for responsiveness
                    orderedWidgets.apply {
                        add(toIndex, removeAt(fromIndex))
                    }
                },
                onDragEnd = {
                    // Persist to DB only when user drops
                    settingsViewModel.saveWidgetOrder(orderedWidgets.toList())
                }
            )

            LazyColumn(
                state = lazyListState,
                modifier = Modifier
                    .fillMaxSize()
                    .dragContainer(dragDropState),
                contentPadding = PaddingValues(bottom = 160.dp)
            ) {
                itemsIndexed(
                    items = orderedWidgets,
                    key = { _, widget -> widget.id }
                ) { index, widgetType ->

                    val isDragging = index == dragDropState.draggingItemIndex

                    // Calculate translation: distinct logic for dragged vs. stationary items
                    val translationY = if (isDragging) {
                        dragDropState.draggingItemOffset
                    } else {
                        0f
                    }

                    Box(
                        modifier = Modifier
                            .zIndex(if (isDragging) 1f else 0f)
                            .graphicsLayer {
                                this.translationY = translationY
                                this.shadowElevation = if (isDragging) 8.dp.toPx() else 0f
                                this.scaleX = if (isDragging) 1.02f else 1f
                                this.scaleY = if (isDragging) 1.02f else 1f
                            }
                            // CRITICAL FIX: Only apply animation to items NOT being dragged.
                            // This prevents the "flicker" by stopping the layout animation
                            // from fighting your manual drag offset.
                            .then(
                                if (!isDragging) {
                                    Modifier.animateItem(
                                        placementSpec = spring(
                                            stiffness = Spring.StiffnessLow,
                                            visibilityThreshold = IntOffset.VisibilityThreshold
                                        )
                                    )
                                } else {
                                    Modifier
                                }
                            )
                    ) {
                        WidgetContainer(
                            widgetType = widgetType,
                            isExpanded = widgetType.id !in collapsedWidgetIds,
                            onExpandedChange = { newExpandedState ->
                                scope.launch {
                                    settingsViewModel.setWidgetExpandedState(widgetType.id, newExpandedState)
                                }
                            },
                            onDragStart = { dragDropState.onDragStart(index) },
                            onDrag = { dragAmount -> dragDropState.onDrag(dragAmount) },
                            onDragEnd = { dragDropState.onDragEnd() },
                            onDragCancel = { dragDropState.onDragInterrupted() },
                            modifier = Modifier.fillMaxWidth()
                        ) {
                            LazyWidget(
                                widgetType = widgetType,
                                navController = navController,
                                vocabularyViewModel = vocabularyViewModel,
                                progressViewModel = progressViewModel,
                                onShowCustomExerciseDialog = onShowCustomExerciseDialog,
                                startDailyExercise = startDailyExercise,
                                onNavigateToCategoryDetail = onNavigateToCategoryDetail,
                                onNavigateToCategoryList = onNavigateToCategoryList,
                                onShowWordPairExerciseDialog = onShowWordPairExerciseDialog,
                                onMissingLanguage = { missingId ->
                                    selectedMissingLanguageId = missingId
                                    showMissingLanguageDialog = true
                                }
                            )
                        }
                    }
                }
            }
        }
    }
}

@Composable
private fun WidgetContainer(
    widgetType: WidgetType,
    isExpanded: Boolean,
    onExpandedChange: (Boolean) -> Unit,
    modifier: Modifier = Modifier,
    onDragStart: () -> Unit,
    onDrag: (Float) -> Unit,
    onDragEnd: () -> Unit,
    onDragCancel: () -> Unit,
    content: @Composable () -> Unit
) {
    AppCard(
        modifier = modifier.padding(horizontal = 8.dp, vertical = 4.dp),
    ) {
        Column(
            modifier = Modifier
                .fillMaxWidth()
                .animateContentSize(animationSpec = tween(300, easing = FastOutSlowInEasing))
        ) {
            Row(
                modifier = Modifier
                    .fillMaxWidth()
                    .padding(start = 12.dp),
                verticalAlignment = Alignment.CenterVertically
            ) {
                Text(
                    text = stringResource(widgetType.titleRes),
                    style = MaterialTheme.typography.titleMedium,
                    modifier = Modifier.weight(1f)
                )

                IconButton(onClick = { onExpandedChange(!isExpanded) }) {
                    Icon(
                        imageVector = if (isExpanded) AppIcons.ArrowDropUp
                        else AppIcons.ArrowDropDown,
                        contentDescription = if (isExpanded) stringResource(R.string.text_collapse_widget)
                        else stringResource(R.string.text_expand_widget)
                    )
                }

                // Drag Handle with specific pointer input
                Icon(
                    imageVector = AppIcons.DragHandle,
                    contentDescription = stringResource(R.string.text_drag_to_reorder),
                    tint = if (isExpanded) MaterialTheme.colorScheme.onSurface.copy(alpha = 0.38f)
                    else MaterialTheme.colorScheme.onSurface,
                    modifier = Modifier
                        .padding(end = 8.dp, start = 8.dp)
                        .pointerInput(Unit) {
                            detectDragGestures(
                                onDragStart = { _ -> onDragStart() },
                                onDrag = { change, dragAmount ->
                                    change.consume()
                                    onDrag(dragAmount.y)
                                },
                                onDragEnd = { onDragEnd() },
                                onDragCancel = { onDragCancel() }
                            )
                        }
                )
            }
            if (isExpanded) {
                content()
            }
        }
    }
}

// --------------------------------------------------------------------------------
// Fixed Drag and Drop Logic
// --------------------------------------------------------------------------------

@Composable
fun rememberDragDropState(
    lazyListState: LazyListState,
    onSwap: (Int, Int) -> Unit,
    onDragEnd: () -> Unit
): DragDropState {
    val scope = rememberCoroutineScope()
    return remember(lazyListState, scope) {
        DragDropState(
            state = lazyListState,
            onSwap = onSwap,
            onDragFinished = onDragEnd,
            scope = scope
        )
    }
}

fun Modifier.dragContainer(dragDropState: DragDropState): Modifier {
    return this.pointerInput(dragDropState) {
        // Just allows the modifier to exist in the chain, logic is in the handle
    }
}

class DragDropState(
    private val state: LazyListState,
    private val onSwap: (Int, Int) -> Unit,
    private val onDragFinished: () -> Unit,
    private val scope: CoroutineScope
) {
    var draggingItemIndex by mutableIntStateOf(-1)
        private set

    private val _draggingItemOffset = Animatable(0f)
    val draggingItemOffset: Float
        get() = _draggingItemOffset.value

    private val scrollChannel = Channel<Float>(Channel.CONFLATED)

    init {
        scope.launch {
            for (scrollAmount in scrollChannel) {
                if (scrollAmount != 0f) {
                    state.scrollBy(scrollAmount)
                    checkSwap()
                }
            }
        }
    }

    fun onDragStart(index: Int) {
        draggingItemIndex = index
        scope.launch { _draggingItemOffset.snapTo(0f) }
    }

    fun onDrag(dragAmount: Float) {
        if (draggingItemIndex == -1) return

        scope.launch {
            _draggingItemOffset.snapTo(_draggingItemOffset.value + dragAmount)
            checkSwap()
            checkOverscroll()
        }
    }

    private fun checkSwap() {
        val draggedIndex = draggingItemIndex
        if (draggedIndex == -1) return

        val visibleItems = state.layoutInfo.visibleItemsInfo
        val draggedItemInfo = visibleItems.find { it.index == draggedIndex } ?: return

        // Calculate the visual center of the dragged item
        val draggedCenter = draggedItemInfo.offset + (draggedItemInfo.size / 2) + _draggingItemOffset.value

        // Find a target to swap with
        // FIX: We strictly check if we have crossed the CENTER of the target item.
        // This acts as a hysteresis buffer to prevent flickering at the edges.
        val targetItem = visibleItems.find { item ->
            item.index != draggedIndex &&
                    draggedCenter > item.offset &&
                    draggedCenter < (item.offset + item.size)
        }

        if (targetItem != null) {
            // Extra Check: Ensure we have actually crossed the midpoint of the target
            val targetCenter = itemCenter(targetItem.offset, targetItem.size)
            val isAboveAndMovingDown = draggedIndex < targetItem.index && draggedCenter > targetCenter
            val isBelowAndMovingUp = draggedIndex > targetItem.index && draggedCenter < targetCenter

            if (isAboveAndMovingDown || isBelowAndMovingUp) {
                val targetIndex = targetItem.index

                // 1. Swap Data
                onSwap(draggedIndex, targetIndex)

                // 2. Adjust Offset
                // We calculate the physical distance the item moved in the layout (e.g. 150px).
                // We subtract this from the current drag offset to keep the item visually stationary under the finger.
                val layoutJumpDistance = (targetItem.offset - draggedItemInfo.offset).toFloat()

                scope.launch {
                    _draggingItemOffset.snapTo(_draggingItemOffset.value - layoutJumpDistance)
                }

                // 3. Update Index
                draggingItemIndex = targetIndex
            }
        }
    }

    private fun itemCenter(offset: Int, size: Int): Float {
        return offset + (size / 2f)
    }

    private fun checkOverscroll() {
        val draggedIndex = draggingItemIndex
        if (draggedIndex == -1) {
            scrollChannel.trySend(0f)
            return
        }

        val layoutInfo = state.layoutInfo
        val visibleItems = layoutInfo.visibleItemsInfo
        val draggedItemInfo = visibleItems.find { it.index == draggedIndex } ?: return

        val viewportStart = layoutInfo.viewportStartOffset
        val viewportEnd = layoutInfo.viewportEndOffset
        // Increased threshold slightly for smoother top-edge scrolling
        val boundsStart = viewportStart + (viewportEnd * 0.15f)
        val boundsEnd = viewportEnd - (viewportEnd * 0.15f)

        val itemTop = draggedItemInfo.offset + _draggingItemOffset.value
        val itemBottom = itemTop + draggedItemInfo.size

        val scrollAmount = when {
            itemTop < boundsStart -> -10f // Slower, more controlled scroll speed
            itemBottom > boundsEnd -> 10f
            else -> 0f
        }

        scrollChannel.trySend(scrollAmount)
    }

    fun onDragEnd() {
        resetDrag()
        onDragFinished()
    }

    fun onDragInterrupted() {
        resetDrag()
    }

    private fun resetDrag() {
        draggingItemIndex = -1
        scrollChannel.trySend(0f)
        scope.launch { _draggingItemOffset.snapTo(0f) }
    }
}

// --------------------------------------------------------------------------------
// Remainder of your existing components
// --------------------------------------------------------------------------------

@Composable
private fun LazyWidget(
    widgetType: WidgetType,
    navController: NavController,
    vocabularyViewModel: VocabularyViewModel,
    progressViewModel: ProgressViewModel,
    onShowCustomExerciseDialog: () -> Unit,
    startDailyExercise: (Boolean) -> Unit,
    onNavigateToCategoryDetail: (Int) -> Unit,
    onNavigateToCategoryList: () -> Unit,
    onShowWordPairExerciseDialog: () -> Unit,
    onMissingLanguage: (Int) -> Unit
) {
    when (widgetType) {


        WidgetType.Status -> LazyStatusWidget(
            vocabularyViewModel = vocabularyViewModel,
            onNavigateToNew = { navController.navigate("vocabulary_sorting?mode=NEW") },
            onNavigateToDuplicates = { navController.navigate("vocabulary_sorting?mode=DUPLICATES") },
            onNavigateToFaulty = { navController.navigate("vocabulary_sorting?mode=FAULTY") },
            onNavigateToNoGrammar = { navController.navigate("no_grammar_items") },
            onNavigateToMissingLanguage = onMissingLanguage
        )

        else -> {
            // Regular widgets that load immediately
            when (widgetType) {
                WidgetType.Streak -> StreakWidget(
                    streak = progressViewModel.streak.collectAsState(initial = 0).value,
                    lastSevenDays = progressViewModel.lastSevenDays.collectAsState().value,
                    dueTodayCount = progressViewModel.dueTodayCount.collectAsState().value,
                    wordsCompleted = progressViewModel.totalWordsCompleted.collectAsState().value,
                    onStatisticsClicked = { navController.navigate("vocabulary_heatmap") }
                )

                WidgetType.WeeklyActivityChart -> WeeklyActivityChartWidget(
                    weeklyStats = progressViewModel.weeklyActivityStats.collectAsState().value
                )

                WidgetType.AllVocabulary -> AllVocabularyWidget(
                    vocabularyViewModel = vocabularyViewModel,
                    onOpenAllVocabulary = { navController.navigate("vocabulary_list/false/null") },
                    onStageClicked = { stage -> navController.navigate("vocabulary_list/false/$stage") }
                )

                WidgetType.DueToday -> DueTodayWidget(
                    vocabularyViewModel = vocabularyViewModel,
                    onStageClicked = { stage -> navController.navigate("vocabulary_list/false/$stage") }
                )

                WidgetType.CategoryProgress -> CategoryProgressWidget(
                    onCategoryClicked = { category ->
                        category?.let { onNavigateToCategoryDetail(it.id) }
                    },
                    onViewAllClicked = onNavigateToCategoryList
                )

                WidgetType.Levels -> LevelWidget(
                    totalWords = vocabularyViewModel.vocabularyItems.collectAsState().value.size,
                    learnedWords = vocabularyViewModel.stageStats.collectAsState().value
                        .firstOrNull { it.stage == VocabularyStage.LEARNED }?.itemCount ?: 0,
                    onNavigateToProgress = { navController.navigate("language_progress") }
                )

            }
        }
    }
}

@Composable
private fun LazyStatusWidget(
    vocabularyViewModel: VocabularyViewModel,
    onNavigateToNew: () -> Unit,
    onNavigateToDuplicates: () -> Unit,
    onNavigateToFaulty: () -> Unit,
    onNavigateToNoGrammar: () -> Unit,
    onNavigateToMissingLanguage: (Int) -> Unit
) {
    var isLoading by remember { mutableStateOf(true) }

    // Collect all flows asynchronously
    val newItemsCount by vocabularyViewModel.newItemsCount.collectAsState()
    val duplicateCount by vocabularyViewModel.duplicateItemsCount.collectAsState()
    val faultyItemsCount by vocabularyViewModel.faultyItemsCount.collectAsState()
    val itemsWithoutGrammarCount by vocabularyViewModel.itemsWithoutGrammarCount.collectAsState()
    val missingLanguageInfo by vocabularyViewModel.missingLanguageInfo.collectAsState()

    LaunchedEffect(
        newItemsCount,
        duplicateCount,
        faultyItemsCount,
        itemsWithoutGrammarCount,
        missingLanguageInfo
    ) {
        delay(100)
        isLoading = false
    }

    if (isLoading) {
        Box(
            modifier = Modifier
                .fillMaxWidth()
                .padding(vertical = 32.dp),
            contentAlignment = Alignment.Center
        ) {
            CircularProgressIndicator(modifier = Modifier.padding(16.dp))
        }
    } else {
        StatusWidget(
            onNavigateToNew = onNavigateToNew,
            onNavigateToDuplicates = onNavigateToDuplicates,
            onNavigateToFaulty = onNavigateToFaulty,
            onNavigateToNoGrammar = onNavigateToNoGrammar,
            onNavigateToMissingLanguage = onNavigateToMissingLanguage
        )
    }
}

@Preview
@Composable
fun DashboardContentPreview() {
    val navController = rememberNavController()
    DashboardContent(
        navController = navController,
        onShowCustomExerciseDialog = {},
        onNavigateToCategoryDetail = {},
        startDailyExercise = {},
        onNavigateToCategoryList = {},
        onShowWordPairExerciseDialog = {},
    )
}

@Preview
@Composable
fun WidgetContainerPreview() {
    WidgetContainer(
        widgetType = WidgetType.Streak,
        isExpanded = true,
        onExpandedChange = {},
        onDragStart = { } ,
        onDrag = { },
        onDragEnd = { },
        onDragCancel = { }
    ) {
        Box(
            modifier = Modifier
                .fillMaxWidth()
                .padding(16.dp),
            contentAlignment = Alignment.Center
        ) {
            Text("Preview Content")
        }
    }
}