<template>
	<view class="cart-page">
		<view v-if="!loggedIn" class="cart-guest">
			<u-empty mode="car" text="登录后查看购物车" icon-size="100" />
			<button class="cart-btn-primary" @click="goLogin">去登录</button>
		</view>

		<template v-else>
			<view v-if="loading && !groups.length" class="cart-loading">
				<u-loading-icon mode="circle" />
			</view>

			<view v-else-if="loadFailed && !groups.length" class="cart-error">
				<u-empty mode="list" text="加载失败" icon-size="80" />
				<text class="cart-retry" @click="loadCart">点击重试</text>
			</view>

			<view v-else-if="!groups.length" class="cart-empty">
				<u-empty mode="car" :text="emptyText" icon-size="100" />
				<button class="cart-btn-primary" @click="goHome">去逛逛</button>
			</view>

			<template v-else>
				<view v-if="showInvalidBar" class="cart-toolbar">
					<text class="cart-toolbar__btn" @click="onCleanInvalid">清理失效商品</text>
					<text v-if="hasCheckedAny" class="cart-toolbar__btn" @click="onDeleteChecked">删除选中</text>
				</view>

				<scroll-view class="cart-scroll" scroll-y :style="{ height: scrollHeight }">
					<cart-shop-group
						v-for="group in groups"
						:key="group.shopId"
						:group="group"
						@shop-check="onShopCheck"
						@shop-click="onShopClick"
						@check-change="onItemCheck"
						@quantity-change="onQuantityChange"
						@delete="onDeleteItem"
						@goods-click="onGoodsClick"
					/>
				</scroll-view>

				<view class="cart-footer">
					<view class="cart-footer__check" @click="onToggleSelectAll">
						<view class="check-icon" :class="{ 'check-icon--on': selectAllChecked }">
							<u-icon v-if="selectAllChecked" name="checkbox-mark" color="#fff" size="14" />
						</view>
						<text class="cart-footer__label">全选</text>
					</view>
					<view class="cart-footer__sum">
						<text class="cart-footer__sum-label">合计：</text>
						<text class="cart-footer__sum-price">¥{{ checkedSummary.checkedAmountText }}</text>
					</view>
					<button
						class="cart-footer__btn"
						:disabled="!checkedSummary.checkedCount || actionLock"
						@click="onCheckout"
					>
						去结算({{ checkedSummary.checkedCount }})
					</button>
				</view>
			</template>
		</template>
	</view>
</template>

<script setup>
import { ref, computed } from 'vue'
import { onShow } from '@dcloudio/uni-app'
import { getToken } from '@/utils/auth'
import {
	getCartList,
	updateCartChecked,
	updateCartQuantity,
	removeCartItem,
	removeCartItems,
	cleanInvalidCart,
	prepareCartCheckout
} from '@/api/cart'
import {
	mapCartList,
	hasInvalidCartItems,
	countInvalidCartItems,
	getCheckedShopIds,
	getCheckedPurchasableIds,
	getAllPurchasableItems
} from '@/utils/cartDisplay'
import { goCartCheckout } from '@/utils/checkoutNav'
import { CART_EMPTY_TEXT, CART_MSG_CROSS_SHOP } from '@/constants/cart'
import { goGoodsDetail } from '@/utils/goodsDetail'
import { goShopHome } from '@/utils/shopNav'
import { PAGE_LOGIN, PAGE_HOME } from '@/utils/pageRoute'
import { useActionGuard } from '@/utils/actionGuard'
import CartShopGroup from '@/components/cart/CartShopGroup.vue'

const { locked: actionLock, run: runCartAction } = useActionGuard()

const loggedIn = ref(false)
const loading = ref(false)
const loadFailed = ref(false)
const groups = ref([])
const checkedSummary = ref({
	checkedCount: 0,
	checkedQuantity: 0,
	checkedAmountText: '0'
})
const scrollHeight = ref('500px')
const emptyText = CART_EMPTY_TEXT

const showInvalidBar = computed(() => hasInvalidCartItems(groups.value))

const allPurchasable = computed(() => getAllPurchasableItems(groups.value))

const selectAllChecked = computed(() => {
	const list = allPurchasable.value
	return list.length > 0 && list.every((item) => item.checked)
})

const hasCheckedAny = computed(() =>
	groups.value.some((g) => (g.items || []).some((item) => item.checked))
)

function calcScrollHeight() {
	try {
		const sys = uni.getSystemInfoSync()
		const h = sys.windowHeight || 600
		scrollHeight.value = `${h - 120}px`
	} catch (e) {
		scrollHeight.value = '500px'
	}
}

function applyCartData(data) {
	const mapped = mapCartList(data)
	groups.value = mapped.groups
	checkedSummary.value = mapped.checkedSummary
}

async function loadCart() {
	loading.value = true
	loadFailed.value = false
	try {
		const res = await getCartList()
		applyCartData(res.data)
	} catch (e) {
		loadFailed.value = true
		if (!groups.value.length) {
			groups.value = []
		}
	} finally {
		loading.value = false
	}
}

function buildCheckedPayload(items) {
	return items.map((item) => ({
		cartItemId: item.cartItemId,
		checked: !!item.checked
	}))
}

async function syncChecked(items) {
	if (!items.length) return
	runCartAction(async () => {
		try {
			await updateCartChecked(buildCheckedPayload(items))
			await loadCart()
		} catch (e) {
			await loadCart()
		}
	})
}

function onItemCheck(item, checked) {
	syncChecked([{ ...item, checked }])
}

function onShopCheck(group, checked) {
	const items = (group.items || [])
		.filter((row) => row.purchasable)
		.map((row) => ({ ...row, checked }))
	if (!items.length) return
	syncChecked(items)
}

function onToggleSelectAll() {
	const next = !selectAllChecked.value
	const items = allPurchasable.value.map((row) => ({ ...row, checked: next }))
	if (!items.length) return
	syncChecked(items)
}

function onQuantityChange(item, quantity) {
	runCartAction(async () => {
		try {
			await updateCartQuantity(item.cartItemId, quantity)
			await loadCart()
		} catch (e) {
			await loadCart()
		}
	})
}

function confirmRemove(onConfirm) {
	uni.showModal({
		title: '提示',
		content: '确定移出该商品吗？',
		success: (res) => {
			if (res.confirm) onConfirm()
		}
	})
}

async function onDeleteItem(item) {
	confirmRemove(async () => {
		try {
			await removeCartItem(item.cartItemId)
			uni.showToast({ title: '已移出', icon: 'none' })
			await loadCart()
		} catch (e) {
			// request 已提示
		}
	})
}

function onDeleteChecked() {
	const ids = []
	groups.value.forEach((g) => {
		;(g.items || []).forEach((item) => {
			if (item.checked) ids.push(item.cartItemId)
		})
	})
	if (!ids.length) {
		uni.showToast({ title: '请先勾选商品', icon: 'none' })
		return
	}
	uni.showModal({
		title: '提示',
		content: `确定移出选中的 ${ids.length} 件商品吗？`,
		success: async (res) => {
			if (!res.confirm) return
			try {
				await removeCartItems(ids)
				uni.showToast({ title: '已移出', icon: 'none' })
				await loadCart()
			} catch (e) {
				// request 已提示
			}
		}
	})
}

async function onCleanInvalid() {
	const invalidCount = countInvalidCartItems(groups.value)
	if (!invalidCount) {
		uni.showToast({ title: '暂无失效商品', icon: 'none' })
		return
	}
	uni.showModal({
		title: '提示',
		content: `确定清理 ${invalidCount} 件失效商品吗？`,
		success: async (res) => {
			if (!res.confirm) return
			try {
				const result = await cleanInvalidCart()
				const n = (result.data && result.data.removedCount) || 0
				uni.showToast({ title: n ? `已清理${n}件` : '暂无失效商品', icon: 'none' })
				await loadCart()
			} catch (e) {
				// request 已提示
			}
		}
	})
}

function onCheckout() {
	runCartAction(async () => {
		const ids = getCheckedPurchasableIds(groups.value)
		if (!ids.length) {
			uni.showToast({ title: '请先勾选要结算的商品', icon: 'none' })
			return
		}
		const shopIds = getCheckedShopIds(groups.value)
		if (shopIds.size > 1) {
			uni.showToast({ title: CART_MSG_CROSS_SHOP, icon: 'none' })
			return
		}
		await prepareCartCheckout(ids)
		goCartCheckout(ids)
	})
}

function onShopClick(group) {
	if (group && group.shopId) {
		goShopHome(group.shopId)
	}
}

function onGoodsClick(item) {
	if (item && item.goodsId) {
		goGoodsDetail(item.goodsId)
	}
}

function goLogin() {
	uni.navigateTo({ url: PAGE_LOGIN })
}

function goHome() {
	uni.switchTab({ url: PAGE_HOME })
}

onShow(() => {
	loggedIn.value = !!getToken()
	calcScrollHeight()
	if (!loggedIn.value) {
		groups.value = []
		return
	}
	loadCart()
})
</script>

<style lang="scss" scoped>
.cart-page {
	height: calc(100vh - 288rpx);
	background: #f5f6f8;
	padding-bottom: env(safe-area-inset-bottom);
}
.cart-guest,
.cart-empty,
.cart-loading,
.cart-error {
	padding: 120rpx 48rpx;
	display: flex;
	flex-direction: column;
	align-items: center;
}
.cart-btn-primary {
	margin-top: 40rpx;
	width: 320rpx;
	height: 80rpx;
	line-height: 80rpx;
	background: linear-gradient(135deg, #43a047 0%, #2e7d32 100%);
	color: #fff;
	font-size: 28rpx;
	border-radius: 40rpx;
	border: none;
}
.cart-retry {
	margin-top: 24rpx;
	font-size: 28rpx;
	color: #2e7d32;
}
.cart-toolbar {
	display: flex;
	justify-content: flex-end;
	gap: 24rpx;
	padding: 16rpx 24rpx;
	background: #fff;
}
.cart-toolbar__btn {
	font-size: 26rpx;
	color: #2e7d32;
}
.cart-scroll {
	padding: 16rpx 24rpx;
	box-sizing: border-box;
}
.cart-footer {
	position: fixed;
	left: 0;
	right: 0;
	bottom: 100rpx;
	display: flex;
	align-items: center;
	padding: 16rpx 24rpx;
	padding-bottom: calc(16rpx + env(safe-area-inset-bottom));
	background: #fff;
	border-top: 1rpx solid #eee;
	z-index: 10;
}
.cart-footer__check {
	display: flex;
	align-items: center;
	margin-right: 16rpx;
}
.check-icon {
	width: 36rpx;
	height: 36rpx;
	border: 2rpx solid #ccc;
	border-radius: 50%;
	display: flex;
	align-items: center;
	justify-content: center;
	background: #fff;
}
.check-icon--on {
	background: #2e7d32;
	border-color: #2e7d32;
}
.cart-footer__label {
	margin-left: 8rpx;
	font-size: 26rpx;
	color: #333;
}
.cart-footer__sum {
	flex: 1;
	text-align: right;
	margin-right: 16rpx;
}
.cart-footer__sum-label {
	font-size: 26rpx;
	color: #333;
}
.cart-footer__sum-price {
	font-size: 34rpx;
	color: #e53935;
	font-weight: 600;
}
.cart-footer__btn {
	flex-shrink: 0;
	min-width: 200rpx;
	height: 72rpx;
	line-height: 72rpx;
	padding: 0 28rpx;
	background: linear-gradient(135deg, #43a047 0%, #2e7d32 100%);
	color: #fff;
	font-size: 28rpx;
	border-radius: 36rpx;
	border: none;
}
.cart-footer__btn[disabled] {
	opacity: 0.5;
}
</style>
