import {defineStore} from 'pinia'
import type Chat from '@/mode/Chat'
import type Message from '@/mode/Message'
import ChatType from '@/utils/ChatType'
import GroupApi from '@/api/GroupApi'
import UserApi from '../api/UserApi'
import MessageType from '@/utils/MessageType'
import FetchRequest from '@/api/FetchRequest'
import {useSettingStore} from '@/store/settingStore'
import DictUtils from '@/utils/DictUtils'
import {useUserStore} from '@/store/userStore'
import {useImmunityStore} from '@/store/immunityStore'
import type Extend from '@/mode/Extend'
import {useSysStore} from "@/store/sysStore";
import type Receipt from "@/mode/Receipt";
import {useWsStore} from "@/store/WsStore";
import ChatApi from "@/api/ChatApi";
import VimConfig from "@/config/VimConfig";

export interface IState {
    chats: Array<Chat>;
    openChatId: string | null;
    last: number;
    quoteMessage: Message | undefined
    chatMessage: Map<string, Message[]>;
    chatLastTime: Map<string, number>;
    chatLastMessage: Map<string, string>;
    //未读消息id
    chatUnreadId: Map<string, Array<string>>
}

export const useChatStore = defineStore({
    id: 'chat_store',
    state: (): IState => ({
        chats: new Array<Chat>(),
        //当前打开的聊天室id
        openChatId: null,
        //消息声音提醒时间（限流作用）
        last: 0,
        //引用消息的id
        quoteMessage: undefined,
        chatMessage: new Map<string, Message[]>(),
        chatLastTime: new Map<string,number>(),
        chatLastMessage: new Map<string,string>(),
        chatUnreadId: new Map<string, []>()

    }),
    // 开启数据缓存
    persist: {
        enabled: true,
        strategies: [
            {
                key: 'chat',
                storage: localStorage,
                paths: ['chatLastTime','chatLastMessage','chatUnreadId']
            }
        ]
    },
    getters: {
        allUnReadCount(): number {
            return this.chats.reduce((accumulator, currentValue) => accumulator + currentValue.unreadCount, 0)
        }
    },
    actions: {
        /**
         * 去重
         * @param chatArr 聊天室数组
         */
        removeDuplicateChats(chatArr: Chat[]) {
            return  chatArr.reduce((prev: Chat[], cur: Chat) => {
                const has = prev.some((item) => item.id === cur.id)
                return has ? prev : [...prev, cur]
            }, [])
        },
        /**
         * 重新加载聊历史记录
         */
        reloadChats() {
            return Promise.all([ChatApi.topList(), ChatApi.list()])
                .then((res) => {
                    this.chats = []
                    const topChats = res[0].data
                    topChats.forEach((item) => {
                        item.top = true
                    })
                    const list = topChats.concat(res[1].data)
                    list.forEach((item) => {
                        item.unreadCount = (this.chatUnreadId[item.id]??[]).length
                    })
                    //去重
                    this.chats = this.removeDuplicateChats(list)
                    return Promise.resolve()
                })
        },
        setQuoteMessage(quoteMessage: Message | undefined) {
            this.quoteMessage = quoteMessage
        },
        /**
         * 把一个消息推送到对应的聊天记录里面
         * @param message 消息
         */
        pushMessage(message: Message) {
            const hideIndex = 10
            const chat = this.getChat(message.chatId)
            //所在的位置
            const chatIndex = this.getChatIndex(message.chatId)
            //消息是在队列的后面，用户可能看不到，需要把消息移到队列的前面
            if (chatIndex > hideIndex) {
                const topList = this.chats.filter((item) => !!item.top) // 查找已置顶元素的位置
                const topIndex = topList.length
                if (topIndex < hideIndex) {
                    const temp = this.chats.splice(chatIndex, 1)[0];
                    this.chats.splice(topIndex, 0, temp)
                    //把消息列表更新到服务端
                    ChatApi.move(message.chatId)
                }
            }
            //说明该聊天对话框已经存在
            if (chat) {
                this.addToMessageList(message, chat, true)
            } else {
                this.createChatRoom(message)
                const chat = this.getChat(message.chatId);
                if (chat) {
                    this.addToMessageList(message, chat, true)
                }
            }
            if (message.chatId === this.openChatId && !message.mine) {
                const user = useUserStore().getUser();
                if (chat && user) {
                    const receipt: Receipt = {
                        chatId: chat.id,
                        userId: user?.id,
                        timestamp: new Date().getTime(),
                        type: chat.type
                    }
                    useWsStore().sendRead(receipt)
                }
            }
        },
        /**
         * 把数据插入到消息的列表，有序插入
         * @param list list
         * @param message 消息
         * @param chat 聊天室
         * @param addTips 仅仅添加，不做其他操作(true:提醒 false:不提醒)
         */
        insertMessage(list: Message[], message: Message, chat: Chat, addTips: boolean = true): void {
            //重复数据,不予处理
            const repeat = list.findIndex((item) => {
                return item.id === message.id
            })
            if (repeat > -1) {
                return
            }
			// this.openChatId !== chat.id
            if (addTips && !message.mine && ((message.fromId != useUserStore().getUser()?.id &&
                    useImmunityStore().immunityList.indexOf(message.chatId) === -1) ||
                (message.type === ChatType.GROUP && this.isAtMine(message.extend)))) {
                // @ts-ignore
                this.chatLastMessage[chat.id] = message.content
                // @ts-ignore
                this.chatLastTime[chat.id] = message.timestamp
                if (!this.chatUnreadId[chat.id]) {
                    this.chatUnreadId[chat.id] = []
                }
                if(!this.chatUnreadId[chat.id].includes(message.id)){
                    this.chatUnreadId[chat.id].push(message.id)
                }
                chat.unreadCount = this.chatUnreadId[chat.id].length
                this.messageTips(message)
            } else if (message.fromId == useUserStore().getUser()?.id) {
                // @ts-ignore
                this.chatLastMessage[chat.id] = message.content
                // @ts-ignore
                this.chatLastTime[chat.id] = message.timestamp
            }
            //如果新消息的时间比历史数据的时间小
            const len = list.findIndex((n) => {
                // @ts-ignore
                return n.timestamp > message.timestamp
            })
            //消息是在队列的中间，不在最后
            if (len > -1) {
                list.splice(len, 0, message)
            } else {
                list.push(message)
            }
        },
        /**
         *  当前用户是否被@
         *  @param extend 扩展信息
         */
        isAtMine(extend: Extend | undefined): boolean {
            const user = useUserStore().getUser()
            //@所有人
            if (extend && extend.atAll && user) {
                return true
            }
            //@指定用户
            if (extend && extend.atUserIds && user) {
                return extend.atUserIds.indexOf(user.id) > -1
            }
            return false
        },
        /**
         * 创建一个新聊天室
         * @param message message
         * @private 私有方法
         */
        createChatRoom(message: Message) {
            //先占位，后加载
            const chat: Chat = {
                id: message.chatId,
                name: '加载中...',
                avatar: '',
                type: message.type,
                unreadCount: 0,
                isLoading: false,
                loaded: true
            }
            // @ts-ignore
            this.chatLastMessage[chat.id] = message.content
            // @ts-ignore
            this.chatLastTime[chat.id] = message.timestamp
            this.newChat(chat)
            if (message.type === ChatType.GROUP) {
                GroupApi.get(message.chatId).then((res) => {
                    this.updateChat(chat.id, res.data.name, res.data.avatar, false)
                })
            } else {
                UserApi.getUser(message.mine ? message.chatId : message.fromId).then((res) => {
                    this.updateChat(chat.id, res.data.name, res.data.avatar, false)
                })
            }
        },
        /**
         * 重置未读消息计数
         */
        reset() {
            this.chats.forEach((item: Chat) => {
                item.unreadCount = 0
                this.chatUnreadId[item.id] = []
            })
        },

        /**
         * 打开一个聊天对话框
         * @param chat chat
         */
        openChat(chat: Chat) {
            let hasChat = false
            this.chats.forEach((item: Chat) => {
                //聊天对话框已经存在
                if (item.id === chat.id) {
                    item.unreadCount = 0
                    this.chatUnreadId[item.id] = []
                    hasChat = true
                }
            })
            //新增一个新聊天对话框
            if (!hasChat) {
                chat.unreadCount = 0
                this.chatUnreadId[chat.id] = []
                //添加到聊天列表第一个
                this.newChat(chat)
            }
        },

        /**
         * 根据聊天室的ID 获取他的index
         * @param id 聊天室的ID
         */
        getChatIndex(id: string) {
            let i = -1
            this.chats.forEach((item: Chat, index: number) => {
                if (item.id === id) {
                    i = index
                }
            })
            return i
        },

        /**
         * 根据聊天室的ID 获取聊天室
         * @param id 聊天室的ID
         */
        getChat(id: string): null | Chat {
            let chat: null | Chat = null
            this.chats.forEach((item: Chat) => {
                if (item.id === id) {
                    chat = item
                }
            })
            return chat
        },
        /**
         * 退出清除chatMessage
         */
        clearMessage(): void {
            this.chatMessage = new Map<string, Message[]>()
        },

        /**
         * 设置打开的chatId
         */
        setOpenChatId(id: string | null) {
            this.openChatId = id
        },

        /**
         * 限制聊天记录的数组的长度
         * @param message 新增的聊天消息
         * @param chat 聊天室
         * @param addTips 是否提醒
         */
        addToMessageList(message: Message, chat: Chat, addTips: boolean = true) {
            const messageList = this.getChatMessage(chat.id)
            this.insertMessage(messageList, message, chat, addTips)
            this.chatMessage.set(chat.id, messageList)
        },

        /**
         * 获取聊天消息
         */
        getChatMessage(chatId: string) {
            return this.chatMessage.get(chatId) ?? []
        },
        /**
         * 删除聊天
         * @param id  聊天室的ID
         */
        delChat(id: string) {
            this.chats.splice(this.getChatIndex(id), 1)
            ChatApi.delete(id)
        },
        /**
         * 更新聊天室信息
         * @param id 聊天室id
         * @param name 名称
         * @param avatar 头像
         * @param updateUnreadCount 是否更新未读消息数
         * @param updateServer 是否更新服务器
         */
        updateChat(id: string, name: string, avatar: string, updateUnreadCount: boolean = true, updateServer: boolean = true) {
            this.chats.forEach((item: Chat) => {
                if (item.id === id) {
                    item.name = name
                    item.avatar = avatar
                    if (updateUnreadCount) {
                        item.unreadCount = 0
                        this.chatUnreadId[item.id] = []
                    }
                    if (updateServer) {
                        ChatApi.update(item)
                    }
                }
            })
        },
        /**
         * 新增聊天室
         * @param chat 聊天室
         */
        newChat(chat: Chat) {
            const items = this.chats
            const topList = items.filter((item) => item.top) // 查找已置顶元素的位置
            const topIndex = topList.length
            if (this.chats.findIndex((item) => item.id === chat.id) === -1) {
                items.splice(topIndex, 0, chat) // 将该元素插入已置顶元素的后面
                ChatApi.add(chat)
            }
        },

        /**
         * 撤回消息
         * @param message 消息
         */
        backMessage(message: Message) {
            this.chatMessage.get(message.chatId)?.forEach((item) => {
                if (item.id === message.id) {
                    item.content = '该消息已被撤回'
                    item.messageType = MessageType.event

                }
            })
        },
        /**
         * 撤回消息
         * @param message 消息
         */
        deMessage(message: Message) {
            const messages = this.chatMessage.get(message.chatId)
            messages?.forEach((item) => {
                //删除id 一样的消息
                if (item.id === message.id) {
                    messages?.splice(messages?.indexOf(item), 1)
                }
            })
        },
        /**
         * 置顶聊天室
         * @param id 聊天室的ID
         */
        topChat(id: string) {
            const items = this.chats
            const itemIndex = this.getChatIndex(id) // 查找对应元素的索引
            const chat = JSON.parse(JSON.stringify(this.chats[itemIndex]))
            if (itemIndex !== -1) {
                items.splice(itemIndex, 1) // 先从原数组中删除该元素
                const topIndex = items.findIndex((item) => !!item.top) // 查找已置顶元素的位置
                if (topIndex !== -1) {
                    items.splice(topIndex, 0, chat) // 将该元素插入已置顶元素的前面
                } else {
                    items.unshift(chat) // 如果不存在已置顶元素，则将该元素插入数组最前面
                }
                chat.top = true // 标记该元素已置顶
            }
            ChatApi.top(id)
        },
        /**
         * 实现取消置顶功能
         * @param id 聊天室的ID
         */
        cancelTop(id: string) {
            const items = this.chats
            const itemIndex = this.getChatIndex(id) // 查找对应元素的索引
            const chat = JSON.parse(JSON.stringify(this.chats[itemIndex]))
            if (itemIndex !== -1 && chat.top) {
                chat.top = false // 标记该元素已取消置顶
                const topList = items.filter((item) => !!item.top) // 查找已置顶元素的位置
                const topIndex = topList.length
                if (topIndex !== 0) {
                    items.splice(topIndex, 0, chat) // 将该元素插入已置顶元素的后面
                } else {
                    items.push(chat) // 如果不存在已置顶元素，则将该元素插入数组末尾
                }
                items.splice(itemIndex, 1) // 最后从原位置删除该元素
            }

            ChatApi.cancelTop(id)
        },
        /**
         * 消息提醒，限流2秒
         */
        messageTips: function (message: Message) {
            const now = Date.now()
            if (now - this.last >= 1000) {
                this.last = now
                if (useSettingStore().setting?.canSoundRemind === DictUtils.YES) {
                    // 创建音频对象并播放
                    const innerAudioContext = uni.createInnerAudioContext();
                    innerAudioContext.src = `${FetchRequest.getHost()}${VimConfig.soundPath}`;
                    innerAudioContext.play()

                    //#ifdef APP-PLUS
                    //只提醒友聊，如果想提示群聊，去掉 && message.type === ChatType.FRIEND
                    if (VimConfig.openUniPush && !useSysStore().show && message.type === ChatType.FRIEND) {
                        let content = MessageType.text === message.messageType ? message.content : ''
                        uni.createPushMessage({
                            title: '您有一条新消息',
                            content: content,
                            sound: 'system',
                            fail: fail => {
                                console.log(fail);
                            }
                        })
                    }
                    // #endif
                }
            }
        },
        /**
         * 设置已读读消息时间
         */
        setLastReadTime(receipt: Receipt) {
            this.chats.forEach((item: Chat) => {
                if (receipt.userId === item.id) {
                    item.lastReadTime = receipt.timestamp

                }
            })
        },
        /**
         * 设置当前聊天室的对方 已读时间
         */
        setCurrentChatLastReadTime(time: number) {
            if (this.openChatId && this.getChat(this.openChatId)) {
                const chat = this.getChat(this.openChatId);
                if (chat) {
                    chat.lastReadTime = time
                }
            }
        },
    }
})
