<template>
    <div class="wx-chat">
        <aside class="friend-list" ref="friendListRef" @scroll="onFriendListScroll">
            <div class="search">PC 微信 聊天</div>
            <ul>
                <li v-for="item in users" :key="item.sender_id" :class="{selected: selectedUser && selectedUser.sender_id === item.sender_id}" @click="selectUser(item)">
                    <img class="avatar" :src="item.sender_avatar || defaultAvatar" alt="avatar" />
                    <div class="meta">
                        <div class="name-row">
                            <span class="name">{{ item.sender_name }}</span>
                            <span class="time">{{ formatTime(item.send_time) }}</span>
                        </div>
                        <div class="last">
                            <span class="content">{{ item.content }}</span>
                            <span v-if="item.unread_count > 0" class="badge">{{ item.unread_count }}</span>
                        </div>
                    </div>
                </li>
            </ul>
            <div class="list-loading" v-if="userListLoading">加载中...</div>
            <div class="list-end" v-if="userListEnd">已加载全部</div>
            <div class="list-error" v-if="userListError">
                加载失败，请
                <button @click.stop="retryLoadUsers">重试</button>
            </div>
        </aside>

        <section class="chat-area">
            <header class="chat-header" v-if="selectedUser">
                <img class="header-avatar" :src="selectedUser.sender_avatar || defaultAvatar" />
                <div class="header-title">{{ selectedUser.sender_name }}</div>
            </header>

            <main class="chat-messages" ref="messagesRef" @scroll.passive="onMessagesScroll">
                <div class="loading-top" v-if="messagesLoading && messagesPage>0">加载中...</div>
                <div class="messages-wrap">
                    <div v-for="msg in messages" :key="msg.id || msg._id || msg.send_time + msg.content" :class="['message', {me: isMyMessage(msg)}]">
                        <img class="msg-avatar" :src="msg.sender_avatar || defaultAvatar" />
                        <div class="bubble">
                            <div class="sender" v-if="!isMyMessage(msg)">{{ msg.sender_name }}</div>
                            <div class="content" v-if="msg.msg_type===0">{{ msg.content }}</div>
                            <div class="content" v-else>
                                <img class="img-preview" :src="msg.content" @click="previewImage(msg.content)" />
                            </div>
                            <div class="time">{{ formatTime(msg.send_time) }}</div>
                        </div>
                    </div>
                </div>
                <div class="messages-end" v-if="messagesEnd && messages.length>0">已加载全部历史消息</div>
            </main>

            <footer class="chat-input">
                <textarea v-model="inputText" @keydown.enter.prevent="onEnterSend" placeholder="输入消息，回车发送"></textarea>
                <div class="controls">
                    <input ref="fileInput" type="file" accept="image/*" multiple @change="onFilesSelected" style="display:none" />
                    <button @click="triggerFile">图片</button>
                    <button @click="sendText">发送</button>
                </div>
            </footer>
        </section>
    </div>
</template>

<script setup>
import { ref, reactive, onMounted, nextTick, watch, onUnmounted } from 'vue'
import { useRoute } from 'vue-router'
import { getUserList, send_message, get_messages } from '@/api/chat'
import { uploadFile } from '@/api/upload'

const route = useRoute()
const app_id = route.params.app_id || route.query.app_id || ''

const defaultAvatar = '/favicon.ico'

// Friend list state
const users = ref([])
const userPage = ref(0)
const userPageSize = ref(20)
const userTotal = ref(0)
const userListLoading = ref(false)
const userListEnd = ref(false)
const userListError = ref(false)
const friendListRef = ref(null)

// Chat state
const selectedUser = ref(null)
const messages = ref([]) // messages sorted newest-last (visual top=oldest)
const messagesPage = ref(0)
const messagesPageSize = ref(20)
const messagesTotal = ref(0)
const messagesLoading = ref(false)
const messagesEnd = ref(false)
const messagesRef = ref(null)

const inputText = ref('')
const fileInput = ref(null)

const currentUserId = ref('current_user_id') // TODO: replace with real current user ID source

function formatTime(ts){
    if(!ts) return ''
    const d = new Date(ts)
    const now = new Date()
    if(d.getFullYear() !== now.getFullYear()) return `${d.getFullYear()}-${d.getMonth()+1}-${d.getDate()}`
    if(d.toDateString() === now.toDateString()) return `${pad(d.getHours())}:${pad(d.getMinutes())}`
    return `${pad(d.getMonth()+1)}-${pad(d.getDate())}`
}
function pad(n){return n<10?('0'+n):n}

async function loadUsers(){
    if(userListLoading.value || userListEnd.value) return
    userListLoading.value = true
    userListError.value = false
    try{
        const params = { app_id, page: userPage.value, page_size: userPageSize.value }
        const res = await getUserList(params)
        // backend returns { list, page, page_size, total }
        const list = res.list || []
        userTotal.value = res.total || 0
        if(list.length>0){
            users.value = users.value.concat(list)
            userPage.value += 1
            if(users.value.length >= userTotal.value) userListEnd.value = true
        } else {
            userListEnd.value = true
        }
    }catch(e){
        console.error(e)
        userListError.value = true
    }finally{
        userListLoading.value = false
    }
}

function onFriendListScroll(e){
    const el = friendListRef.value
    if(!el) return
    // load next page when scrolled to bottom
    if(el.scrollTop + el.clientHeight >= el.scrollHeight - 10){
        loadUsers()
    }
}

function retryLoadUsers(){
    userListError.value = false
    loadUsers()
}

function selectUser(u){
    if(selectedUser.value && selectedUser.value.sender_id === u.sender_id) return
    selectedUser.value = u
    // reset message state and load newest messages
    messages.value = []
    messagesPage.value = 0
    messagesEnd.value = false
    loadMessages(true)
    // clear unread locally
    u.unread_count = 0
}

async function loadMessages(initial=false){
    if(messagesLoading.value || messagesEnd.value) return
    if(!selectedUser.value) return
    messagesLoading.value = true
    try{
        const params = { app_id, user_id: selectedUser.value.sender_id, page: messagesPage.value, page_size: messagesPageSize.value }
        const res = await get_messages(params)
        const list = (res.list||[])
        messagesTotal.value = res.total || 0
        if(initial){
            // initial load: we want newest messages visible at bottom
            messages.value = list.reverse() // assume API returns newest-first; adjust as needed
            // after render, scroll to bottom
            await nextTick()
            scrollMessagesToBottom()
            messagesPage.value = 1
            if(messages.value.length >= messagesTotal.value) messagesEnd.value = true
        } else {
            // loading older messages (scroll top) - prepend
            const beforeTop = messagesRef.value ? messagesRef.value.scrollHeight : null
            messages.value = list.reverse().concat(messages.value)
            await nextTick()
            // keep scroll position
            if(messagesRef.value && beforeTop!=null){
                messagesRef.value.scrollTop = messagesRef.value.scrollHeight - beforeTop
            }
            messagesPage.value += 1
            if(messages.value.length >= messagesTotal.value) messagesEnd.value = true
        }
    }catch(e){
        console.error(e)
    }finally{
        messagesLoading.value = false
    }
}

function onMessagesScroll(){
    const el = messagesRef.value
    if(!el || messagesLoading.value || messagesEnd.value) return
    if(el.scrollTop <= 10){
        // load older
        loadMessages(false)
    }
}

function scrollMessagesToBottom(){
    const el = messagesRef.value
    if(!el) return
    el.scrollTop = el.scrollHeight
}

function isMyMessage(msg){
    return String(msg.sender_id) === String(currentUserId.value)
}

async function sendText(){
    if(!selectedUser.value) return
    const text = inputText.value && inputText.value.trim()
    if(!text) return
    const payload = { app_id, content: text, msg_type: 1, to_user_id: selectedUser.value.sender_id }
    // optimistic UI
    const sendingMsg = { sender_id: currentUserId.value, sender_name: '我', sender_avatar: defaultAvatar, content: text, msg_type:1, send_time: new Date().toISOString(), _sending: true }
    messages.value.push(sendingMsg)
    inputText.value = ''
    scrollMessagesToBottom()
    try{
        const res = await send_message(payload)
        // replace last sending message state
        const idx = messages.value.findIndex(m=>m._sending)
        if(idx!==-1){
            messages.value[idx] = Object.assign({}, messages.value[idx], res || {}, {_sending:false})
        }
    }catch(e){
        console.error(e)
        // mark last as failed
        const idx = messages.value.findIndex(m=>m._sending)
        if(idx!==-1) messages.value[idx]._sending = false, messages.value[idx]._failed = true
    }
}

function onEnterSend(){
    sendText()
}

function triggerFile(){
    fileInput.value && fileInput.value.click()
}

async function onFilesSelected(e){
    const files = Array.from(e.target.files || [])
    if(files.length===0) return
    for(const f of files){
        await uploadAndSend(f)
    }
    // clear input
    e.target.value = ''
}

async function uploadAndSend(file){
    if(!selectedUser.value) return
    const fd = new FormData()
    fd.append('file', file)
    try{
        const up = await uploadFile(fd, '')
        const url = up && up.url || up.data && up.data.url || up.path || up
        // optimistic insert image message
        const sendingMsg = { sender_id: currentUserId.value, sender_name: '我', sender_avatar: defaultAvatar, content: url, msg_type:1, send_time: new Date().toISOString(), _sending:true }
        messages.value.push(sendingMsg)
        scrollMessagesToBottom()
        const payload = { app_id, content: url, msg_type: 1, to_user_id: selectedUser.value.sender_id }
        const res = await send_message(payload)
        const idx = messages.value.findIndex(m=>m._sending && m.msg_type===1)
        if(idx!==-1) messages.value[idx] = Object.assign({}, messages.value[idx], res || {}, {_sending:false})
    }catch(e){
        console.error(e)
        const idx = messages.value.findIndex(m=>m._sending && m.msg_type===1)
        if(idx!==-1) messages.value[idx]._sending = false, messages.value[idx]._failed = true
    }
}

function previewImage(url){
    // simple preview in new tab
    window.open(url, '_blank')
}

onMounted(()=>{
    loadUsers()
})

</script>

<style scoped>
.wx-chat{display:flex;height:100vh}
.friend-list{width:300px;border-right:1px solid #e6e6e6;overflow:auto}
.friend-list .search{padding:12px;border-bottom:1px solid #f0f0f0}
.friend-list ul{list-style:none;padding:0;margin:0}
.friend-list li{display:flex;padding:10px;cursor:pointer;border-bottom:1px solid #f5f5f5}
.friend-list li.selected{background:#f0f8ff}
.friend-list .avatar{width:48px;height:48px;border-radius:6px;margin-right:10px}
.friend-list .meta{flex:1}
.friend-list .name-row{display:flex;justify-content:space-between}
.badge{background:#f56c6c;color:#fff;padding:2px 6px;border-radius:12px;font-size:12px;margin-left:8px}
.chat-area{flex:1;display:flex;flex-direction:column}
.chat-header{height:64px;display:flex;align-items:center;padding:10px;border-bottom:1px solid #eee}
.header-avatar{width:40px;height:40px;border-radius:6px;margin-right:10px}
.chat-messages{flex:1;overflow:auto;padding:16px;background:#fafafa}
.message{display:flex;margin-bottom:12px}
.message.me{flex-direction:row-reverse}
.msg-avatar{width:36px;height:36px;border-radius:6px;margin:0 10px}
.bubble{max-width:60%;background:#fff;padding:8px;border-radius:6px;box-shadow:0 1px 1px rgba(0,0,0,0.05)}
.message.me .bubble{background:#dcf8c6}
.time{font-size:12px;color:#999;margin-top:6px}
.chat-input{height:100px;border-top:1px solid #eee;padding:8px;display:flex;flex-direction:column}
.chat-input textarea{flex:1;resize:none;padding:8px}
.controls{display:flex;gap:8px;margin-top:8px}
.img-preview{max-width:200px;cursor:pointer}
</style>
