<template>
	<view class="chat-page">
		<view class="nav" :style="{ paddingTop: statusBarTop + 'px' }">
			<view class="back" @tap="back"><uni-icons type="left" size="24" color="#15362f"></uni-icons></view>
			<view class="nav-main">
				<view class="nav-title">校园圈聊天</view>
				<view class="nav-sub">文字和图片会进行内容审核</view>
			</view>
		</view>

		<view class="post-card" v-if="session" @tap="goPost">
			<image class="cover" v-if="session.displayCover" :src="session.displayCover" mode="aspectFill"></image>
			<view class="cover no-cover" v-else>圈</view>
			<view class="post-main">
				<view class="post-title">{{session.displayTitle || '校园圈内容'}}</view>
				<view class="post-sub">{{session.postType === 'partner' ? '找搭子' : '校园墙'}}</view>
			</view>
			<view class="link">查看 ›</view>
		</view>

		<scroll-view
			class="message-scroll"
			scroll-y
			:scroll-into-view="scrollIntoView"
			:scroll-with-animation="true"
			:style="{ paddingTop: contentTop + 'px' }"
			@scrolltoupper="loadOlder"
		>
			<view class="load-tip" v-if="loadingOlder">加载中...</view>
			<view class="safe-tip">请勿发送涉黄涉暴、辱骂诈骗等内容，审核未通过的消息不会送达对方。</view>
			<view class="message-row" :class="{ mine: item.mine }" v-for="item in messages" :key="item.id" :id="'msg-' + item.id">
				<view class="avatar">{{item.mine ? '我' : 'TA'}}</view>
				<view class="message-main">
					<view class="bubble text-bubble" :class="{ failed: item.localState === 'failed' }" v-if="item.messageType == 1">{{item.content}}</view>
					<view class="bubble image-bubble" :class="{ failed: item.localState === 'failed' }" v-else>
						<image :src="item.content" mode="aspectFill" @tap="previewImage(item.content)"></image>
					</view>
					<view class="message-status" v-if="item.mine && item.localState">{{statusText(item)}}</view>
				</view>
			</view>
			<view id="chat-bottom" class="bottom-anchor"></view>
		</scroll-view>

		<view class="input-bar">
			<view class="image-btn" @tap="chooseImage"><uni-icons type="image" size="24" color="#61736e"></uni-icons></view>
			<input v-model.trim="draft" confirm-type="send" placeholder="请输入消息..." @confirm="sendText" />
			<view class="send-btn" :class="{ disabled: sending }" @tap="sendText">{{sending ? '发送中' : '发送'}}</view>
		</view>
	</view>
</template>

<script>
	import {
		getCampusChatSession,
		pageCampusChatMessages,
		sendCampusChatMessage,
		uploadCampusImage
	} from '@/common/campusApi.js'

	export default {
		data() {
			return {
				statusBarTop: 24,
				sessionId: '',
				session: null,
				messages: [],
				pageNum: 1,
				pageSize: 20,
				totalPages: 1,
				loadingOlder: false,
				draft: '',
				sending: false,
				scrollIntoView: 'chat-bottom',
				selfId: String(uni.getStorageSync('id') || '')
			}
		},
		computed: {
			contentTop() {
				return this.statusBarTop + uni.upx2px(220)
			}
		},
		onLoad(options = {}) {
			this.sessionId = options.sessionId || ''
			if (uni.getMenuButtonBoundingClientRect) this.statusBarTop = uni.getMenuButtonBoundingClientRect().top || this.statusBarTop
			this.load()
		},
		methods: {
			back() { uni.navigateBack() },
			load() {
				if (!this.sessionId) return
				getCampusChatSession(this.sessionId).then(session => {
					this.session = session
				})
				this.loadMessages(true)
			},
			loadMessages(reset) {
				if (reset) {
					this.pageNum = 1
					this.totalPages = 1
				}
				return pageCampusChatMessages(this.sessionId, this.pageNum, this.pageSize).then(page => {
					const records = page && (page.records || page.content) ? (page.records || page.content) : []
					const normalized = records.reverse().map(this.normalizeMessage)
					this.totalPages = Number(page && (page.pages || page.totalPages)) || 1
					this.messages = reset ? normalized : normalized.concat(this.messages)
					this.scrollToBottom()
					if (reset) uni.$emit('campusUnreadChange')
				})
			},
			loadOlder() {
				if (this.loadingOlder || this.pageNum >= this.totalPages) return
				this.loadingOlder = true
				this.pageNum += 1
				this.loadMessages(false).finally(() => {
					this.loadingOlder = false
				})
			},
			normalizeMessage(item) {
				return {
					...item,
					mine: String(item.senderId) === this.selfId,
					localState: item.localState || ''
				}
			},
			sendText() {
				if (this.sending) return
				const text = this.draft
				if (!text) return
				const clientMsgId = 'local_' + Date.now()
				this.draft = ''
				this.appendLocal({ id: clientMsgId, clientMsgId, messageType: 1, content: text })
				this.sending = true
				sendCampusChatMessage({ sessionId: this.sessionId, messageType: 1, content: text, clientMsgId }).then(message => {
					this.replaceLocal(clientMsgId, message)
				}).catch(err => {
					this.markFailed(clientMsgId, (err && err.message) || '发送失败')
				}).finally(() => {
					this.sending = false
				})
			},
			chooseImage() {
				if (this.sending) return
				uni.chooseImage({
					count: 1,
					sizeType: ['compressed'],
					success: async res => {
						const path = res.tempFilePaths && res.tempFilePaths[0]
						if (!path) return
						const clientMsgId = 'local_' + Date.now()
						this.appendLocal({ id: clientMsgId, clientMsgId, messageType: 2, content: path })
						this.sending = true
						try {
							const url = await uploadCampusImage(path)
							const message = await sendCampusChatMessage({ sessionId: this.sessionId, messageType: 2, content: url, clientMsgId })
							this.replaceLocal(clientMsgId, message)
						} catch (e) {
							this.markFailed(clientMsgId, (e && e.message) || '图片发送失败')
						} finally {
							this.sending = false
						}
					}
				})
			},
			appendLocal(message) {
				this.messages.push({ ...message, mine: true, localState: 'sending', senderId: this.selfId })
				this.scrollToBottom()
			},
			replaceLocal(clientMsgId, message) {
				const index = this.messages.findIndex(item => item.clientMsgId === clientMsgId)
				const normalized = this.normalizeMessage({ ...message, localState: '' })
				if (index > -1) this.$set(this.messages, index, normalized)
				else this.messages.push(normalized)
				this.scrollToBottom()
			},
			markFailed(clientMsgId, reason) {
				const item = this.messages.find(row => row.clientMsgId === clientMsgId)
				if (item) {
					item.localState = 'failed'
					item.auditReason = reason
				}
				uni.showToast({ title: reason, icon: 'none', duration: 3000 })
			},
			statusText(item) {
				if (item.localState === 'sending') return '发送中'
				if (item.localState === 'failed') return item.auditReason || '发送失败'
				return ''
			},
			scrollToBottom() {
				this.$nextTick(() => {
					this.scrollIntoView = ''
					this.$nextTick(() => { this.scrollIntoView = 'chat-bottom' })
				})
			},
			previewImage(url) {
				uni.previewImage({ urls: [url] })
			},
			goPost() {
				if (!this.session || !this.session.postId) return
				uni.navigateTo({ url: '/package1/post/postDetail?id=' + this.session.postId + '&source=campus' })
			}
		}
	}
</script>

<style scoped>
	.chat-page { min-height: 100vh; background: #f5faf8; }
	.nav { position: fixed; left: 0; right: 0; top: 0; z-index: 20; display: flex; align-items: center; gap: 16rpx; padding: 14rpx 24rpx; background: rgba(245,250,248,.98); }
	.back { width: 64rpx; height: 64rpx; border-radius: 50%; background: #fff; display: flex; align-items: center; justify-content: center; }
	.nav-title { color: #15362f; font-size: 31rpx; font-weight: 800; }
	.nav-sub { margin-top: 4rpx; color: #7b8c87; font-size: 22rpx; }
	.post-card { position: fixed; left: 24rpx; right: 24rpx; top: 118rpx; z-index: 18; display: flex; align-items: center; gap: 14rpx; padding: 16rpx; border-radius: 24rpx; background: #fff; box-shadow: 0 10rpx 26rpx rgba(39, 76, 70, .08); }
	.cover { width: 82rpx; height: 82rpx; border-radius: 18rpx; background: #e8f7f3; }
	.no-cover { display: flex; align-items: center; justify-content: center; color: #28a889; font-weight: 800; }
	.post-main { flex: 1; min-width: 0; }
	.post-title { font-size: 25rpx; color: #253d37; font-weight: 700; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
	.post-sub, .link { margin-top: 6rpx; color: #83948f; font-size: 22rpx; }
	.message-scroll { height: 100vh; box-sizing: border-box; padding-left: 24rpx; padding-right: 24rpx; padding-bottom: 130rpx; }
	.load-tip, .safe-tip { text-align: center; color: #879691; font-size: 22rpx; padding: 18rpx 0; }
	.safe-tip { margin: 0 8rpx 18rpx; background: #ecf8f4; border-radius: 999rpx; }
	.message-row { display: flex; gap: 12rpx; margin: 18rpx 0; }
	.message-row.mine { flex-direction: row-reverse; }
	.avatar { width: 56rpx; height: 56rpx; line-height: 56rpx; border-radius: 50%; background: #dff8f0; color: #257c69; text-align: center; font-size: 22rpx; }
	.message-main { max-width: 72%; }
	.bubble { padding: 18rpx 22rpx; border-radius: 24rpx; background: #fff; color: #263d38; font-size: 27rpx; line-height: 1.5; box-shadow: 0 8rpx 22rpx rgba(39, 76, 70, .06); }
	.mine .bubble { background: #34c7a2; color: #fff; }
	.bubble.failed { opacity: .55; }
	.image-bubble { padding: 8rpx; }
	.image-bubble image { width: 220rpx; height: 220rpx; border-radius: 18rpx; }
	.message-status { margin-top: 8rpx; color: #9a8a7b; font-size: 21rpx; text-align: right; }
	.bottom-anchor { height: 20rpx; }
	.input-bar { position: fixed; left: 0; right: 0; bottom: 0; z-index: 20; display: flex; align-items: center; gap: 14rpx; padding: 18rpx 24rpx 34rpx; background: #fff; box-shadow: 0 -8rpx 28rpx rgba(31, 67, 59, .08); }
	.image-btn { width: 70rpx; height: 70rpx; border-radius: 50%; background: #f1f6f4; display: flex; align-items: center; justify-content: center; }
	.input-bar input { flex: 1; height: 72rpx; border-radius: 999rpx; background: #f4f8f7; padding: 0 24rpx; font-size: 26rpx; }
	.send-btn { padding: 0 24rpx; height: 72rpx; line-height: 72rpx; border-radius: 999rpx; background: #34c7a2; color: #fff; font-weight: 700; }
	.send-btn.disabled { opacity: .6; }
</style>
