package com.jishisongfu.duobibi.ui.alert

import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.background
import androidx.compose.foundation.horizontalScroll
import androidx.compose.foundation.layout.Arrangement
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.Spacer
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Add
import androidx.compose.material.icons.filled.NotificationsActive
import androidx.compose.material.icons.filled.Refresh
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExtendedFloatingActionButton
import androidx.compose.material3.FilterChip
import androidx.compose.material3.FilterChipDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SheetState
import androidx.compose.material3.pulltorefresh.PullToRefreshBox
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.rememberModalBottomSheetState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.jishisongfu.duobibi.data.db.AlertMode
import com.jishisongfu.duobibi.data.db.AlertStatus
import com.jishisongfu.duobibi.data.db.PriceAlert
import com.jishisongfu.duobibi.ui.ALL_PLATFORMS
import com.jishisongfu.duobibi.ui.DbbProgressBar
import com.jishisongfu.duobibi.ui.HeroBanner
import com.jishisongfu.duobibi.ui.PlatformChip
import com.jishisongfu.duobibi.ui.ProductThumb
import com.jishisongfu.duobibi.ui.fmtYuan
import com.jishisongfu.duobibi.ui.rememberHaptics
import com.jishisongfu.duobibi.ui.theme.DbbColors
import com.jishisongfu.duobibi.ui.theme.DbbGradients
import kotlin.math.abs

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun AlertScreen(vm: AlertViewModel = hiltViewModel()) {
    val wants by vm.wants.collectAsStateWithLifecycle()
    val boughts by vm.boughts.collectAsStateWithLifecycle()
    val readyCount by vm.readyCount.collectAsStateWithLifecycle()
    val refreshing by vm.refreshing.collectAsStateWithLifecycle()

    // 旋转 / 进详情再返回时保留 Tab 选择和 Sheet 打开态。
    var tab by rememberSaveable { mutableStateOf(0) }
    var addOpen by rememberSaveable { mutableStateOf(false) }
    val haptics = rememberHaptics()

    Scaffold(
        containerColor = DbbColors.Bg,
        contentWindowInsets = WindowInsets(0),
        floatingActionButton = {
            ExtendedFloatingActionButton(
                onClick = { haptics.confirm(); addOpen = true },
                containerColor = DbbColors.Teal,
                contentColor = Color.White,
            ) {
                Icon(Icons.Filled.Add, null)
                Spacer(Modifier.width(6.dp))
                Text("加监控")
            }
        },
    ) { padding ->
        Column(
            Modifier
                .padding(padding)
                .fillMaxSize()
                .background(DbbColors.Bg),
        ) {
            HeroBanner(
                title = "降价雷达",
                subtitle = if (readyCount > 0) "$readyCount 件已到价,快去看看" else "盯着想买和已买的,降价就提醒你",
                icon = Icons.Filled.NotificationsActive,
                gradient = DbbGradients.Alert,
                trailing = {
                    IconButton(
                        onClick = { haptics.confirm(); vm.refreshAll() },
                        enabled = !refreshing,
                    ) {
                        Icon(Icons.Filled.Refresh, "立即查价", tint = Color.White)
                    }
                },
            )
            TodayActivityRow(allAlerts = wants + boughts)
            Box(Modifier.padding(horizontal = 14.dp, vertical = 10.dp)) {
                StatCard(wants.size + boughts.size, readyCount)
            }
            Row(
                Modifier.fillMaxWidth().padding(horizontal = 14.dp),
                horizontalArrangement = Arrangement.spacedBy(8.dp),
                verticalAlignment = Alignment.CenterVertically,
            ) {
                SegChip("想买的 ${wants.size}", tab == 0) { tab = 0 }
                SegChip("已买的 ${boughts.size}", tab == 1) { tab = 1 }
                Spacer(Modifier.weight(1f))
                Text("按到价优先", color = DbbColors.InkTer, fontSize = 11.sp)
            }
            Spacer(Modifier.height(10.dp))
            val list = if (tab == 0) wants else boughts
            // 用 PullToRefreshBox 包列表区:从列表中部下拉触发 vm.refreshAll(),
            // refreshing 状态由 VM 暴露的 StateFlow 反向驱动指示器(转完才收回),
            // 跟 hero 右上 Refresh 按钮共享同一个底层动作。
            PullToRefreshBox(
                isRefreshing = refreshing,
                onRefresh = vm::refreshAll,
                modifier = Modifier.fillMaxSize(),
            ) {
                if (list.isEmpty()) {
                    EmptyHint(
                        if (tab == 0) "还没有想买的商品。\n加一个并设置心理价,降到就提醒你。"
                        else "还没有已买的商品。\n加一个,买后还降价就提醒你申请价保。",
                    )
                } else {
                    LazyColumn(
                        Modifier.fillMaxSize(),
                        contentPadding = PaddingValues(14.dp, 0.dp, 14.dp, 88.dp),
                        verticalArrangement = Arrangement.spacedBy(10.dp),
                    ) {
                        items(list, key = { it.id }) { a ->
                            AlertCard(
                                a,
                                onStop = { vm.stop(a.id) },
                                onArchive = { vm.archive(a.id) },
                                onReactivate = { vm.reactivate(a.id) },
                                onDelete = { vm.delete(a.id) },
                            )
                        }
                    }
                }
            }
        }
    }

    if (addOpen) {
        AddAlertSheet(
            sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true),
            onDismiss = { addOpen = false },
            onAddWant = { t, p, target -> vm.addWant(t, p, target); addOpen = false },
            onAddBought = { t, p, price -> vm.addBought(t, p, price); addOpen = false },
        )
    }
}

/**
 * Hero 下方"今日动态"横滑条 — 解决 hero 与 StatCard 之间的空荡感。
 *
 * 内容自适应:
 *  - 有已到价(lastSavings > 0)→ 优先展示这些(降价金额最大者在前)
 *  - 没有到价但有最近查过的 → 展示"价格无变动"的最近 3 条
 *  - 完全空(列表是 0)→ 展示 3 张"占位卡":提示用户去加监控
 */
@Composable
private fun TodayActivityRow(allAlerts: List<PriceAlert>) {
    val active = remember(allAlerts) {
        // 排序优先级:已到价 (lastSavings > 0) > 有查过 > 其它,各类内部按 lastCheckedAt 降序
        allAlerts
            .filter { it.lastCurrentPrice != null }
            .sortedWith(
                compareByDescending<PriceAlert> { (it.lastSavings ?: 0.0) > 0.0 }
                    .thenByDescending { it.lastCheckedAt ?: 0L }
            )
            .take(5)
    }
    Row(
        modifier = Modifier
            .fillMaxWidth()
            .horizontalScroll(rememberScrollState())
            .padding(horizontal = 12.dp, vertical = 10.dp),
        horizontalArrangement = Arrangement.spacedBy(8.dp),
    ) {
        if (active.isEmpty()) {
            ActivityPlaceholderCard("📉", "盯个想买的", "降到心理价就推送")
            ActivityPlaceholderCard("💸", "盯个已买的", "降价提示申请价保")
            ActivityPlaceholderCard("⏰", "每日自动查", "不用手动刷")
        } else {
            active.forEach { a -> ActivityCard(a) }
        }
    }
}

@Composable
private fun ActivityCard(a: PriceAlert) {
    val ready = (a.lastSavings ?: 0.0) > 0.0
    val accent = if (ready) DbbColors.Save else DbbColors.InkSec
    val accentBg = if (ready) DbbColors.SaveBg else DbbColors.Fill
    val current = a.lastCurrentPrice ?: 0.0
    // 横向布局:左图 + 右信息列。固定 195×110 dp,跟 ActivityPlaceholderCard 等大,
    // 避免横滑条里有的卡大有的卡小的视觉跳跃。
    // ProductThumb 内部按 title 查 ProductImageMap,命中真图就显图,否则 vector icon 兜底。
    Row(
        Modifier
            .width(195.dp)
            .height(110.dp)
            .clip(RoundedCornerShape(12.dp))
            .background(DbbColors.Card)
            .padding(horizontal = 10.dp, vertical = 10.dp),
        verticalAlignment = Alignment.Top,
    ) {
        ProductThumb(title = a.title, size = 44.dp)
        Spacer(Modifier.width(8.dp))
        Column(Modifier.weight(1f)) {
            Row(verticalAlignment = Alignment.CenterVertically) {
                Box(
                    Modifier
                        .clip(RoundedCornerShape(5.dp))
                        .background(accentBg)
                        .padding(horizontal = 6.dp, vertical = 1.dp),
                ) {
                    Text(
                        if (ready) "已到价" else "监控中",
                        color = accent,
                        fontSize = 9.sp,
                        fontWeight = FontWeight.Bold,
                    )
                }
                Spacer(Modifier.weight(1f))
                val arrow = when (a.lastTrend) { "down" -> "↓"; "up" -> "↑"; else -> "·" }
                Text(arrow, color = accent, fontSize = 11.sp, fontWeight = FontWeight.Bold)
            }
            Spacer(Modifier.height(4.dp))
            Text(
                a.title, color = DbbColors.Ink, fontSize = 11.sp, fontWeight = FontWeight.SemiBold,
                maxLines = 2, lineHeight = 14.sp,
            )
            Spacer(Modifier.height(3.dp))
            Text(
                "¥${fmtYuan(current)}",
                color = accent, fontWeight = FontWeight.ExtraBold, fontSize = 16.sp,
                letterSpacing = (-0.4).sp,
            )
            if (ready) {
                Text("省 ¥${fmtYuan(a.lastSavings ?: 0.0)}", color = DbbColors.Save, fontSize = 10.sp)
            } else {
                Text(a.platform ?: "全网", color = DbbColors.InkTer, fontSize = 10.sp)
            }
        }
    }
}

@Composable
private fun ActivityPlaceholderCard(emoji: String, title: String, subtitle: String) {
    // 跟 ActivityCard 等大(195×110 dp),内容垂直居中,避免横滑条里大小跳变。
    Column(
        Modifier
            .width(195.dp)
            .height(110.dp)
            .clip(RoundedCornerShape(12.dp))
            .background(DbbColors.Card)
            .padding(horizontal = 12.dp, vertical = 10.dp),
        verticalArrangement = Arrangement.Center,
    ) {
        Text(emoji, fontSize = 22.sp)
        Spacer(Modifier.height(4.dp))
        Text(title, color = DbbColors.Ink, fontSize = 13.sp, fontWeight = FontWeight.Bold)
        Text(subtitle, color = DbbColors.InkTer, fontSize = 10.sp)
    }
}

@Composable
private fun StatCard(totalCount: Int, readyCount: Int) {
    Card(
        Modifier.fillMaxWidth(),
        colors = CardDefaults.cardColors(containerColor = DbbColors.TealBg),
        elevation = CardDefaults.cardElevation(defaultElevation = 2.dp),
        shape = RoundedCornerShape(14.dp),
    ) {
        Row(
            Modifier.padding(horizontal = 14.dp, vertical = 12.dp),
            verticalAlignment = Alignment.CenterVertically,
        ) {
            Icon(
                Icons.Filled.NotificationsActive, contentDescription = null,
                tint = DbbColors.TealDark, modifier = Modifier.size(18.dp),
            )
            Spacer(Modifier.width(8.dp))
            Text(
                "监控中 $totalCount 件 · 已到价 $readyCount 件",
                color = DbbColors.TealDark, fontWeight = FontWeight.Bold, fontSize = 13.sp,
            )
            Spacer(Modifier.weight(1f))
            Text("自动定时查价", color = DbbColors.InkSec, fontSize = 11.sp)
        }
    }
}

@Composable
private fun SegChip(label: String, selected: Boolean, onClick: () -> Unit) {
    FilterChip(
        selected = selected, onClick = onClick, label = { Text(label) },
        colors = FilterChipDefaults.filterChipColors(
            selectedContainerColor = DbbColors.Teal, selectedLabelColor = Color.White,
        ),
    )
}

@Composable
private fun EmptyHint(text: String) {
    Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
        Text(
            text,
            color = DbbColors.InkTer, fontSize = 13.sp,
            textAlign = TextAlign.Center,
        )
    }
}

@Composable
private fun AlertCard(
    a: PriceAlert,
    onStop: () -> Unit,
    onArchive: () -> Unit,
    onReactivate: () -> Unit,
    onDelete: () -> Unit,
) {
    val archived = a.status != AlertStatus.ACTIVE
    val ready = (a.lastSavings ?: 0.0) > 0.0
    val anchor = if (a.mode == AlertMode.WANT) a.targetPrice else a.purchasePrice
    val anchorLabel = if (a.mode == AlertMode.WANT) "心理价" else "买价"
    val current = a.lastCurrentPrice
    val platformDisplay = a.platform ?: "全网"

    Card(
        Modifier.fillMaxWidth(),
        colors = CardDefaults.cardColors(containerColor = DbbColors.Card),
        elevation = CardDefaults.cardElevation(defaultElevation = 2.dp),
        shape = RoundedCornerShape(16.dp),
        border = BorderStroke(
            if (ready && !archived) 1.5.dp else 1.dp,
            if (ready && !archived) DbbColors.Teal else DbbColors.Border,
        ),
    ) {
        Column(Modifier.padding(13.dp)) {
            Row(verticalAlignment = Alignment.CenterVertically) {
                ProductThumb(title = a.title, size = 36.dp)
                Spacer(Modifier.width(10.dp))
                Text(
                    a.title, fontWeight = FontWeight.Bold, color = DbbColors.Ink,
                    modifier = Modifier.weight(1f), maxLines = 2,
                )
                PlatformChip(name = platformDisplay)
            }
            Spacer(Modifier.height(8.dp))
            Row(verticalAlignment = Alignment.Bottom) {
                Text(
                    "$anchorLabel ¥${fmtYuan(anchor ?: 0.0)}",
                    color = DbbColors.InkSec, fontSize = 13.sp,
                )
                Spacer(Modifier.weight(1f))
                if (current != null) {
                    val arrow = when (a.lastTrend) { "down" -> " ↓"; "up" -> " ↑"; else -> "" }
                    val priceColor = if (ready) DbbColors.Save else DbbColors.Ink
                    Text(
                        "当前 ¥${fmtYuan(current)}$arrow",
                        fontWeight = FontWeight.ExtraBold, fontSize = 18.sp, color = priceColor,
                        letterSpacing = (-0.5).sp,
                    )
                } else {
                    Text("待查价", color = DbbColors.InkTer, fontSize = 12.sp)
                }
            }
            if (current != null && anchor != null && anchor > 0) {
                Spacer(Modifier.height(6.dp))
                val frac: Float
                val barColor: Color
                if (ready) {
                    frac = 1f
                    barColor = DbbColors.Save
                } else {
                    frac = (anchor / current).coerceIn(0.0, 1.0).toFloat()
                    // 未到价用中性灰条:把屏幕色相压到 teal/save/up 三色,不再用 Gold 第四色。
                    barColor = DbbColors.InkTer
                }
                DbbProgressBar(frac, color = barColor)
                Spacer(Modifier.height(4.dp))
                Row {
                    val diffText = if (ready) {
                        "已低于${anchorLabel} ¥${fmtYuan(abs(anchor - current))}"
                    } else {
                        "还差 ¥${fmtYuan(current - anchor)} 到${anchorLabel}"
                    }
                    Text(diffText, color = DbbColors.InkTer, fontSize = 11.sp)
                    Spacer(Modifier.weight(1f))
                    if (ready) Text("近 7 天最低", color = DbbColors.InkTer, fontSize = 11.sp)
                }
            }
            if (ready && !archived) {
                Spacer(Modifier.height(8.dp))
                val msg = if (a.mode == AlertMode.WANT) {
                    "🎯 已降到心理价以下,可入手"
                } else {
                    "💰 比买价低 ¥${fmtYuan(a.lastSavings ?: 0.0)},可申请价保"
                }
                Box(
                    Modifier
                        .fillMaxWidth()
                        .clip(RoundedCornerShape(8.dp))
                        .background(DbbColors.SaveBg)
                        .padding(horizontal = 10.dp, vertical = 9.dp),
                ) {
                    Text(msg, color = DbbColors.Save, fontWeight = FontWeight.SemiBold, fontSize = 13.sp)
                }
            }
            Spacer(Modifier.height(4.dp))
            Row(horizontalArrangement = Arrangement.End, modifier = Modifier.fillMaxWidth()) {
                if (archived) {
                    TextButton(onClick = onReactivate) { Text("恢复监控", color = DbbColors.Teal) }
                } else {
                    if (a.mode == AlertMode.BOUGHT && ready) {
                        TextButton(onClick = onArchive) { Text("已申请·归档", color = DbbColors.Teal) }
                    }
                    TextButton(onClick = onStop) { Text("停止", color = DbbColors.InkSec) }
                }
                TextButton(onClick = onDelete) { Text("删除", color = DbbColors.Up) }
            }
        }
    }
}

@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun AddAlertSheet(
    sheetState: SheetState,
    onDismiss: () -> Unit,
    onAddWant: (String, String?, Double?) -> Unit,
    onAddBought: (String, String, Double) -> Unit,
) {
    // 旋转 / 切到后台再回来时保留表单内容,避免用户重新输 — Bottom Sheet 表单丢字最痛。
    // AlertMode 是 object/String 常量,nullable 也可序列化,都能 rememberSaveable。
    var mode by rememberSaveable { mutableStateOf(AlertMode.WANT) }
    var title by rememberSaveable { mutableStateOf("") }
    var platform by rememberSaveable { mutableStateOf<String?>(null) }
    var priceText by rememberSaveable { mutableStateOf("") }

    ModalBottomSheet(onDismissRequest = onDismiss, sheetState = sheetState, containerColor = DbbColors.Card) {
        Column(Modifier.fillMaxWidth().padding(20.dp).padding(bottom = 16.dp)) {
            Text("加入降价监控", fontWeight = FontWeight.Bold, fontSize = 18.sp, color = DbbColors.Ink)
            Spacer(Modifier.height(14.dp))
            Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
                SegChip("想买的", mode == AlertMode.WANT) { mode = AlertMode.WANT }
                SegChip("已买的", mode == AlertMode.BOUGHT) { mode = AlertMode.BOUGHT }
            }
            Spacer(Modifier.height(14.dp))
            OutlinedTextField(
                value = title, onValueChange = { title = it },
                label = { Text("商品名") },
                singleLine = true, modifier = Modifier.fillMaxWidth(),
            )
            Spacer(Modifier.height(10.dp))
            Text(
                if (mode == AlertMode.WANT) "平台(可不选,任意平台到价都提醒)" else "平台",
                color = DbbColors.InkSec, fontSize = 12.sp,
            )
            Spacer(Modifier.height(6.dp))
            Row(
                Modifier.fillMaxWidth().horizontalScroll(rememberScrollState()),
                horizontalArrangement = Arrangement.spacedBy(6.dp),
            ) {
                if (mode == AlertMode.WANT) {
                    FilterChip(
                        selected = platform == null, onClick = { platform = null },
                        label = { Text("不限") },
                        colors = FilterChipDefaults.filterChipColors(
                            selectedContainerColor = DbbColors.Teal,
                            selectedLabelColor = Color.White,
                        ),
                    )
                }
                ALL_PLATFORMS.forEach { p ->
                    FilterChip(
                        selected = platform == p, onClick = { platform = p },
                        label = { Text(p) },
                        colors = FilterChipDefaults.filterChipColors(
                            selectedContainerColor = DbbColors.Teal,
                            selectedLabelColor = Color.White,
                        ),
                    )
                }
            }
            Spacer(Modifier.height(10.dp))
            OutlinedTextField(
                value = priceText,
                onValueChange = { priceText = it.filter { c -> c.isDigit() || c == '.' } },
                label = { Text(if (mode == AlertMode.WANT) "心理价(元)" else "购买价(元)") },
                keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Decimal),
                singleLine = true, modifier = Modifier.fillMaxWidth(),
            )
            Spacer(Modifier.height(18.dp))
            val price = priceText.toDoubleOrNull()
            val valid = title.isNotBlank() &&
                (if (mode == AlertMode.WANT) (price == null || price > 0)
                else (price != null && price > 0 && platform != null))
            Button(
                onClick = {
                    if (mode == AlertMode.WANT) onAddWant(title, platform, price)
                    else onAddBought(title, platform!!, price!!)
                },
                enabled = valid,
                modifier = Modifier.fillMaxWidth().height(50.dp),
                shape = RoundedCornerShape(14.dp),
                colors = ButtonDefaults.buttonColors(containerColor = DbbColors.Teal),
            ) { Text("开始监控", fontWeight = FontWeight.SemiBold) }
            if (mode == AlertMode.BOUGHT) {
                Spacer(Modifier.height(8.dp))
                Text(
                    "提示:已买的需选平台 + 填买价,降价后提醒你申请价保。",
                    color = DbbColors.InkTer, fontSize = 11.sp,
                )
            }
        }
    }
}
