<template>
	<view class="chat-page">
		<view class="chat-header">
			<view class="chat-header-main">
				<view class="back" @click="goBack">
					<image class="header-icon-img" src="/static/icons/back.svg" mode="aspectFit" />
				</view>
				<view class="chat-title-wrap" @click="onTitleClick">
					<view class="chat-title-texts">
						<text class="chat-title">{{ contactTitle }}</text>
					</view>
				</view>
				<view class="header-actions">
					<view class="header-icon" @click="onMore">
						<image class="header-icon-img" src="/static/icons/more.svg" mode="aspectFit" />
					</view>
				</view>
			</view>
		</view>
		<scroll-view
			class="message-list"
			scroll-y
			:scroll-into-view="scrollIntoView"
			scroll-with-animation
			@scrolltoupper="onLoadMore"
		>
			<view v-if="loadingMoreForContact" class="load-more">加载更多...</view>
			<view v-else-if="!messageList.length" class="empty-messages">
				<text class="empty-text">暂无消息，发一句打个招呼吧</text>
			</view>
			<view
				v-for="(msg, index) in messageList"
				:key="msg.id || msg.tempId || index"
			>
				<PrivateMessageBubble
					v-if="msg.type === 'MESSAGE' || msg.type === 'PRIVATE' || !msg.type"
					:msg="msg"
					:sender-name="getSenderName(msg)"
					:sender-id="otherUserId"
					:sender-avatar="contactAvatar"
					:me-name="currentUserName"
					:me-id="currentUserId"
					:me-avatar="currentUserAvatar"
					:show-date-label="shouldShowDateLabel(index)"
					:remind-loading="remindingNotificationId === String(msg.id)"
					@preview-image="previewImage"
					@open-notification-url="openNotificationUrl"
					@retry="onRetry"
					@remind-user-notification="onRemindUserNotification"
				/>
				<NotificationBubble
					v-else
					:msg="msg"
					:sender-name="getSenderName(msg)"
					:show-date-label="shouldShowDateLabel(index)"
					@open-notification-url="openNotificationUrl"
				/>
			</view>
		</scroll-view>
		<view class="input-bar">
			<view class="input-row">
				<view class="input-wrap">
					<input
						v-model="inputValue"
						class="input"
						:placeholder="'发送给 ' + contactTitle"
						confirm-type="send"
						@confirm="onSend"
						@focus="onInputFocus"
					/>
				</view>
				<view class="input-icon input-icon-plus" @click="onPlus">
					<image class="input-plus-img" src="/static/icons/add.svg" mode="aspectFit" />
				</view>
			</view>
			<view v-if="showPlusPanel" class="plus-panel">
				<view class="plus-item" @click="onChooseImage">
					<view class="plus-icon">
						<image class="plus-inner-icon" src="/static/icons/image.svg" mode="aspectFit" />
					</view>
					<text class="plus-label-title">图片</text>
				</view>
				<view class="plus-item" @click="onChooseVideo">
					<view class="plus-icon">
						<image class="plus-inner-icon" src="/static/icons/video.svg" mode="aspectFit" />
					</view>
					<text class="plus-label-title">视频</text>
				</view>
				<view class="plus-item" @click="onChooseFile">
					<view class="plus-icon">
						<image class="plus-inner-icon" src="/static/icons/file.svg" mode="aspectFit" />
					</view>
					<text class="plus-label-title">文件</text>
				</view>
			</view>
		</view>
	</view>
</template>

<script setup>
import { ref, computed, watch, onMounted } from 'vue'
import { onLoad, onUnload } from '@dcloudio/uni-app'
import PrivateMessageBubble from '../../components/chat/PrivateMessageBubble.vue'
import NotificationBubble from '../../components/chat/NotificationBubble.vue'
import { useMessages } from '../../composables/useMessages'
import { useContacts } from '../../composables/useContacts'
import { chatStore } from '../../store/chat'
import { getMessageCallbackUrl, getToken } from '../../utils/api'

const otherUserId = ref('')
const contactTitle = ref('会话')
const fallbackContactName = ref('')
const inputValue = ref('')
const scrollIntoView = ref('')
const showPlusPanel = ref(false)
/** 正在对哪条 USER_NOTIFICATION 执行「再次提醒」（用于按钮 loading，并防并发连点） */
const remindingNotificationId = ref('')

const { messages, loadingMore, fetchMessages, fetchMoreMessages, sendMessage, retrySendMessage, sendFileMessage, remindUserNotification } = useMessages()
const { fetchContacts } = useContacts()

function syncContactTitle() {
	const contact = (chatStore.contacts || []).find((c) => String(c.user_id || c.id) === String(otherUserId.value))
	if (contact) {
		contactTitle.value = (contact.app_name || contact.title || '会话')
		return
	}
	// 若会话列表未命中（例如从联系人详情进入，此时 chatStore.contacts 未包含该用户）
	contactTitle.value = fallbackContactName.value || '会话'
}

const messageList = computed(() => {
	const id = String(otherUserId.value)
	return (messages[id] || [])
})

const loadingMoreForContact = computed(() => !!loadingMore[String(otherUserId.value)])

onLoad((options) => {
	otherUserId.value = String((options && (options.otherUserId || options.userId)) || '0')
	// 用联系人详情传参兜底：保证从联系人详情进来仍能显示名字
	try {
		const raw = options && options.contactName != null ? String(options.contactName) : ''
		const s = raw
		// 若未自动解码，可能是 %E5...，这里做一次安全解码
		if (/%[0-9A-Fa-f]{2}/.test(s)) fallbackContactName.value = decodeURIComponent(s)
		else fallbackContactName.value = s
	} catch (e) {
		fallbackContactName.value = ''
	}
	chatStore.setActiveContact(otherUserId.value)
	chatStore.clearUnread(otherUserId.value)
	chatStore.updateTabBarUnreadBadge()
	syncContactTitle()
	try {
		const u = uni.getStorageSync('current_user')
		if (u && typeof u === 'object') {
			if (u.name) currentUserName.value = u.name
			currentUserId.value = String(u.id ?? u.user_id ?? '')
			currentUserAvatar.value = u.avatar || u.avatar_url || ''
		}
	} catch (e) {}
	// 进入聊天时，确保会话列表已就绪：联系人详情页跳转时可能还没加载 chatStore.contacts
	if (!chatStore.contacts || !chatStore.contacts.length) {
		Promise.resolve()
			.then(() => fetchContacts())
			.then(() => syncContactTitle())
			.catch(() => {})
	} else {
		// contacts 已有数据时也做一次兜底（例如 otherUserId 刚好没命中但后续会更新）
		syncContactTitle()
	}
	fetchMessages(otherUserId.value)
})

onUnload(() => {
	chatStore.setActiveContact('')
})

onMounted(() => {
	// 滚动到底部
	setTimeout(() => {
		const list = messageList.value
		if (list.length) scrollIntoView.value = 'msg-' + (list[list.length - 1].id || list[list.length - 1].tempId)
	}, 300)
})

watch(messageList, (list) => {
	if (list.length) scrollIntoView.value = 'msg-' + (list[list.length - 1].id || list[list.length - 1].tempId)
}, { deep: true })

// contacts 更新后同步聊天标题（避免从联系人详情进入仍显示“会话”）
watch(
	() => chatStore.contacts,
	() => {
		if (otherUserId.value) syncContactTitle()
	},
	{ deep: true }
)

function goBack() {
	uni.navigateBack()
}

function onSend() {
	const text = inputValue.value.trim()
	if (!text) return
	sendMessage(otherUserId.value, text)
	inputValue.value = ''
	showPlusPanel.value = false
}

function onLoadMore() {
	fetchMoreMessages(otherUserId.value)
}

function onRetry(msg) {
	retrySendMessage(otherUserId.value, msg)
}

async function onRemindUserNotification(msg) {
	if (remindingNotificationId.value) return
	if (!msg || msg.tempId) return
	remindingNotificationId.value = String(msg.id)
	try {
		await remindUserNotification(otherUserId.value, msg)
	} finally {
		remindingNotificationId.value = ''
	}
}

function getSenderName(msg) {
	return msg.isMe ? (currentUserName.value || '我') : contactTitle.value
}

function shouldShowDateLabel(index) {
	const list = messageList.value
	if (index <= 0) return true
	const prev = list[index - 1]
	const curr = list[index]
	if (!prev || !curr || !prev.createdAt || !curr.createdAt) return true
	const prevDay = new Date(prev.createdAt).toDateString()
	const currDay = new Date(curr.createdAt).toDateString()
	return prevDay !== currDay
}

const currentUserName = ref('')
const currentUserId = ref('')
const currentUserAvatar = ref('')
const contactAvatar = computed(() => {
	const contact = (chatStore.contacts || []).find((c) => String(c.user_id || c.id) === String(otherUserId.value))
	return (contact && contact.avatar) ? contact.avatar : ''
})

function previewImage(url) {
	if (!url) return
	uni.previewImage({ urls: [url] })
}

async function openNotificationUrl(msg) {
	const token = getToken()
	try {
		const res = await getMessageCallbackUrl(token, msg.id)
		const url = res.callback_url || res.callbackUrl || msg.actionUrl
		if (url) {
			const pageUrl =
				'/pages/webview/index?url=' +
				encodeURIComponent(url) +
				'&title=' +
				encodeURIComponent(msg.title || '详情')
			uni.navigateTo({ url: pageUrl })
		}
	} catch (e) {
		if (msg.actionUrl) {
			const pageUrl =
				'/pages/webview/index?url=' +
				encodeURIComponent(msg.actionUrl) +
				'&title=' +
				encodeURIComponent(msg.title || '详情')
			uni.navigateTo({ url: pageUrl })
		} else {
			uni.showToast({ title: '打开失败', icon: 'none' })
		}
	}
}

function onTitleClick() {
	// 可扩展：进入联系人详情或下拉菜单
}

function onMore() {
	uni.showActionSheet({
		itemList: ['聊天信息', '查找聊天内容', '清空聊天记录'],
		success: (res) => {}
	})
}

function onInputFocus() {
	showPlusPanel.value = false
}

function onChooseImage() {
	uni.hideKeyboard()
	uni.chooseImage({
		count: 1,
		success: (res) => {
			const path = res.tempFilePaths[0]
			sendFileMessage(otherUserId.value, path, 'image')
		}
	})
}

function onChooseVideo() {
	uni.hideKeyboard()
	uni.chooseVideo({
		sourceType: ['album', 'camera'],
		success: (res) => {
			const path = res.tempFilePath || (res.tempFilePaths && res.tempFilePaths[0])
			if (path) {
				sendFileMessage(otherUserId.value, path, 'video')
			}
		}
	})
}

function onChooseFile() {
	uni.hideKeyboard()
	// 不同平台支持差异较大，如有需要可按端分别处理
	if (uni.chooseMessageFile) {
		uni.chooseMessageFile({
			count: 1,
			type: 'file',
			success: (res) => {
				const file = res.tempFiles && res.tempFiles[0]
				if (file && file.path) {
					sendFileMessage(otherUserId.value, file.path, 'file')
				}
			}
		})
	} else {
		uni.showToast({ title: '当前端暂不支持选文件', icon: 'none' })
	}
}

function onPlus() {
	uni.hideKeyboard()
	showPlusPanel.value = !showPlusPanel.value
}
</script>

<style scoped>
.chat-page {
	height: 100vh;
	display: flex;
	flex-direction: column;
	background: #f3f4f6;
	overflow-x: hidden;
	/* 顶部安全区由 header 自己处理 */
	padding-bottom: constant(safe-area-inset-bottom);
	padding-bottom: env(safe-area-inset-bottom);
}
.chat-header {
	/* 只负责安全区和背景，与会话列表页 custom-header 对齐 */
	padding: 0 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: #ffffff;
	box-shadow: 0 1px 0 rgba(15, 23, 42, 0.06);
}

.chat-header-main {
	height: 88rpx;
	display: flex;
	align-items: center;
	justify-content: space-between;
	position: relative;
}
.back {
	width: 64rpx;
	height: 64rpx;
	display: flex;
	align-items: center;
	justify-content: center;
	margin-right: 8rpx;
}
.header-icon-img {
	width: 44rpx;
	height: 44rpx;
	opacity: 0.9;
}
.chat-title-wrap {
	position: absolute;
	left: 50%;
	transform: translateX(-50%);
	display: flex;
	align-items: center;
	justify-content: center;
}
.chat-title-texts {
	display: flex;
	flex-direction: column;
	justify-content: center;
}
.chat-title {
	font-size: 34rpx;
	font-weight: 600;
	color: #111827;
}
.header-actions {
	display: flex;
	align-items: center;
	gap: 16rpx;
}
.header-icon {
	width: 56rpx;
	height: 56rpx;
	display: flex;
	align-items: center;
	justify-content: center;
}
.message-list {
	flex: 1;
	min-height: 0;
	height: 0;
	/* 去掉顶部内边距，使第一条消息与列表页首行对齐 */
	padding: 0 24rpx 16rpx;
}
.load-more {
	text-align: center;
	padding: 16rpx;
	font-size: 24rpx;
	color: #999;
}
.empty-messages {
	flex: 1;
	display: flex;
	align-items: center;
	justify-content: center;
	min-height: 200rpx;
	padding: 48rpx;
}
.empty-text {
	font-size: 28rpx;
	color: #999;
}
.input-bar {
	display: flex;
	flex-direction: column;
	gap: 16rpx;
	padding: 10rpx 16rpx;
	background: #f5f5f7;
	border-top: 1rpx solid #e5e7eb;
	padding-bottom: max(10rpx, constant(safe-area-inset-bottom));
	padding-bottom: max(10rpx, env(safe-area-inset-bottom));
}
.input-row {
	display: flex;
	align-items: center;
}
.input-wrap {
	position: relative;
	min-height: 60rpx;
	max-height: 140rpx;
	padding: 6rpx 18rpx;
	background: #ffffff;
	border-radius: 999rpx;
	flex: 1;
	display: flex;
	align-items: center;
}
.input {
	min-height: 40rpx;
	font-size: 26rpx;
	height: 44rpx;
	line-height: 44rpx;
	padding: 0;
	width: 100%;
	box-sizing: border-box;
}
.input-icons {
	display: flex;
	align-items: center;
	justify-content: flex-start;
	gap: 24rpx;
}
.input-icon {
	width: 64rpx;
	height: 64rpx;
	display: flex;
	align-items: center;
	justify-content: center;
}
.input-icon .icon-emoji,
.input-icon .icon-at,
.input-icon .icon-mic,
.input-icon .icon-pic,
.input-icon .icon-aa {
	font-size: 40rpx;
	color: #6b7280;
}
.input-icon-plus {
	margin-left: 12rpx;
	border-radius: 999rpx;
	border: 2rpx solid #111827;
	background: #ffffff;
}
.input-plus-img {
	width: 36rpx;
	height: 36rpx;
	opacity: 0.9;
}

.plus-panel {
	margin-top: 12rpx;
	padding: 24rpx 16rpx 12rpx;
	background: #f5f5f7;
	border-radius: 24rpx;
	display: flex;
	justify-content: space-between;
}

.plus-item {
	flex: 1;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: flex-start;
}

.plus-icon {
	width: 120rpx;
	height: 120rpx;
	border-radius: 32rpx;
	background: #ffffff;
	display: flex;
	align-items: center;
	justify-content: center;
	margin-bottom: 8rpx;
}

.plus-inner-icon {
	width: 56rpx;
	height: 56rpx;
}

.plus-label-title {
	font-size: 26rpx;
	color: #111111;
}

.plus-label-desc {
	margin-top: 2rpx;
	font-size: 22rpx;
	color: #999999;
}
</style>
