<template>
	<view class="list-container">
		<image class="background-image" src="/static/listbg.png" mode="aspectFill"></image>
		<view class="back-header">
			<view class="btn-back">
				<view class="back-btn" hover-class="hover_btn" @click="handleBack">
					<image class="back-icon" src="/static/icon_back.png" mode="aspectFill"></image>
				</view>
				<!-- <button class="back-upload" @click="handleUpload">照片上传</button> -->
			</view>
			<view class="list-title">
				<text class="title-line">请选择</text>
				<text class="title-line">你喜欢的风格</text>
			</view>
			<input class="search-input" v-model="searchValue" placeholder-class="search-input-placeholder"
				placeholder="请输入作品类型、作者名称" @input="onSearchInput" @confirm="onSearchConfirm" />
		</view>
		<scroll-view class="tabs-container" direction="horizontal" :show-scrollbar="showTabsScrollbar" :scroll-left="tabsScrollLeft" @scroll="onTabsScroll" @scrollend="onTabsScrollEnd" scroll-with-animation="true" :scroll-into-view="scrollIntoViewId">
			<view class="tabs-group" v-if="tabs.length > 0">
				<view class="tabs" id="tab-all" @click="changeActiveTab('all')" :class="{ active: activeTab == 'all' }">
					<text class="tab-item" :class="{ active: activeTab == 'all' }">{{ t('全部') }}</text>
				</view>
				<view class="tabs" v-for="item in tabs" :key="item.value" :id="'tab-' + formatTabId(item.value)"
					@click="changeActiveTab(item.value)" :class="{ active: activeTab == item.value }">
					<text class="tab-item" :class="{ active: activeTab == item.value }">{{ item.label }}</text>
				</view>
			</view>
		</scroll-view>
		<!-- 瀑布流区域 -->
		<scroll-view class="waterfall-container" direction="vertical" @scrolltolower="onScrollToLower"
			refresher-enabled="true" :refresher-triggered="isRefreshing" @refresherrefresh="onRefresh"
			v-if="!isLoading || adslist.length > 0">
			<!-- 数据加载完成后显示瀑布流 -->
			<view class="waterfall-columns" v-if="!isLoading && adslist.length > 0">
				<view class="waterfall-column" v-for="columnIndex in 3" :key="columnIndex">
						<view class="waterfall-item" v-for="(item, index) in getColumnItems(columnIndex - 1)" :key="item.id"
							:style="{ backgroundColor: getItemBackground(item.id) }"
							@click="handleItemClick(item)">
							<image class="item-image" :src="item.style_image" mode="widthFix" lazy-load="true"
								@load="onImageLoad(item.id)" @error="onImageError(item.id)"></image>
					</view>
				</view>
			</view>
			<!-- 加载更多提示 -->
			<view class="loading-more" v-if="isLoadingMore">
				<text class="loading-text">加载中...</text>
			</view>
			<!-- 没有更多数据提示 -->
			<view class="no-more" v-if="noMoreData && adslist.length > 0">
				<text class="no-more-text">没有更多数据了</text>
			</view>
		</scroll-view>

		<!-- 初始加载状态 -->
		<view class="initial-loading" v-if="isLoading && adslist.length == 0">
			<image class="loading-gif" src="/static/Loading.gif" mode="aspectFit"></image>
			<text class="loading-text">加载中...</text>
		</view>
		<!-- 空状态显示 -->
		<view class="empty-state" v-if="!isLoading && (meta.total == 0 || hasError) && adslist.length == 0">
			<image class="empty-icon" src="/static/error_black.png" mode="aspectFit"></image>
		</view>
		<!-- 弹窗组件 -->
		<PopupCheck :visible="showPopup" @close="handleClosePopup" @upload="handleUploadFromPopup"
			@take-photo="handleTakePhotoFromPopup" />
		<PopupUpload :visible="showPopupUpload" :close-on-overlay="true" @close="handleClosePopupUpload" />
	</view>
</template>
<script setup>
	import { ref } from 'vue'
	import { category, list, ossUpload } from '../../utils/reques.uts'
	import type { ResponseData } from '../../utils/reques.uts'

	import PopupCheck from '../../components/Popup/PopupCheck.uvue'
	import PopupUpload from '../../components/Popup/PopupUpload.uvue'
	

	// 定义标签项的类型接口
	type TabItem = {
		label : string
		value : string
	}

	// 定义列表项的类型接口
	type listItem = {
		style_image : string
		id : number
	}

	type metaData = {
		total : number
		records : number
	}

	// 弹窗显示状态
	const showPopup = ref(false)
	const showPopupUpload = ref(false)
	const searchValue = ref('')
	const activeTab = ref<string>('all')
	// H5 横向滚动控制与可视化
	const showTabsScrollbar = ref<boolean>(true)
	const tabsScrollLeft = ref<number>(0)
	// 横向滚动到可视区域的目标 id
	const scrollIntoViewId = ref<string>('tab-all')
	const tabs = ref<Array<TabItem>>([])
	const adslist = ref<Array<listItem>>([])
	const meta = ref<metaData>({
		total: 0,
		records: 0
	})

	// 添加 imageSrc 和 url 变量
	const imageSrc = ref('')
	const url = ref('')

	// 随机占位背景色列表（未加载完成时使用）
	const PLACEHOLDER_COLORS = [
		'#ab372f', '#f15642', '#692a1b', '#eeaa9c', '#64483d',
		'#ea8958', '#e8b49a', '#be7e4a', '#9a8878', '#f9e9cd',
		'#806332', '#b7ae8f', '#b7d07a', '#1a6840', '#40a070',
		'#10aec2', '#806d9e', '#a35c8f', '#c35691', '#d13c74'
	] as Array<string>

	// 每个 item 的加载状态和占位背景色映射，按 id 存储
	const itemLoaded = ref<Map<number, boolean>>(new Map<number, boolean>())
	const itemBgColors = ref<Map<number, string>>(new Map<number, string>())

	// 随机取色（严格返回字符串）
	function pickRandomColor() : string {
		const len : number = PLACEHOLDER_COLORS.length
		const idx : number = Math.floor(Math.random() * len)
		return PLACEHOLDER_COLORS[idx]
	}

	// 为新列表项初始化占位背景色和加载状态
	function ensureItemMappings(items : Array<listItem>) : void {
		for (let i = 0; i < items.length; i++) {
			const id : number = items[i].id
			if (!itemBgColors.value.has(id)) {
				itemBgColors.value.set(id, pickRandomColor())
			}
			if (!itemLoaded.value.has(id)) {
				itemLoaded.value.set(id, false)
			}
		}
	}

	// 供模板使用：返回当前 item 的背景色
	function getItemBackground(id : number) : string {
		const loaded : boolean = itemLoaded.value.get(id) ?? false
		if (loaded) {
			return '#FFFFFF'
		}
		const color = itemBgColors.value.get(id)
		return color != null ? color : '#FFFFFF'
	}

	// 定义分页参数类型
	type PageParams = {
		search : string
		value : string
		limit : number
		page : number
	}

	// 分页和加载状态管理
	const pageParams = ref<PageParams>({
		search: '',
		value: '',
		limit: 10,
		page: 1
	})
	const isLoading = ref(false)
	const isLoadingMore = ref(false)
	const isRefreshing = ref(false)
	const noMoreData = ref(false)
	const hasError = ref(false) // 添加请求失败状态

	// 防止 H5 端生命周期重复触发导致初始化调用两次
	const hasInit = ref<boolean>(false)

	const t = (s : string) : string => s

	// 规范化生成 tab 的 id，避免非法字符影响滚动定位
	function formatTabId(value : string) : string {
		let res : string = ''
		for (let i = 0; i < value.length; i++) {
			const ch : string = value.charAt(i)
			const code : number = value.charCodeAt(i) ?? 0
			const isUpper : boolean = code >= 65 && code <= 90
			const isLower : boolean = code >= 97 && code <= 122
			const isDigit : boolean = code >= 48 && code <= 57
			if (isUpper || isLower || isDigit || ch == '_' || ch == '-') {
				res += ch
			} else {
				res += '-'
			}
		}
		return res
	}

	// tabs 区域滚动事件（用于 H5 调试与确保绑定生效）
	function onTabsScroll(e : UniScrollEvent) : void {
		const d = e.detail
		// 同步横向滚动位置，便于编程控制
		tabsScrollLeft.value = d.scrollLeft
	}

	function onTabsScrollEnd(_e : UniScrollEvent) : void {
		// 可按需处理滚动结束逻辑
	}
	// 获取分类数据的函数
    const getcategory = async () : Promise<void> => {
        const params = {} as object
        try {
            const res : ResponseData = await category(params) as ResponseData
            if (res.code == 0) {
                // 正确处理 UTSJSONObject 数组到 TabItem 数组的转换
                const dataArray = res.data as Array<any>
                const tabItems : Array<TabItem> = []

                for (let i = 0; i < dataArray.length; i++) {
                    const item = dataArray[i] as UTSJSONObject
                    const tabItem : TabItem = {
                        label: item.getString('label') ?? '',
                        value: item.getString('value') ?? ''
                    }
                    tabItems.push(tabItem)
                }

                tabs.value = tabItems
            }
        } catch (error) {
            // 分类请求失败，保留现有 tabs 状态即可
            console.log('获取分类失败:')
        }
    }

const getlist = async (isLoadMore : boolean) : Promise<void> => {
		// 如果是加载更多，设置加载更多状态
		if (isLoadMore) {
			if (isLoadingMore.value || noMoreData.value) return
			isLoadingMore.value = true
		} else {
			// 首次加载或刷新
			isLoading.value = true
			pageParams.value.page = 1
			noMoreData.value = false
			hasError.value = false // 重置错误状态
			// 刷新时重置映射，避免旧状态干扰
			itemLoaded.value = new Map<number, boolean>()
			itemBgColors.value = new Map<number, string>()
		}

		// 构建请求参数
	const params = {
			value: pageParams.value.value,
			search: pageParams.value.search,
			limit: pageParams.value.limit,
			page: pageParams.value.page
		} as object

        try {
            const res : ResponseData = await list(params) as ResponseData
            if (res.code == 0) {
                // 检查meta是否为null或undefined
                // 正确处理 meta 数据的赋值
                if (res.meta != null) {
                    const metaObj = res.meta as UTSJSONObject
					const newMeta: metaData = {
						total: metaObj.getNumber('total') ?? 0,
						records: metaObj.getNumber('records') ?? 0
					}
					meta.value = newMeta
					// console.log('newMeta',newMeta);
				}

				// 正确处理 UTSJSONObject 数组到 listItem 数组的转换
				const dataArray = res.data as Array<any>
				const listItems : Array<listItem> = []
					// console.log('dataArray',dataArray);
					
				for (let i = 0; i < dataArray.length; i++) {
					const item = dataArray[i] as UTSJSONObject
					const listItemData : listItem = {
						style_image: item.getString('style_image') ?? '' + '?x-oss-process=image/resize,lfit,w_60',
						id: item.getNumber('id') ?? 0
					}
					listItems.push(listItemData)
				}

				if (isLoadMore) {
					// 初始化新追加项的占位颜色与加载状态
					ensureItemMappings(listItems)
					// 加载更多：追加数据
					adslist.value = [...adslist.value, ...listItems]
					// 如果返回的数据少于limit，说明没有更多数据了
					if (listItems.length < pageParams.value.limit) {
						noMoreData.value = true
					}
				} else {
					// 首次加载或刷新：替换数据
					ensureItemMappings(listItems)
					adslist.value = listItems
					// 首屏如果返回的数据不足一页，则直接标记为没有更多，防止触底立即再次请求
					if (listItems.length < pageParams.value.limit) {
						noMoreData.value = true
					}
				}
			}
		} catch (error) {
			console.log('获取列表失败:', error)
			hasError.value = true // 设置请求失败状态
		} finally {
			isLoading.value = false
			isLoadingMore.value = false
			isRefreshing.value = false
		}
	}

	onLoad(() => {
		// H5 有时会重复触发页面初始化，这里加一次性防护
		if (hasInit.value == true) {
			return
		}
		hasInit.value = true
		getcategory()
		getlist(false)
	});

	onUnload(() => {
		// 页面卸载时重置初始化标记，便于下次进入重新初始化
		hasInit.value = false
	})

	const changeActiveTab = (tabValue : string) : void => {
		activeTab.value = tabValue
		pageParams.value.value = tabValue
		if (tabValue == 'all') {
			pageParams.value.value = ''
		}
		// 切换标签后，滚动到对应标签位置
		scrollIntoViewId.value = tabValue == 'all' ? 'tab-all' : 'tab-' + formatTabId(tabValue)
		// 清空列表数据，以便显示初始加载状态
		adslist.value = []
		getlist(false)
	}

	const handleBack = () => {
		uni.reLaunch({
			url: '/pages/index/index'
		})
	}

	const handleUpload = () => {
		showPopup.value = true
	}

	// 标签点击处理，切换激活标签
	const handleTab1Click = (id : string) : void => {
		activeTab.value = id
	}

	// 处理弹窗关闭
	const handleClosePopup = () => {
		showPopup.value = false
	}

	// 处理弹窗中的上传操作
	const handleUploadFromPopup = async () => {
		// 选择手机上传 -> 检测平台
		showPopup.value = false

		// #ifdef WEB
		// H5 端先选择图片
		try {
			uni.chooseImage({
				count: 1,
				sizeType: ['original', 'compressed'],
				sourceType: ['album', 'camera'],
				success: async (res) => {
					const tempFilePaths = res.tempFilePaths
					if (tempFilePaths.length > 0) {
						imageSrc.value = tempFilePaths[0]

						// 执行上传
						try {
							const uploadRes = await ossUpload(imageSrc.value) as ResponseData
							console.log('uploadRes', uploadRes);
							
							if (uploadRes.code == 0) {
								// 解析返回的数据
								const data = uploadRes.data as UTSJSONObject
								url.value = data?.getString('url') ?? ''

								// 使用 encodeURIComponent 编码 URL 参数
								const encodedUrl = encodeURIComponent(url.value)
								console.log('准备导航到 camera 页面，URL:', '/pages/camera/index?imageSrc=' + encodedUrl)
								uni.navigateTo({
									url: '/pages/camera/index?imageSrc=' + encodedUrl,
									success: () => {
										console.log('导航成功')
									},
									fail: (err) => {
										console.log('导航到相机页面失败:', err)
										uni.showToast({
											title: '页面跳转失败',
											icon: 'none'
										})
									}
								})
							} else {
								uni.showToast({
									title: '上传失败，请重试',
									icon: 'error'
								})
							}
						} catch (error) {
							console.log('ossUpload 失败:', error)
							uni.showToast({
								title: '上传失败，请重试',
								icon: 'error'
							})
						}
					}
				},
				fail: (error) => {
					console.log('取消:', error)
					uni.showToast({
						title: '取消',
						icon: 'none'
					})
				}
			})
			return
		} catch (error) {
			console.log('H5 选择图片异常:', error)
		}
		// #endif

		// 非 H5 端或异常时，显示上传提示弹窗
		showPopupUpload.value = true
	}

	// 处理弹窗中的拍照操作
	const handleTakePhotoFromPopup = () => {
		showPopup.value = false
		uni.navigateTo({
			url: '/pages/posture/index',
			fail: (err) => {
				console.log('导航到拍照页面失败:', err)
				uni.showToast({
					title: '页面跳转失败',
					icon: 'none'
				})
			}
		})
	}

	// Upload 弹窗关闭
	const handleClosePopupUpload = () => {
		showPopupUpload.value = false
	}

	// 滚动到底部触发加载更多
	const onScrollToLower = () : void => {
		// 触底加载更多：避免与首屏加载并发；仅在非加载中且有更多数据时触发
		if (isLoading.value || isLoadingMore.value || noMoreData.value) {
			return
		}
		pageParams.value.page = pageParams.value.page + 1
		getlist(true)
	}

	// 下拉刷新
	const onRefresh = () : void => {
		isRefreshing.value = true
		pageParams.value.page = 1
		getlist(false)
	}

	// 执行搜索
	function performSearch() : void {
		pageParams.value.search = searchValue.value
		pageParams.value.page = 1
		noMoreData.value = false
		getlist(false)
	}

	// 搜索输入处理
	let searchTimer : number | null = null
	function onSearchInput(event : UniInputEvent) : void {
		// 防抖处理，避免频繁请求
		if (searchTimer != null) {
			clearTimeout(searchTimer as number)
		}
		searchTimer = setTimeout(() => {
			performSearch()
		}, 1000) // 防抖
	}

	// 搜索确认处理
	function onSearchConfirm() : void {
		if (searchTimer != null) {
			clearTimeout(searchTimer as number)
		}
		performSearch()
	}

	// 瀑布流相关方法
	// 将数据分配到三列中
	const getColumnItems = (columnIndex : number) : Array<listItem> => {
		const columnItems : Array<listItem> = []
		for (let i = columnIndex; i < adslist.value.length; i += 3) {
			columnItems.push(adslist.value[i])
		}
		return columnItems
	}

	// 处理图片点击事件
	const handleItemClick = (item : listItem) : void => {
		uni.setStorage({
			key: 'selectedItem',
			data: {
				id: item.id,
				content: item.style_image
			}
		})
		showPopup.value = true
	}

	// 图片加载成功：标记该 item 已加载，背景色切回白色
	const onImageLoad = (id : number) : void => {
		itemLoaded.value.set(id, true)
	}

	// 图片加载失败：保持随机占位色
	const onImageError = (id : number) : void => {
		itemLoaded.value.set(id, false)
	}
</script>
<style scoped>
	.list-container {
		width: 100%;
		/* height: 492.36rpx; */
		position: relative;
		display: flex; /* 页面根容器采用flex布局，便于子容器flex:1生效 */
		flex-direction: column; /* 垂直方向布局 */
		height: 100%; /* 撑满页面高度，确保滚动容器可计算高度 */
	}

	.background-image {
		position: absolute;
		top: 0;
		left: 0;
		width: 100%;
		/* height: 100%; */
		height: 492.36rpx;
		z-index: 1;
	}

	.back-btn {
		width: 50rpx;
		height: 50rpx;
		border-radius: 25rpx;
		background-color: rgba(255, 255, 255, 0.5);
		/* 最后一个参数 0~1 表示透明度 */
	}

	.back-header {
		padding: 0 38rpx;
		padding-top: 33rpx;
		position: relative;
		z-index: 2;
	}

	.btn-back {
		display: flex;
		flex-direction: row;
		justify-content: space-between;
		align-items: center;
	}

	.back-btn {
		width: 50rpx;
		height: 50rpx;
		border-radius: 25rpx;
		background-color: rgba(255, 255, 255, 0.5);
		display: flex;
		justify-content: center;
		align-items: center;
	}

	.back-icon {
		width: 45rpx;
		height: 45rpx;
	}

	.search-input {
		margin-top: 18rpx;
		width: 422rpx;
		height: 56rpx;
		background: rgba(255, 255, 255, 0.36);
		border-radius: 28rpx;
		font-weight: bold;
		font-size: 19rpx;
		color: #333333;
		padding: 0 28rpx;
	}

	.search-input-placeholder {
		height: 100%;
		line-height: 56rpx;
	}




	.back-upload {
		width: 102rpx;
		height: 44rpx;
		border-radius: 14rpx;
		border: 1px solid #FD3DA0;
		background-color: #fd4196;
		font-weight: bold;
		font-size: 16rpx;
		color: #FFFFFF;
		line-height: 44rpx;
	}

	.list-title {
		margin-top: 40rpx;
	}

	.list-title .title-line {
		font-weight: bold;
		font-size: 55rpx;
		color: #000000;
	}

	.tabs-container {
		height: 40rpx;
		margin: 19rpx 34rpx 1rpx 34rpx;
		z-index: 1;
		display: flex;
		flex-direction: row;
		width: auto;
		white-space: nowrap;
	}
	
	.tabs-container::-webkit-scrollbar {
		display: none;
	}

	.tabs-group {
		display: flex;
		flex-wrap: nowrap;
		flex-direction: row;
		/* 移除宽度限制，允许横向展开 */
		width: auto;
		/* 确保子元素不会换行 */
		white-space: nowrap;
	}

	.tabs {
		display: flex;
		align-items: center;
		justify-content: center;
		flex: 0 0 auto;
		margin-right: 16rpx;
	}

	.tab-item.active {
		color: #FD3C9F;
	}

	.tab-item {
		padding: 10rpx;
		font-weight: bold;
		font-size: 25rpx;
		color: #3D3B3B;
	}

	/* 瀑布流区域 */
	.waterfall-container {
		flex: 1;
		padding: 0 30rpx;
		margin-top: 20rpx;
		position: relative;
		z-index: 99;
	}

	.waterfall-columns {
		display: flex;
		flex-direction: row;
		justify-content: space-between;
		align-items: flex-start;
	}

	.waterfall-column {
		width: 32%;
		display: flex;
		flex-direction: column;
	}

	.waterfall-item {
		background: #FFFFFF;
		border-radius: 16rpx;
		overflow: hidden;
		box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
		margin-bottom: 20rpx;
		width: 100%;
		max-height: 350rpx;
	}

	.item-image {
		width: 100%;
		height: auto;
		min-height: 200rpx;
		display: flex;
	}

	/* 加载状态样式 */
	.loading-more {
		display: flex;
		justify-content: center;
		align-items: center;
		padding: 30rpx 0;
		width: 100%;
		
	}

	.loading-text {
		font-size: 24rpx;
		color: #999999;
	}

	.no-more {
		display: flex;
		justify-content: center;
		align-items: center;
		padding: 30rpx 0;
		width: 100%;
	}

	.no-more-text {
		font-size: 24rpx;
		color: #cccccc;
	}

	.item-content {
		padding: 20rpx;
	}

	.item-title {
		font-size: 28rpx;
		color: #333333;
		font-weight: bold;
		line-height: 1.4;
	}

	/* 空状态样式 */
	.empty-state {
		display: flex;
		flex-direction: column;
		align-items: center;
		justify-content: center;
		padding: 300rpx 0;
		flex: 1;

	}

	.empty-icon {
		width: 300rpx;
		height: 300rpx;
		margin-bottom: 30rpx;
	}

	.empty-text {
		font-size: 28rpx;
		color: #999999;
		text-align: center;
	}

	/* 初始加载状态样式 */
	.initial-loading {
		display: flex;
		flex-direction: column;
		align-items: center;
		justify-content: center;
		padding: 200rpx 0;
		flex: 1;
		position: relative;
		z-index: 99;
	}

	.loading-gif {
		width: 140rpx;
		height: 140rpx;
		margin-bottom: 15rpx;
	}
</style>