<template>
	<view class="my-space-page">
		<view class="top-safe" :style="{ height: menuButtonInfo.top + 'px' }"></view>
		<view class="float-bar">
			<view class="home-back" @tap="back">
				<text class="home-back-icon">‹</text>
				<text>返回资料</text>
			</view>
		</view>

		<view class="space-hero">
			<image class="hero-avatar-img" v-if="profile.avatarUrl" :src="profile.avatarUrl" mode="aspectFill"></image>
			<view class="hero-avatar" v-else>{{ profile.avatarText || '我' }}</view>
			<view class="hero-main">
				<view class="hero-title-row">
					<view class="hero-title">我的个人空间</view>
					<view class="publish-btn" @tap="openComposer">+ 发动态</view>
				</view>
				<view class="hero-sub">{{ profile.anonymousName || '半匿名漂流者' }} · {{ profile.currentMode === 'e' ? '轻轻热闹' : '安静陪伴' }}</view>
			</view>
		</view>

		<view class="moment-empty" v-if="!moments.length && !loadingMoments">还没有动态，发一条让同频的人认识你</view>
		<view class="moment-card" v-for="item in moments" :key="item.id">
			<view class="moment-top">
				<text class="moment-time">{{ momentTime(item.createTime) }}</text>
				<text class="moment-state blocked" v-if="item.localState === 'failed'">{{ item.failTip || '发布失败' }}</text>
				<text class="moment-state auditing" v-else-if="item.status === 0">审核中</text>
				<text class="moment-state blocked" v-else-if="item.status === 2">未通过审核</text>
				<text class="moment-del" @tap="removeMoment(item)">删除</text>
			</view>
			<view class="moment-text" v-if="item.content">{{ item.content }}</view>
			<view class="moment-grid" v-if="item.imageList && item.imageList.length" :class="'g' + item.imageList.length">
				<image v-for="(img, idx) in item.imageList" :key="idx" :src="img" mode="aspectFill" @tap="previewMomentImages(item, idx)"></image>
			</view>
			<view class="moment-video" v-if="item.videoUrl" @tap="playMomentVideo(item)">
				<image class="moment-video-poster" v-if="item.videoPoster" :src="item.videoPoster" mode="aspectFill"></image>
				<view class="moment-video-holder" v-else></view>
				<view class="moment-play">▶</view>
			</view>
		</view>
		<view class="moment-more" v-if="loadingMoments">加载中...</view>
		<view class="moment-more" v-else-if="hasMoreMoments && moments.length" @tap="loadMoments(false)">查看更早的动态</view>
		<view class="moment-more" v-else-if="!hasMoreMoments && moments.length">没有更多动态了</view>

		<view class="composer-mask" v-if="showComposer" @tap="closeComposer">
			<view class="composer" @tap.stop>
				<view class="composer-title">发动态</view>
				<textarea class="composer-input" v-model="composeText" maxlength="1000"
					placeholder="此刻想说点什么..." :show-confirm-bar="false"></textarea>
				<view class="composer-grid">
					<view class="composer-thumb" v-for="(img, idx) in composeImages" :key="idx" @tap="retryComposeImage(img)">
						<image :src="img.local" mode="aspectFill"></image>
						<view class="thumb-state" v-if="img.status === 'uploading'">上传中</view>
						<view class="thumb-state failed" v-else-if="img.status === 'failed'">失败·点我重试</view>
						<view class="thumb-del" @tap.stop="removeComposeImage(idx)">×</view>
					</view>
					<view class="composer-thumb" v-if="composeVideo" @tap="retryComposeVideo">
						<image v-if="composeVideo.poster" :src="composeVideo.poster" mode="aspectFill"></image>
						<view class="thumb-video-mark">▶ 视频</view>
						<view class="thumb-state" v-if="composeVideo.status === 'uploading'">上传中</view>
						<view class="thumb-state failed" v-else-if="composeVideo.status === 'failed'">失败·点我重试</view>
						<view class="thumb-del" @tap.stop="composeVideo = null">×</view>
					</view>
					<view class="composer-add" v-if="canAddMedia" @tap="chooseMomentMedia">＋</view>
				</view>
				<view class="composer-tip">最多 5 张图片，或 1 个视频 · 内容需通过审核</view>
				<view class="composer-submit" :class="{ disabled: publishing }" @tap="submitMoment">发布</view>
			</view>
		</view>
	</view>
</template>

<script>
	import { getIeProfile, pageIeMoments, publishIeMoment, deleteIeMoment } from '@/common/ieApi.js'
	import tui from '@/common/httpRequest.js'

	export default {
		data() {
			return {
				menuButtonInfo: { top: 44 },
				profile: {},
				moments: [],
				momentPage: 1,
				hasMoreMoments: true,
				loadingMoments: false,
				showComposer: false,
				composeText: '',
				composeImages: [],
				composeVideo: null,
				publishing: false
			}
		},
		computed: {
			canAddMedia() {
				if (this.composeVideo) return false
				return this.composeImages.length < 5
			}
		},
		onLoad() {
			if (uni.getMenuButtonBoundingClientRect) this.menuButtonInfo = uni.getMenuButtonBoundingClientRect()
			this.loadProfile()
			this.loadMoments(true)
		},
		onReachBottom() {
			this.loadMoments(false)
		},
		async onPullDownRefresh() {
			try {
				await Promise.all([
					this.loadProfile(),
					this.loadMoments(true, true)
				])
			} finally {
				uni.stopPullDownRefresh()
			}
		},
		methods: {
			back() {
				uni.navigateBack({ fail: () => uni.redirectTo({ url: '/package1/ieBrowser/universe' }) })
			},
			async loadProfile() {
				const profile = await getIeProfile()
				if (profile) this.profile = profile
			},
			async loadMoments(reset, force = false) {
				if (this.loadingMoments && !force) return
				if (!reset && !this.hasMoreMoments) return
				this.loadingMoments = true
				try {
					const page = reset ? 1 : this.momentPage
					const result = await pageIeMoments(null, page, 10)
					const records = (result && result.records) || []
					this.moments = reset ? records : this.moments.concat(records)
					this.hasMoreMoments = records.length >= 10
					this.momentPage = page + 1
				} finally {
					this.loadingMoments = false
				}
			},
			momentTime(timeStr) {
				if (!timeStr) return ''
				const time = new Date(String(timeStr).replace(/-/g, '/')).getTime()
				if (!time) return ''
				const diff = Date.now() - time
				if (diff < 60000) return '刚刚'
				if (diff < 3600000) return Math.floor(diff / 60000) + ' 分钟前'
				if (diff < 86400000) return Math.floor(diff / 3600000) + ' 小时前'
				if (diff < 172800000) return '昨天'
				const d = new Date(time)
				return (d.getMonth() + 1) + '月' + d.getDate() + '日'
			},
			previewMomentImages(item, index) {
				uni.previewImage({ urls: item.imageList || [], current: item.imageList[index] })
			},
			playMomentVideo(item) {
				if (item.status === 0) {
					uni.showToast({ title: '视频审核中，通过后对方可见', icon: 'none' })
				}
				if (!item.videoUrl) return
				uni.navigateTo({ url: '/package1/ieBrowser/videoPreview?url=' + encodeURIComponent(item.videoUrl) })
			},
			removeMoment(item) {
				if (String(item.id).indexOf('local-') === 0) {
					this.moments = this.moments.filter(m => m.id !== item.id)
					return
				}
				uni.showModal({
					title: '删除动态',
					content: '删除后无法恢复，确定删除吗？',
					success: async (res) => {
						if (!res.confirm) return
						await deleteIeMoment(item.id)
						this.moments = this.moments.filter(m => m.id !== item.id)
					}
				})
			},
			openComposer() {
				this.showComposer = true
			},
			closeComposer() {
				this.showComposer = false
			},
			removeComposeImage(index) {
				this.composeImages.splice(index, 1)
			},
			addComposeImages(paths) {
				const items = (paths || [])
					.filter(p => !!p)
					.slice(0, 5 - this.composeImages.length)
					.map(p => ({ local: p, url: '', status: 'uploading' }))
				if (!items.length) return
				this.composeImages = this.composeImages.concat(items)
				items.forEach(item => this.uploadComposeImage(item))
			},
			async uploadComposeImage(item) {
				item.status = 'uploading'
				try {
					item.url = await this.silentUpload(item.local)
					item.status = 'done'
				} catch (e) {
					item.status = 'failed'
				}
			},
			retryComposeImage(item) {
				if (item.status === 'failed') this.uploadComposeImage(item)
			},
			async uploadComposeVideo() {
				const video = this.composeVideo
				if (!video) return
				video.status = 'uploading'
				try {
					video.url = await this.silentUpload(video.local)
					if (video.poster) {
						try { video.posterUrl = await this.silentUpload(video.poster) } catch (e) { video.posterUrl = '' }
					}
					video.status = 'done'
				} catch (e) {
					video.status = 'failed'
				}
			},
			retryComposeVideo() {
				if (this.composeVideo && this.composeVideo.status === 'failed') this.uploadComposeVideo()
			},
			chooseMomentMedia() {
				const hasImages = this.composeImages.length > 0
				if (!uni.chooseMedia) {
					uni.chooseImage({
						count: 5 - this.composeImages.length,
						success: (res) => {
							this.addComposeImages(res.tempFilePaths || [])
						}
					})
					return
				}
				uni.chooseMedia({
					count: hasImages ? 5 - this.composeImages.length : 5,
					mediaType: hasImages ? ['image'] : ['image', 'video'],
					maxDuration: 60,
					success: (res) => {
						const files = res.tempFiles || []
						if (!files.length) return
						if (res.type === 'video') {
							const file = files[0]
							if (file.size > 100 * 1024 * 1024) {
								uni.showToast({ title: '视频不能超过100MB，请先剪辑', icon: 'none' })
								return
							}
							if (file.duration && file.duration > 61) {
								uni.showToast({ title: '视频不能超过60秒', icon: 'none' })
								return
							}
							this.composeVideo = {
								local: file.tempFilePath,
								poster: file.thumbTempFilePath || '',
								size: file.size,
								url: '',
								posterUrl: '',
								status: 'uploading'
							}
							this.uploadComposeVideo()
							return
						}
						const oversize = files.find(f => f.size > 10 * 1024 * 1024)
						if (oversize) {
							uni.showToast({ title: '单张图片不能超过10MB', icon: 'none' })
							return
						}
						this.addComposeImages(files.map(f => f.tempFilePath))
					}
				})
			},
			silentUpload(filePath) {
				return new Promise((resolve, reject) => {
					uni.uploadFile({
						url: tui.interfaceUrl() + '/upload/file',
						filePath,
						name: 'file',
						timeout: 300000,
						header: { accessToken: uni.getStorageSync('hiver_token') },
						success: (res) => {
							try {
								const d = JSON.parse(String(res.data || '{}').replace(/\ufeff/g, ''))
								const fileObj = d.result !== undefined ? d.result : d.data
								const url = typeof fileObj === 'string' ? fileObj : (fileObj && (fileObj.url || fileObj.fileUrl || fileObj.path || fileObj.fullPath))
								if (d.code % 100 === 0 && url) resolve(url)
								else reject(new Error(d.message || '上传失败'))
							} catch (e) {
								reject(e)
							}
						},
						fail: () => reject(new Error('上传失败'))
					})
				})
			},
			async waitComposeUploads(images, video) {
				const uploading = () => images.some(item => item.status === 'uploading') ||
					(video && video.status === 'uploading')
				while (uploading()) {
					await new Promise(resolve => setTimeout(resolve, 500))
				}
				if (images.some(item => item.status !== 'done')) throw new Error('图片上传失败')
				if (video && video.status !== 'done') throw new Error('视频上传失败')
			},
			async submitMoment() {
				if (this.publishing) return
				const content = this.composeText.trim()
				if (!content && !this.composeImages.length && !this.composeVideo) {
					uni.showToast({ title: '写点什么或选张图片吧', icon: 'none' })
					return
				}
				const images = this.composeImages
				const video = this.composeVideo
				if (images.some(item => item.status === 'failed') || (video && video.status === 'failed')) {
					uni.showToast({ title: '有图片/视频上传失败，点缩略图重试', icon: 'none' })
					return
				}
				this.publishing = true
				const localCard = {
					id: 'local-' + Date.now(),
					content,
					imageList: images.map(item => item.local),
					videoUrl: video ? video.local : '',
					videoPoster: video ? video.poster : '',
					status: 1,
					localState: 'publishing',
					failTip: '',
					createTime: this.formatNow()
				}
				this.moments.unshift(localCard)
				this.showComposer = false
				this.composeText = ''
				this.composeImages = []
				this.composeVideo = null
				this.publishing = false
				uni.showToast({ title: '已发布', icon: 'none' })
				try {
					await this.waitComposeUploads(images, video)
					const payload = { content, images: images.map(item => item.url) }
					if (video) {
						payload.videoUrl = video.url
						payload.videoPoster = video.posterUrl || ''
					}
					const moment = await publishIeMoment(payload)
					if (!moment) throw new Error('发布失败，请稍后再试')
					const index = this.moments.findIndex(m => m.id === localCard.id)
					if (index >= 0) {
						moment.imageList = localCard.imageList.length ? localCard.imageList : moment.imageList
						moment.videoPoster = localCard.videoPoster || moment.videoPoster
						this.moments.splice(index, 1, moment)
					}
				} catch (e) {
					localCard.localState = 'failed'
					localCard.failTip = (e && e.message) || '发布失败'
					uni.showToast({ title: localCard.failTip, icon: 'none' })
				}
			},
			formatNow() {
				const d = new Date()
				const pad = n => (n < 10 ? '0' + n : '' + n)
				return d.getFullYear() + '-' + pad(d.getMonth() + 1) + '-' + pad(d.getDate()) + ' ' +
					pad(d.getHours()) + ':' + pad(d.getMinutes()) + ':' + pad(d.getSeconds())
			}
		}
	}
</script>

<style lang="scss" scoped>
	page { background: #f7f9ff; }
	.my-space-page { min-height: 100vh; padding: 0 32rpx 80rpx; box-sizing: border-box; color: #161b2e; background: radial-gradient(circle at 50% 8%, rgba(169,255,231,.36), transparent 320rpx), radial-gradient(circle at 86% 30%, rgba(255,184,209,.2), transparent 340rpx), linear-gradient(180deg, #fbfdff, #eef4ff 62%, #fff4e8); }
	.float-bar { position: relative; z-index: 5; display: flex; align-items: center; }
	.home-back { display: flex; align-items: center; height: 58rpx; padding: 0 22rpx 0 12rpx; border: 1rpx solid rgba(255,255,255,.88); border-radius: 999rpx; color: rgba(22,27,46,.66); background: rgba(255,255,255,.66); backdrop-filter: blur(20rpx); box-shadow: 0 14rpx 36rpx rgba(96,112,160,.12), inset 0 1rpx 0 rgba(255,255,255,.95); font-size: 23rpx; font-weight: 800; }
	.home-back-icon { margin-right: 6rpx; padding-bottom: 6rpx; font-size: 40rpx; line-height: 50rpx; font-weight: 400; }
	.publish-btn { flex-shrink: 0; height: 54rpx; line-height: 54rpx; padding: 0 20rpx; border-radius: 999rpx; color: #11162a; background: #a9ffe7; font-size: 22rpx; font-weight: 900; box-shadow: 0 12rpx 28rpx rgba(96,200,170,.24); }
	.space-hero { display: flex; align-items: center; margin-top: 28rpx; padding: 30rpx; border-radius: 38rpx; background: rgba(255,255,255,.66); border: 1rpx solid rgba(255,255,255,.82); box-shadow: 0 22rpx 70rpx rgba(96,112,160,.14); }
	.hero-avatar, .hero-avatar-img { flex-shrink: 0; width: 112rpx; height: 112rpx; margin-right: 24rpx; border-radius: 50%; }
	.hero-avatar { line-height: 112rpx; text-align: center; color: #11162a; background: linear-gradient(145deg, #effffb, #a9ffe7); font-size: 38rpx; font-weight: 900; }
	.hero-main { flex: 1; min-width: 0; }
	.hero-title-row { display: flex; align-items: center; justify-content: space-between; gap: 16rpx; }
	.hero-title { font-size: 36rpx; font-weight: 900; }
	.hero-sub { margin-top: 10rpx; color: rgba(22,27,46,.48); font-size: 23rpx; }
	.moment-empty { margin-top: 60rpx; text-align: center; color: rgba(22,27,46,.4); font-size: 25rpx; }
	.moment-card { margin-top: 24rpx; padding: 26rpx; border-radius: 28rpx; background: rgba(255,255,255,.85); border: 1rpx solid rgba(255,255,255,.9); box-shadow: 0 12rpx 32rpx rgba(96,112,160,.08); }
	.moment-top { display: flex; align-items: center; }
	.moment-time { flex: 1; color: rgba(22,27,46,.42); font-size: 21rpx; }
	.moment-state { margin-right: 16rpx; padding: 4rpx 14rpx; border-radius: 999rpx; font-size: 20rpx; font-weight: 700; }
	.moment-state.auditing { color: #b07b1f; background: rgba(255,196,87,.18); }
	.moment-state.blocked { color: #d2486a; background: rgba(255,107,146,.14); }
	.moment-del { color: rgba(22,27,46,.38); font-size: 22rpx; padding: 4rpx 8rpx; }
	.moment-text { margin-top: 14rpx; font-size: 27rpx; line-height: 42rpx; word-break: break-all; }
	.moment-grid { display: flex; flex-wrap: wrap; margin-top: 16rpx; }
	.moment-grid image { width: 196rpx; height: 196rpx; margin: 0 10rpx 10rpx 0; border-radius: 16rpx; background: rgba(22,27,46,.05); }
	.moment-grid.g1 image { width: 400rpx; height: 400rpx; border-radius: 22rpx; }
	.moment-grid.g2 image { width: 300rpx; height: 300rpx; }
	.moment-video { position: relative; margin-top: 16rpx; width: 440rpx; height: 290rpx; border-radius: 22rpx; overflow: hidden; background: #1a2034; }
	.moment-video-poster, .moment-video-holder { width: 100%; height: 100%; }
	.moment-play { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); width: 84rpx; height: 84rpx; line-height: 84rpx; text-align: center; border-radius: 50%; color: #fff; background: rgba(0,0,0,.45); font-size: 32rpx; }
	.moment-more { margin-top: 26rpx; text-align: center; color: rgba(22,27,46,.36); font-size: 22rpx; padding: 12rpx 0; }
	.composer-mask { position: fixed; inset: 0; z-index: 120; display: flex; align-items: flex-end; background: rgba(13,17,32,.5); backdrop-filter: blur(10rpx); }
	.composer { width: 100%; padding: 36rpx 32rpx calc(40rpx + env(safe-area-inset-bottom)); border-radius: 40rpx 40rpx 0 0; background: #ffffff; box-sizing: border-box; }
	.composer-title { font-size: 32rpx; font-weight: 800; text-align: center; }
	.composer-input { width: 100%; height: 200rpx; margin-top: 24rpx; padding: 22rpx; border-radius: 22rpx; background: #f4f6fc; font-size: 27rpx; box-sizing: border-box; }
	.composer-grid { display: flex; flex-wrap: wrap; margin-top: 20rpx; }
	.composer-thumb { position: relative; width: 150rpx; height: 150rpx; margin: 0 14rpx 14rpx 0; border-radius: 16rpx; overflow: hidden; background: #1a2034; }
	.composer-thumb image { width: 100%; height: 100%; }
	.thumb-del { position: absolute; right: 0; top: 0; width: 40rpx; height: 40rpx; line-height: 36rpx; text-align: center; color: #fff; background: rgba(0,0,0,.55); border-radius: 0 0 0 16rpx; font-size: 26rpx; }
	.thumb-video-mark { position: absolute; left: 0; bottom: 0; right: 0; padding: 4rpx 0; text-align: center; color: #fff; background: rgba(0,0,0,.45); font-size: 20rpx; }
	.thumb-state { position: absolute; left: 0; top: 0; right: 0; bottom: 0; display: flex; align-items: center; justify-content: center; color: #fff; background: rgba(0,0,0,.42); font-size: 20rpx; }
	.thumb-state.failed { color: #ffd9e2; background: rgba(160,30,60,.55); }
	.composer-add { width: 150rpx; height: 150rpx; line-height: 146rpx; text-align: center; border-radius: 16rpx; border: 2rpx dashed rgba(22,27,46,.18); color: rgba(22,27,46,.34); font-size: 52rpx; box-sizing: border-box; }
	.composer-tip { margin-top: 8rpx; color: rgba(22,27,46,.38); font-size: 21rpx; }
	.composer-submit { margin-top: 28rpx; height: 92rpx; line-height: 92rpx; text-align: center; border-radius: 999rpx; color: #11162a; background: linear-gradient(135deg, #a9ffe7, #7be3c8); font-size: 30rpx; font-weight: 800; box-shadow: 0 14rpx 32rpx rgba(96,200,170,.32); }
	.composer-submit.disabled { opacity: .6; }
</style>
