<template>
	<view class="app-center-page">
		<!-- 自定义顶栏：头像 + 应用中心 + 搜索 -->
		<view class="custom-header">
			<view class="header-left" @click="onAvatarClick">
				<UserAvatar
					:name="currentUser.name"
					:id="currentUser.id"
					:src="currentUser.avatar"
					:size="80"
					unit="rpx"
				/>
				<view class="org-info">
					<text class="user-name">应用中心</text>
				</view>
			</view>
			<view class="header-right">
				<view class="icon-btn" @click="onSearch">
					<image class="icon-img" src="/static/icons/search.svg" mode="aspectFit" />
				</view>
			</view>
		</view>

		<scroll-view
			class="app-center-scroll"
			scroll-y
			:refresher-enabled="refresherEnabled"
			:refresher-triggered="refresherTriggered"
			@refresherrefresh="onRefresh"
		>
			<!-- 最近使用标题 + 4 列网格（最多展示 8 个） -->
			<view class="recent-section">
				<text class="section-title">最近使用</text>
				<view class="quick-grid">
					<view v-for="app in quickApps" :key="app.id" class="app-tile" @click="openApp(app)">
						<view class="tile-icon" :style="{ background: app.iconBg || defaultIconBg }">
							<image class="tile-icon-img" :src="app.iconPath" mode="aspectFit" />
							<view
								v-if="app.badge"
								class="tile-badge"
								:style="{ background: app.badgeBg || '#fbbf24', color: app.badgeColor || '#fff' }"
							>
								{{ app.badge }}
							</view>
						</view>
						<text class="tile-name tile-name-2">{{ app.name }}</text>
					</view>
				</view>
			</view>

			<view class="all-section">
				<!-- 水平分类 Tab -->
				<view class="category-bar">
					<scroll-view
						class="category-scroll"
						scroll-x
						scroll-with-animation
						:show-scrollbar="false"
						:scroll-into-view="scrollIntoTabId"
					>
						<view class="category-list">
							<view
								v-for="(cat, catIdx) in categories"
								:key="cat.id"
								:id="'cat-tab-' + catIdx"
								class="category-item"
								:class="{ active: cat.id === activeCategoryId }"
								@click="onCategoryTabClick(catIdx)"
							>
								<text class="category-name">{{ cat.name }}</text>
								<view v-if="cat.id === activeCategoryId" class="category-underline" />
							</view>
						</view>
					</scroll-view>
				</view>
			</view>

					<!-- 全部应用 swiper 4 列网格（横向滑动切分类） -->
					<swiper
						class="apps-swiper"
						:current="currentCategoryIndex"
						@change="onSwiperChange"
						:circular="false"
					>
						<swiper-item v-for="cat in categories" :key="cat.id">
							<view class="apps-grid">
								<view
									v-for="app in getAppsByCategory(cat.id)"
									:key="app.id"
									class="app-tile app-tile-4"
									@click="openApp(app)"
								>
									<view class="tile-icon" :style="{ background: app.iconBg || defaultIconBg }">
										<image class="tile-icon-img" :src="app.iconPath" mode="aspectFit" />
										<view
											v-if="app.badge"
											class="tile-badge"
											:style="{ background: app.badgeBg || '#fbbf24', color: app.badgeColor || '#fff' }"
										>
											{{ app.badge }}
										</view>
									</view>
									<text class="tile-name tile-name-2">{{ app.name }}</text>
								</view>
							</view>
						</swiper-item>
					</swiper>
		</scroll-view>
	</view>
</template>

<script>
	import UserAvatar from '../../components/UserAvatar.vue'
	import { getToken, getLaunchpadApps, ssoLogin, getUserIdFromToken } from '../../utils/api'

	const USER_KEY = 'current_user'
	const RECENT_APPS_KEY_PREFIX = 'launchpad_recent_apps_v1_'
	const RECENT_APPS_MAX = 8

	/** 渐变色库与 `components/SystemAvatar.vue` 保持一致 */
	const AVATAR_GRADIENT_PAIRS = [
		['#1e3a8a', '#93c5fd'],
		['#166534', '#86efac'],
		['#c2410c', '#fdba74'],
		['#b91c1c', '#fca5a5'],
		['#5b21b6', '#c4b5fd'],
		['#0f766e', '#5eead4'],
		['#3730a3', '#a5b4fc'],
		['#0d9488', '#2dd4bf'],
		['#b45309', '#fcd34d'],
		['#be123c', '#fda4af'],
		['#0369a1', '#7dd3fc'],
		['#4d7c0f', '#bef264'],
		['#86198f', '#e879f9'],
		['#475569', '#cbd5e1'],
		['#047857', '#6ee7b7'],
		['#6d28d9', '#ddd6fe'],
		['#1e40af', '#93c5fd'],
		['#ea580c', '#fed7aa'],
		['#0e7490', '#99f6e4'],
		['#881337', '#fbcfe8']
	]

	function getGradientIndexByName(name) {
		const s = String(name || '').trim() || 'SYSTEM'
		let hash = 0
		for (let i = 0; i < s.length; i++) {
			hash = ((hash << 5) - hash + s.charCodeAt(i)) | 0
		}
		return Math.abs(hash) % AVATAR_GRADIENT_PAIRS.length
	}

	function getGradientBgByName(name) {
		const idx = getGradientIndexByName(name)
		const pair = AVATAR_GRADIENT_PAIRS[idx]
		return pair ? `linear-gradient(135deg, ${pair[0]} 0%, ${pair[1]} 100%)` : ''
	}

	export default {
		components: { UserAvatar },
		data() {
			return {
				currentUser: { name: '', id: '', avatar: '' },
				defaultIconBg: 'linear-gradient(135deg, #e6f4ea 0%, #d4edda 100%)',

				launchpadLoading: false,

				// 下拉刷新（避免首屏阶段重复触发）
				refresherEnabled: false,
				refresherTriggered: false,

				// 顶部最近使用（本地按 usedAt 倒序，最多 8 个）
				quickApps: [],

				categories: [{ id: 'recent', name: '全部应用' }],
				activeCategoryId: 'recent',

				// 全部应用网格数据：来自接口返回的 items
				allApps: [],

				/** 横向分类 Tab 与 swiper 同步时滚入视口（与 chat 页 scroll-into-view 用法一致） */
				scrollIntoTabId: ''
			}
		},
		async onLoad() {
			this.loadCurrentUser()
			this.refresherEnabled = false
			try {
				await this.fetchLaunchpadApps()
			} finally {
				this.refresherEnabled = true
			}
		},
		computed: {
			currentCategoryIndex() {
				const idx = this.categories.findIndex((c) => c.id === this.activeCategoryId)
				return idx >= 0 ? idx : 0
			},

			filteredApps() {
				// 根据当前 Tab 过滤；如果没有命中则回退显示全部（避免空白）
				const active = String(this.activeCategoryId || '')
				// “全部应用”Tab 的 id 约定为 'recent'
				if (active === 'recent') return this.allApps
				const list = this.allApps.filter((a) => String(a.category || '') === active)
				return list.length ? list : this.allApps
			}
		},
		methods: {
			async onRefresh() {
				this.refresherTriggered = true
				try {
					await this.fetchLaunchpadApps()
				} finally {
					this.refresherTriggered = false
				}
			},
			/** 当前登录用户 id，用于分用户存储「最近使用」 */
			getRecentAppsStorageKey() {
				let uid = ''
				try {
					const raw = uni.getStorageSync(USER_KEY)
					if (raw && typeof raw === 'object') {
						const id = raw.id ?? raw.user_id
						if (id != null && id !== '') uid = String(id)
					}
				} catch (e) {}
				if (!uid) {
					const token = getToken()
					if (token) uid = String(getUserIdFromToken(token) || '')
				}
				return uid ? RECENT_APPS_KEY_PREFIX + uid : ''
			},
			loadRecentApps() {
				const key = this.getRecentAppsStorageKey()
				if (!key) return []
				try {
					const raw = uni.getStorageSync(key)
					if (Array.isArray(raw)) return raw
					if (raw && typeof raw === 'object' && Array.isArray(raw.items)) return raw.items
				} catch (e) {}
				return []
			},
			saveRecentApps(list) {
				const key = this.getRecentAppsStorageKey()
				if (!key) return
				try {
					uni.setStorageSync(key, Array.isArray(list) ? list : [])
				} catch (e) {}
			},
			refreshQuickApps() {
				// 只用已拉取到的 `allApps` + 本地 recent 存储来刷新顶部“最近使用”
				// 避免每次点击应用都发起网络请求
				const appList = Array.isArray(this.allApps) ? this.allApps : []
				if (!appList.length) return

				const recentList = this.loadRecentApps()
					.filter((x) => x && x.appId != null)
					.map((x) => ({ appId: String(x.appId), usedAt: Number(x.usedAt) || 0 }))
					.sort((a, b) => (b.usedAt || 0) - (a.usedAt || 0))

				const appById = new Map(appList.map((a) => [String(a.id), a]))
				const recentApps = []
				const recentSeen = new Set()

				for (const r of recentList) {
					const id = String(r.appId || '')
					if (!id || recentSeen.has(id)) continue
					if (!appById.has(id)) continue
					recentSeen.add(id)
					recentApps.push(appById.get(id))
					if (recentApps.length >= RECENT_APPS_MAX) break
				}

				// 不足 8 个时，用接口里的其他应用补齐（但 recents 仍保持按时间倒序）
				if (recentApps.length < RECENT_APPS_MAX) {
					const rest = appList.filter((a) => !recentSeen.has(String(a.id)))
					recentApps.push(...rest.slice(0, RECENT_APPS_MAX - recentApps.length))
				}

				this.quickApps = recentApps
			},
			recordRecentApp(appId) {
				const id = String(appId ?? '')
				if (!id) return
				if (!this.getRecentAppsStorageKey()) return
				const now = Date.now()
				const list = this.loadRecentApps()

				// 去重 + 更新为最新，按 usedAt 倒序保留最多 8 个
				const next = list
					.filter((x) => x && x.appId != null)
					.map((x) => ({ appId: String(x.appId), usedAt: Number(x.usedAt) || 0 }))
					.filter((x) => x.appId !== id)
				next.unshift({ appId: id, usedAt: now })
				next.sort((a, b) => (b.usedAt || 0) - (a.usedAt || 0))
				this.saveRecentApps(next.slice(0, RECENT_APPS_MAX))
				this.refreshQuickApps()
			},
			async fetchLaunchpadApps() {
				this.launchpadLoading = true
				try {
					const token = getToken()
					if (!token) {
						this.quickApps = []
						this.allApps = []
						this.categories = [{ id: 'recent', name: '全部应用' }]
						this.activeCategoryId = 'recent'
						return
					}

					const res = await getLaunchpadApps()
					const items = Array.isArray(res && res.items) ? res.items : []
					const activeItems = items.filter((i) => i && i.is_active !== false)

					const appList = activeItems.map((it) => {
						const categoryId = it.category_id == null || it.category_id === '' ? 'uncat' : String(it.category_id)
						return {
							id: it.app_id,
							name: it.app_name,
							// 与聊天列表 SystemAvatar 保持一致
							iconPath: '/static/icons/application.svg',
							iconBg: getGradientBgByName(it.app_name),
							category: categoryId,
							categoryName: it.category_name || '未分类',
							description: it.description || '',
							protocolType: it.protocol_type,
							mappedKey: it.mapped_key,
							mappedEmail: it.mapped_email,
							isActive: it.is_active
						}
					})

					this.allApps = appList

					// 从本地最近列表拼出顶部“最近使用”
					const recentList = this.loadRecentApps()
						.filter((x) => x && x.appId != null)
						.map((x) => ({ appId: String(x.appId), usedAt: Number(x.usedAt) || 0 }))
						.sort((a, b) => (b.usedAt || 0) - (a.usedAt || 0))

					const appById = new Map(appList.map((a) => [String(a.id), a]))
					const recentApps = []
					const recentSeen = new Set()
					for (const r of recentList) {
						const id = String(r.appId || '')
						if (!id || recentSeen.has(id)) continue
						if (!appById.has(id)) continue
						recentSeen.add(id)
						recentApps.push(appById.get(id))
						if (recentApps.length >= RECENT_APPS_MAX) break
					}

					// 不足 8 个时，用接口里的其他应用补齐（但 recents 仍保持按时间倒序）
					if (recentApps.length < RECENT_APPS_MAX) {
						const rest = appList.filter((a) => !recentSeen.has(String(a.id)))
						recentApps.push(...rest.slice(0, RECENT_APPS_MAX - recentApps.length))
					}

					this.quickApps = recentApps

					const catMap = new Map()
					for (const a of appList) {
						if (!catMap.has(a.category)) {
							catMap.set(a.category, { id: a.category, name: a.categoryName || '未分类' })
						}
					}

					this.categories = [{ id: 'recent', name: '全部应用' }, ...Array.from(catMap.values())]
					this.activeCategoryId = 'recent'
				} catch (e) {
					// utils/api.js 的 request 已经做了网络、401/403 登录态提示
					uni.showToast({ title: '加载应用失败', icon: 'none' })
				} finally {
					this.launchpadLoading = false
				}
			},
			loadCurrentUser() {
				try {
					const raw = uni.getStorageSync(USER_KEY)
					if (raw && typeof raw === 'object') {
						this.currentUser = {
							name: raw.name || raw.nickname || '',
							id: String(raw.id ?? raw.user_id ?? ''),
							avatar: raw.avatar || raw.avatar_url || ''
						}
					}
				} catch (e) {}
			},
			onAvatarClick() {
				uni.navigateTo({ url: '/pages/profile/index' })
			},
			onSearch() {
				uni.navigateTo({ url: '/pages/search-center/index' })
			},

			// 先清空再设锚点，避免同 id 时不滚动（与 pages/chat/index.vue 一致）
			scrollCategoryTabIntoView(catIdx) {
				const idx = Number(catIdx)
				if (!Number.isFinite(idx) || idx < 0) return
				const anchor = 'cat-tab-' + idx
				this.scrollIntoTabId = ''
				this.$nextTick(() => {
					this.scrollIntoTabId = anchor
					setTimeout(() => {
						this.scrollIntoTabId = anchor
					}, 50)
				})
			},

			onCategoryTabClick(catIdx) {
				const cat = this.categories[catIdx]
				if (!cat) return
				this.activeCategoryId = cat.id
				this.scrollCategoryTabIntoView(catIdx)
			},

			// swiper 滑动切换分类 -> 同步更新 Tab 高亮
			onSwiperChange(e) {
				const idx = e && e.detail ? e.detail.current : 0
				const cat = this.categories[idx]
				if (cat) this.activeCategoryId = cat.id
				this.scrollCategoryTabIntoView(idx)
			},

			// 根据分类 id 获取该页要渲染的应用列表
			getAppsByCategory(catId) {
				const active = String(catId || '')
				if (active === 'recent') return this.allApps
				const list = this.allApps.filter((a) => String(a.category || '') === active)
				return list.length ? list : this.allApps
			},

			async openApp(app) {
				if (!app || !app.id) return
				uni.showLoading({ title: '打开中...' })
				try {
					const res = await ssoLogin(app.id)
					const redirectUrl = res && (res.redirect_url || res.redirectUrl)
					if (!redirectUrl) {
						uni.showToast({ title: '打开失败', icon: 'none' })
						return
					}

					// 登录成功并获得 redirect_url 后，把该应用记录为最新使用
					this.recordRecentApp(app.id)

					const pageUrl =
						'/pages/webview/index?url=' +
						encodeURIComponent(redirectUrl) +
						'&title=' +
						encodeURIComponent(app.name || '应用')
					uni.navigateTo({ url: pageUrl })
				} catch (e) {
					uni.showToast({ title: '打开失败', icon: 'none' })
				} finally {
					uni.hideLoading()
				}
			}
		}
	}
</script>

<style scoped>
	.app-center-page {
		min-height: 100vh;
		height: 100vh;
		display: flex;
		flex-direction: column;
		background: #fff;
	}

	.app-center-scroll {
		flex: 1;
		min-height: 0;
		height: 0;
		/* 与消息/通讯录一致：用框架 tabBar 区域高度，避免重复加 safe-area 造成大块白底或与原生 Tab 错位遮挡 */
		padding-bottom: var(--window-bottom, 50px);
		box-sizing: border-box;
	}

	/* 顶部安全区：与消息/通讯录页面 custom-header 对齐 */
	.custom-header {
		display: flex;
		align-items: center;
		justify-content: space-between;
		padding: 24rpx 24rpx 24rpx 32rpx;
		padding-top: 88rpx;
		padding-top: max(88rpx, calc(24rpx + constant(safe-area-inset-top)));
		padding-top: max(88rpx, calc(24rpx + env(safe-area-inset-top)));
		background: #fff;
		border-bottom: 1rpx solid #eee;
	}
	.header-left {
		display: flex;
		align-items: center;
		flex: 1;
		min-width: 0;
	}
	.org-info {
		margin-left: 24rpx;
		display: flex;
		flex-direction: column;
		min-width: 0;
	}
	.user-name {
		font-size: 32rpx;
		font-weight: 600;
		color: #111827;
	}
	.header-right {
		display: flex;
		align-items: center;
		gap: 24rpx;
	}
	.icon-btn {
		width: 64rpx;
		height: 64rpx;
		display: flex;
		align-items: center;
		justify-content: center;
	}
	.icon-img {
		width: 44rpx;
		height: 44rpx;
		opacity: 0.85;
	}

	/* 最近使用：整体与顶栏拉开一点距离 */
	.recent-section {
		padding-top: 28rpx;
	}

	/* 常用应用 4 列网格 */
	.quick-grid {
		display: flex;
		flex-wrap: wrap;
		gap: 24rpx;
		/* 与顶部自定义顶栏的头像左侧对齐：顶栏左 padding = 32rpx */
		padding: 24rpx 24rpx 40rpx 32rpx;
	}

	.app-tile {
		width: calc((100% - 24rpx * 3) / 4);
		display: flex;
		flex-direction: column;
		align-items: center;
		box-sizing: border-box;
	}

	.tile-icon {
		width: 96rpx;
		height: 96rpx;
		border-radius: 22rpx;
		display: flex;
		align-items: center;
		justify-content: center;
		position: relative;
	}
	.tile-icon-img {
		width: 52rpx;
		height: 52rpx;
		/* 与聊天列表 SystemAvatar 一致：确保图标居中显示为白色 */
		filter: brightness(0) invert(1);
	}

	.tile-badge {
		position: absolute;
		bottom: 12rpx;
		left: 12rpx;
		height: 28rpx;
		padding: 0 10rpx;
		border-radius: 14rpx;
		font-size: 20rpx;
		line-height: 28rpx;
		font-weight: 600;
	}

	.tile-name {
		margin-top: 14rpx;
		font-size: 26rpx;
		color: #111827;
		text-align: center;
		width: 100%;
		overflow: hidden;
		text-overflow: ellipsis;
		white-space: nowrap;
	}

	.tile-name-2 {
		white-space: normal;
		line-height: 1.2;
		display: -webkit-box;
		-webkit-line-clamp: 2;
		-webkit-box-orient: vertical;
		overflow: hidden;
	}

	/* 全部应用（与上方「最近使用」拉开间距） */
	.all-section {
		/* 与顶部自定义顶栏的头像左侧对齐：顶栏左 padding = 32rpx */
		padding: 32rpx 24rpx 0 32rpx;
	}
	.section-title {
		font-size: 34rpx;
		font-weight: 700;
		color: #111827;
		/* 与顶部自定义顶栏的头像左侧对齐：顶栏左 padding = 32rpx */
		padding-left: 32rpx;
		margin-bottom: 18rpx;
	}

	/* 分类 Tab 行 */
	.category-bar {
		display: flex;
		align-items: center;
		gap: 16rpx;
	}
	.category-scroll {
		flex: 1;
		min-width: 0;
	}
	.category-list {
		display: flex;
		align-items: flex-end;
		white-space: nowrap;
		/* 最后一项滚到最右时不贴边裁切 */
		padding-right: 24rpx;
		box-sizing: border-box;
	}
	.category-item {
		display: flex;
		flex-direction: column;
		align-items: center;
		padding: 0 22rpx;
		flex: 0 0 auto; /* 防止 flex 在容器宽度不足时压缩导致文字换行 */
	}
	.category-name {
		font-size: 28rpx;
		color: #6b7280;
		white-space: nowrap; /* 不允许换行，过长则由外层横向 scroll-view 滚动显示 */
	}
	.category-item.active .category-name {
		color: #1f6feb;
		font-weight: 600;
	}
	.category-underline {
		width: 56rpx;
		height: 6rpx;
		border-radius: 8rpx;
		background: #1f6feb;
		margin-top: 12rpx;
	}

	.apps-swiper {
		width: 100%;
		min-height: 600rpx; /* swiper 需要固定/最小高度才能正常展示 */
	}

	/* 全部应用宫格 */
	.apps-grid {
		display: flex;
		flex-wrap: wrap;
		gap: 24rpx;
		padding: 24rpx 24rpx 0;
	}

</style>
