package top.yeij.cyrene.ui.overlay

import android.content.res.Configuration

import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.fadeIn
import androidx.compose.animation.slideInVertically
import androidx.compose.animation.slideOutVertically
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.gestures.detectDragGesturesAfterLongPress
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.OpenInNew
import androidx.compose.material.icons.automirrored.filled.Send
import androidx.compose.material.icons.filled.Close
import androidx.compose.material.icons.filled.KeyboardVoice
import androidx.compose.material.icons.filled.Lock
import androidx.compose.material.icons.filled.Mic
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable

import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue

import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity

import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.delay
import org.koin.compose.koinInject
import top.yeij.cyrene.domain.model.Message
import top.yeij.cyrene.ui.components.ChatBubble
import top.yeij.cyrene.ui.components.TypingIndicator
import top.yeij.cyrene.util.RecordState
import top.yeij.cyrene.viewmodel.OverlayState
import top.yeij.cyrene.viewmodel.OverlayViewModel
import top.yeij.cyrene.viewmodel.SettingsViewModel
import kotlin.math.min

@Composable
private fun AnimatedChatBubble(
    message: Message,
    animIndex: Int,
) {
    var visible by remember { mutableStateOf(false) }
    LaunchedEffect(Unit) {
        delay(min(animIndex, 10) * 60L)
        visible = true
    }
    AnimatedVisibility(
        visible = visible,
        enter = fadeIn(animationSpec = androidx.compose.animation.core.tween(300)) +
            slideInVertically(
                animationSpec = androidx.compose.animation.core.tween(300),
                initialOffsetY = { it / 4 },
            ),
    ) {
        ChatBubble(
            content = message.content,
            role = message.role,
            msgType = message.msgType,
            timestamp = message.timestamp,
            imageDataUris = message.imageDataUris,
        )
    }
}

@Composable
fun OverlayContent(
    onDismiss: () -> Unit,
    onNavigateToMain: () -> Unit,
    viewModel: OverlayViewModel = koinInject(),
    settingsViewModel: SettingsViewModel = koinInject(),
) {
    val state by viewModel.state.collectAsState()
    val messages by viewModel.messages.collectAsState()
    val inputText by viewModel.inputText.collectAsState()
    val recordState by viewModel.voiceRecordState.collectAsState()
    val recordDurationMs by viewModel.voiceRecordDurationMs.collectAsState()
    val animIndex by viewModel.messageAnimIndex.collectAsState()
    val typingIndicatorStyle by settingsViewModel.typingIndicatorStyle.collectAsState()
    val enterToSend by settingsViewModel.enterToSend.collectAsState()
    val listState = rememberLazyListState()
    val isProcessing = state == OverlayState.PROCESSING
    val recordSec = recordDurationMs / 1000f
    val isRecording = recordState == RecordState.RECORDING
    val isLocked = recordState == RecordState.LOCKED

    // Animated "昔涟正在输入..." dots
    val typingDots = remember { mutableStateOf("") }
    LaunchedEffect(isProcessing) {
        if (isProcessing) {
            val dots = arrayOf("", ".", "..", "...")
            var i = 0
            while (true) {
                typingDots.value = dots[i % 4]
                i++
                delay(400)
            }
        } else {
            typingDots.value = ""
        }
    }

    val configuration = LocalConfiguration.current
    val isLandscape = configuration.orientation == Configuration.ORIENTATION_LANDSCAPE

    // Manual status bar height — Compose WindowInsets may not work in VoiceInteractionSession
    val context = androidx.compose.ui.platform.LocalContext.current
    val statusBarHeight = remember {
        val resourceId = context.resources.getIdentifier("status_bar_height", "dimen", "android")
        if (resourceId > 0) context.resources.getDimensionPixelSize(resourceId) else 0
    }
    val statusBarPaddingDp = with(androidx.compose.ui.platform.LocalDensity.current) {
        statusBarHeight.toDp()
    }

    // Manual nav bar height
    val navBarHeight = remember {
        val resourceId = context.resources.getIdentifier("navigation_bar_height", "dimen", "android")
        if (resourceId > 0) context.resources.getDimensionPixelSize(resourceId) else 0
    }
    val navBarPaddingDp = with(androidx.compose.ui.platform.LocalDensity.current) {
        navBarHeight.toDp()
    }

    LaunchedEffect(messages.size) {
        if (messages.isNotEmpty()) {
            listState.animateScrollToItem(messages.size - 1)
        }
    }

    LaunchedEffect(state) {
        if (state == OverlayState.IDLE) {
            viewModel.finish()
            onDismiss()
        }
    }

    AnimatedVisibility(
        visible = state != OverlayState.IDLE,
        enter = fadeIn() + slideInVertically { it },
        exit = fadeOut() + slideOutVertically { it },
    ) {
        Box(
            modifier = Modifier
                .fillMaxSize()
                .padding(top = statusBarPaddingDp, bottom = navBarPaddingDp),
        ) {
            if (isLandscape) {
                LandscapeContent(
                    state = state,
                    messages = messages,
                    inputText = inputText,
                    isProcessing = isProcessing,
                    listState = listState,
                    recordSec = recordSec,
                    isRecording = isRecording,
                    isLocked = isLocked,
                    typingDots = typingDots.value,
                    typingIndicatorStyle = typingIndicatorStyle,
                    enterToSend = enterToSend,
                    animIndex = animIndex,
                    onDismiss = onDismiss,
                    onNavigateToMain = onNavigateToMain,
                    viewModel = viewModel,
                    navBarHeightPx = navBarHeight,
                )
            } else {
                PortraitContent(
                    state = state,
                    messages = messages,
                    inputText = inputText,
                    isProcessing = isProcessing,
                    listState = listState,
                    recordSec = recordSec,
                    isRecording = isRecording,
                    isLocked = isLocked,
                    typingDots = typingDots.value,
                    typingIndicatorStyle = typingIndicatorStyle,
                    enterToSend = enterToSend,
                    animIndex = animIndex,
                    onDismiss = onDismiss,
                    onNavigateToMain = onNavigateToMain,
                    viewModel = viewModel,
                    navBarHeightPx = navBarHeight,
                )
            }
        }
    }
}

@Suppress("LongParameterList")
@Composable
private fun PortraitContent(
    state: OverlayState,
    messages: List<Message>,
    inputText: String,
    isProcessing: Boolean,
    listState: androidx.compose.foundation.lazy.LazyListState,
    recordSec: Float,
    isRecording: Boolean,
    isLocked: Boolean,
    typingDots: String,
    typingIndicatorStyle: String,
    enterToSend: Boolean,
    animIndex: Map<String, Int>,
    onDismiss: () -> Unit,
    onNavigateToMain: () -> Unit,
    viewModel: OverlayViewModel,
    navBarHeightPx: Int,
) {
    Box(
        modifier = Modifier
            .fillMaxSize()
            .clickable(
                indication = null,
                interactionSource = remember { MutableInteractionSource() },
            ) { /* consume clicks */ },
    ) {
        // Messages + top bar stay fixed at top
        Column(modifier = Modifier.fillMaxSize()) {
            MessageTopBar(onDismiss = onDismiss, onNavigateToMain = onNavigateToMain)

            LazyColumn(
                modifier = Modifier
                    .fillMaxWidth()
                    .weight(1f),
                state = listState,
            ) {
                if (messages.isNotEmpty()) {
                    items(messages, key = { it.id }) { message ->
                        AnimatedChatBubble(
                            message = message,
                            animIndex = animIndex[message.id] ?: 0,
                        )
                    }
                }
                if (isProcessing && typingIndicatorStyle != "text") {
                    item(key = "typing_indicator") {
                        TypingIndicator()
                    }
                }
            }
        }

        // Input area at bottom; system adjust=pan handles IME offset
        InputArea(
            state = state,
            inputText = inputText,
            viewModel = viewModel,
            modifier = Modifier
                .align(Alignment.BottomCenter)
                .fillMaxWidth(),
            recordSec = recordSec,
            isRecording = isRecording,
            isLocked = isLocked,
            typingDots = typingDots,
            typingIndicatorStyle = typingIndicatorStyle,
            enterToSend = enterToSend,
        )
    }
}

@Suppress("LongParameterList")
@Composable
private fun LandscapeContent(
    state: OverlayState,
    messages: List<Message>,
    inputText: String,
    isProcessing: Boolean,
    listState: androidx.compose.foundation.lazy.LazyListState,
    recordSec: Float,
    isRecording: Boolean,
    isLocked: Boolean,
    typingDots: String,
    typingIndicatorStyle: String,
    enterToSend: Boolean,
    animIndex: Map<String, Int>,
    onDismiss: () -> Unit,
    onNavigateToMain: () -> Unit,
    viewModel: OverlayViewModel,
    navBarHeightPx: Int,
) {
    Row(
        modifier = Modifier
            .fillMaxSize()
            .clickable(
                indication = null,
                interactionSource = remember { MutableInteractionSource() },
            ) { /* consume clicks */ },
    ) {
        // Messages + top bar on the left, stay fixed
        Column(modifier = Modifier.weight(1f)) {
            MessageTopBar(onDismiss = onDismiss, onNavigateToMain = onNavigateToMain)
            LazyColumn(
                modifier = Modifier
                    .fillMaxWidth()
                    .weight(1f),
                state = listState,
            ) {
                if (messages.isNotEmpty()) {
                    items(messages, key = { it.id }) { message ->
                        AnimatedChatBubble(
                            message = message,
                            animIndex = animIndex[message.id] ?: 0,
                        )
                    }
                }
                if (isProcessing && typingIndicatorStyle != "text") {
                    item(key = "typing_indicator") {
                        TypingIndicator()
                    }
                }
            }
        }

        Box(
            modifier = Modifier
                .width(1.dp)
                .fillMaxHeight()
                .background(MaterialTheme.colorScheme.outlineVariant.copy(alpha = 0.3f))
        )

        Box(
            modifier = Modifier
                .weight(1f)
                .fillMaxHeight(),
            contentAlignment = Alignment.BottomCenter,
        ) {
            InputArea(
                state = state,
                inputText = inputText,
                viewModel = viewModel,
                modifier = Modifier
                    .fillMaxWidth(),
                recordSec = recordSec,
                isRecording = isRecording,
                isLocked = isLocked,
                typingDots = typingDots,
                typingIndicatorStyle = typingIndicatorStyle,
                enterToSend = enterToSend,
            )
        }
    }
}

@Composable
private fun MessageTopBar(
    onDismiss: () -> Unit,
    onNavigateToMain: () -> Unit,
) {
    Row(
        modifier = Modifier
            .fillMaxWidth()
            .background(MaterialTheme.colorScheme.surface.copy(alpha = 0.3f))
            .padding(horizontal = 8.dp, vertical = 4.dp),
        verticalAlignment = Alignment.CenterVertically,
    ) {
        IconButton(onClick = onDismiss) {
            Icon(Icons.Filled.Close, contentDescription = "关闭")
        }
        Spacer(modifier = Modifier.weight(1f))
        IconButton(onClick = onNavigateToMain) {
            Icon(
                Icons.AutoMirrored.Filled.OpenInNew,
                contentDescription = "进入主界面",
                tint = MaterialTheme.colorScheme.primary,
            )
        }
    }
}

@Composable
private fun InputArea(
    state: OverlayState,
    inputText: String,
    viewModel: OverlayViewModel,
    modifier: Modifier = Modifier,
    recordSec: Float = 0f,
    isRecording: Boolean = false,
    isLocked: Boolean = false,
    typingDots: String = "",
    typingIndicatorStyle: String = "bubble",
    enterToSend: Boolean = false,
) {
    // Gesture tracking state — local to InputArea
    var isDragging by remember { mutableStateOf(false) }
    var dragOffsetX by remember { mutableStateOf(0f) }
    var dragOffsetY by remember { mutableStateOf(0f) }
    val inCancelZone = isDragging && dragOffsetY < -120f
    val inLockZone = isDragging && dragOffsetX > 60f
    val isProcessing = state == OverlayState.PROCESSING

    Column(
        modifier = modifier
            .fillMaxWidth()
            .padding(horizontal = 12.dp, vertical = 8.dp),
    ) {
            // "昔涟正在输入..." indicator (text mode only)
            if (isProcessing && typingDots.isNotEmpty() && typingIndicatorStyle == "text") {
                Text(
                    text = "昔涟正在输入$typingDots",
                    style = MaterialTheme.typography.labelSmall,
                    color = MaterialTheme.colorScheme.primary,
                    modifier = Modifier
                        .fillMaxWidth()
                        .padding(bottom = 4.dp),
                    textAlign = TextAlign.Start,
                )
            }

            Row(
                modifier = Modifier.fillMaxWidth(),
                verticalAlignment = Alignment.CenterVertically,
            ) {
                if (isRecording && isDragging) {
                    // Recording with drag — show recording indicator
                    Box(
                        modifier = Modifier
                            .weight(1f)
                            .clip(RoundedCornerShape(12.dp))
                            .background(
                                if (inCancelZone) MaterialTheme.colorScheme.errorContainer
                                else MaterialTheme.colorScheme.surfaceVariant
                            )
                            .padding(horizontal = 16.dp, vertical = 14.dp),
                        contentAlignment = Alignment.Center,
                    ) {
                        Text(
                            text = when {
                                inCancelZone -> "松手取消"
                                inLockZone -> "松手录音"
                                else -> "%.1f\" 上滑取消 右滑松手".format(recordSec)
                            },
                            style = MaterialTheme.typography.bodyMedium,
                            color = if (inCancelZone) MaterialTheme.colorScheme.error
                                    else MaterialTheme.colorScheme.onSurfaceVariant,
                        )
                    }
                    Box(
                        modifier = Modifier
                            .padding(start = 8.dp)
                            .size(48.dp)
                            .clip(CircleShape)
                            .background(MaterialTheme.colorScheme.primary)
                            .offset { IntOffset(dragOffsetX.toInt(), dragOffsetY.toInt()) },
                        contentAlignment = Alignment.Center,
                    ) {
                        Icon(
                            Icons.Filled.Mic,
                            contentDescription = "录音中",
                            tint = MaterialTheme.colorScheme.onPrimary,
                        )
                    }
                } else if (isLocked) {
                    // Locked (hands-free) mode
                    Box(
                        modifier = Modifier
                            .weight(1f)
                            .clip(RoundedCornerShape(12.dp))
                            .background(MaterialTheme.colorScheme.primaryContainer)
                            .padding(horizontal = 16.dp, vertical = 14.dp),
                        contentAlignment = Alignment.Center,
                    ) {
                        Row(verticalAlignment = Alignment.CenterVertically) {
                            Icon(
                                Icons.Filled.Lock,
                                contentDescription = null,
                                modifier = Modifier.size(16.dp),
                                tint = MaterialTheme.colorScheme.onPrimaryContainer,
                            )
                            Spacer(modifier = Modifier.width(8.dp))
                            Text(
                                text = "%.1f\" 松手录音中 — 点击结束".format(recordSec),
                                style = MaterialTheme.typography.bodyMedium,
                                color = MaterialTheme.colorScheme.onPrimaryContainer,
                            )
                        }
                    }
                    IconButton(onClick = { viewModel.finishRecord() }) {
                        Icon(
                            Icons.AutoMirrored.Filled.Send,
                            contentDescription = "发送",
                            tint = MaterialTheme.colorScheme.primary,
                        )
                    }
                } else {
                    // Normal input mode
                    OutlinedTextField(
                        value = inputText,
                        onValueChange = { viewModel.onInputChanged(it) },
                        placeholder = { Text("输入消息...") },
                        modifier = Modifier.weight(1f),
                        maxLines = 3,
                        shape = RoundedCornerShape(24.dp),
                        colors = androidx.compose.material3.OutlinedTextFieldDefaults.colors(
                            unfocusedContainerColor = MaterialTheme.colorScheme.surface.copy(alpha = 0.35f),
                            focusedContainerColor = MaterialTheme.colorScheme.surface.copy(alpha = 0.55f),
                        ),
                        keyboardOptions = if (enterToSend) {
                            KeyboardOptions(imeAction = ImeAction.Done)
                        } else {
                            KeyboardOptions.Default
                        },
                        keyboardActions = if (enterToSend) {
                            KeyboardActions(
                                onDone = { if (inputText.isNotBlank()) viewModel.sendText() },
                            )
                        } else {
                            KeyboardActions.Default
                        },
                    )

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

                    if (inputText.isNotBlank()) {
                        IconButton(
                            onClick = { viewModel.sendText() },
                            enabled = !isProcessing,
                        ) {
                            Icon(
                                Icons.AutoMirrored.Filled.Send,
                                contentDescription = "发送",
                                tint = MaterialTheme.colorScheme.primary,
                            )
                        }
                    } else {
                        Box(
                            modifier = Modifier
                                .size(48.dp)
                                .pointerInput(Unit) {
                                    detectDragGesturesAfterLongPress(
                                        onDragStart = { _ ->
                                            isDragging = true
                                            dragOffsetX = 0f
                                            dragOffsetY = 0f
                                            viewModel.startRecord()
                                        },
                                        onDrag = { change, dragAmount ->
                                            change.consume()
                                            dragOffsetX += dragAmount.x
                                            dragOffsetY += dragAmount.y
                                        },
                                        onDragEnd = {
                                            isDragging = false
                                            when {
                                                dragOffsetY < -120f -> viewModel.cancelRecord()
                                                dragOffsetX > 60f -> viewModel.lockRecord()
                                                else -> viewModel.finishRecord()
                                            }
                                            dragOffsetX = 0f
                                            dragOffsetY = 0f
                                        },
                                        onDragCancel = {
                                            isDragging = false
                                            viewModel.cancelRecord()
                                            dragOffsetX = 0f
                                            dragOffsetY = 0f
                                        },
                                    )
                                },
                            contentAlignment = Alignment.Center,
                        ) {
                            Icon(
                                Icons.Filled.KeyboardVoice,
                                contentDescription = "按住录音",
                                tint = MaterialTheme.colorScheme.onSurfaceVariant,
                            )
                        }
                    }
                }
            }

            // Status hint
            val hint = when {
                isLocked -> ""
                isRecording && isDragging -> ""
                else -> when (state) {
                    OverlayState.LISTENING -> "我在听..."
                    OverlayState.PROCESSING -> "思考中..."
                    OverlayState.SPEAKING -> "正在说话..."
                    OverlayState.WAITING -> "长按麦克风开始说话"
                    OverlayState.IDLE -> ""
                }
            }
            if (hint.isNotEmpty()) {
                Text(
                    text = hint,
                    style = MaterialTheme.typography.labelMedium,
                    modifier = Modifier
                        .fillMaxWidth()
                        .padding(top = 4.dp),
                    textAlign = TextAlign.Center,
                    color = MaterialTheme.colorScheme.onSurfaceVariant,
                )
            }
    }
}
