<template>
    <div class="ai-content-wrap">
        <div class="window-list-wrap">
            <div class="window-title">
                <div class="title-wrap">
                    <p style="color: #333333;font-size: 20px;font-weight: 600;">HORIZON INSIGHTS</p>
                    <span style="color: #666666;font-size: 16px;">弘则研究AI问答小助手</span>
                </div>
                <div class="icon"><img src="~@/assets/img/icons/horizon.png" /></div>
            </div>
            <div class="add-btn" @click="handleAddNewWindow"><i class="el-icon-circle-plus-outline"></i>新建对话窗口</div>
            <div class="list-wrap hidden-scrollbar">
                <Window-List-Item 
                    ref="windowListItem"
                    v-for="item in windowList" :key="item.AiChatTopicId"
                    :activeWindowId="activeWindowId"
                    :item="item"
                    @click.native="changeActiveWindow(item)"
                    @changeEdit="changeWindowTitle"
                    @delete="deleteWindowItem"
                />
                <div class="empty-list" v-if="windowList.length===0">
                    <img src="~@/assets/img/ai_m/empty_list.png" />
                </div>
            </div>
        </div>
        <div class="content-wrap">
            <div class="content-header">
                <div class="title-wrap">
                    <p>{{activeWindowId<=0?'新对话窗口':activeWindow.TopicName||''}}</p>
                    <span>{{activeWindowId<=0?'弘则AI助手使用说明':`${historyList.length||0} messages`}}</span>
                </div>
                <div class="select-box">
                    <!-- <el-select v-model="model" :class="{'hint':showHint}" :disabled="isTyping||(windowContentLoading&&windowContentLoading.visible)" ref="modelSelect" 
                        @click.native="selectClick"
                        @change="changeModel">
                        <el-option v-for="item in modelList" :key="item.label"
                            :label="item.label"
                            :value="item.label">
                            <span style="float:left">{{item.label}}</span>
                            <span style="float:right"><img :src="item.icon" style="margin-top:5px;width:24px;height:24px;"/></span>
                        </el-option>
                    </el-select> -->
                </div>
            </div>
            <!-- 仅这一部分滚动 -->
            <div class="window-content-wrap hidden-scrollbar">
                <div class="content-item" v-for="item in historyList" :key="item.AiChatId">
                    <!-- user 提问 -->
                    <Message-Item :messageInfo="formatMsg(item,'user')"
                        @startTyping="handleStartTyping"
                        @finishedTyping="handleFinishedTyping"
                    />
                    <!-- 模型回答 -->
                    <Message-Item :messageInfo="formatMsg(item,'model')"
                        @startTyping="handleStartTyping"
                        @finishedTyping="handleFinishedTyping"
                    />
                </div>
                <New-Window-Hint v-if="activeWindowId===0"/>
            </div>
            <div class="input-box">
                <textarea rows="6" v-model="inputText" placeholder="请输入提问,Shift+Enter换行" @keydown.enter="handleSendMsg"></textarea>
                <div class="send-btn" @click="handleSendMsg"><img src="~@/assets/img/ai_m/send.png" />发送</div>
            </div>
        </div>
    </div>
</template>

<script>
/* components */
import MessageItem from './components/messageItem.vue';
import NewWindowHint from './components/newWindowHint.vue';
import WindowListItem from './components/windowListItem';
/* api */
import {aiQAInterence} from '@/api/modules/aiApi.js'; 
export default {
    components: { WindowListItem,NewWindowHint, MessageItem },
    data() {
        return {
            /* window */
            activeWindowId:0,//当前激活的窗口id
            activeWindow:null,//当前激活窗口
            windowList:[],//窗口列表
            listWrapLoading:null,
            /* window-content*/
            historyList:[],//当前窗口历史记录
            inputText:'',
            model:'GPT-4 Turbo',//当前选择的模型
            modelOldValue:'',
            modelList:[
                {
                    label:'GPT-4 Turbo',
                    icon:require('@/assets/img/icons/gpt-4-turbo.png'),
                },
                {
                    label:'GPT4',
                    icon:require('@/assets/img/icons/gpt-4.png'),
                },
                {
                    label:'gpt-3.5-turbo-16k',
                    icon:require('@/assets/img/icons/chat-gpt-16k.png'),
                },
                {
                    label:'gpt-3.5-turbo',
                    icon:require('@/assets/img/icons/chat-gpt.png'),
                },
                {
                    label:'eta',
                    icon:require('@/assets/img/icons/horizon.png'),
                },
            ],//模型列表
            showHint:false,//选择模型提示
            isTyping:false,//是否处于打字动画中
            windowContentLoading:null,
            answerLoading:false,//回答中
        };
    },
    watch:{
        model(newVal,oldVal){
            this.modelOldValue = oldVal
        }
    },
    computed:{
        modelIcon(){
            const modelItem = this.modelList.find(i=>i.label===this.model)
            return modelItem?modelItem.icon:''
        }
    },
    methods: {
        //改变活跃窗口
        changeActiveWindow(item){
            if(item.AiChatTopicId===0){
                this.handleAddNewWindow()
                return 
            }
            if(item.AiChatTopicId===this.activeWindowId) return

            if(this.windowContentLoading&&this.windowContentLoading.visible){
                this.$message.warning('上个窗口未加载完成,请稍等')
                return
            }

            this.activeWindowId=item.AiChatTopicId
            this.activeWindow = this.windowList.find(i=>i.AiChatTopicId===item.AiChatTopicId)||{}
            this.historyList = []
            this.isTyping = false
            this.getWindowDetail()
            //切换窗口是否重置输入框
            //this.inputText=''
        },
        //获取对话窗口具体信息
        getWindowDetail(){
            this.windowContentLoading = this.$loading({
                target:document.querySelector('.window-content-wrap'),
            });
            aiQAInterence.getTopicDetail({
                AiChatTopicId:this.activeWindowId
            }).then(res=>{
                if(res.Ret!==200) return
                const {List} = res.Data
                this.historyList = List||[]
                this.windowContentLoading&&this.windowContentLoading.close()
                //使用模型
                this.model = this.historyList.length?this.historyList[this.historyList.length-1].Model:'GPT-4 Turbo'
                //如果有历史记录,则滚动到底部
                this.$nextTick(()=>{
                    const windowContentWrap = document.querySelector('.window-content-wrap')
                    windowContentWrap.scrollTo({
                        top:windowContentWrap.scrollHeight,
                        behavior:'smooth'
                    })
                })
            })
        },
        //格式化对话信息
        formatMsg(msg,type){
            let msgObj = {
                messageId:msg.AiChatId,
                messageTime:'',
                messageText:'',
                messageType:'',
                modelName:''
            }
            const {Ask,Answer,CreateTime,ModifyTime,isPlay,Model} = msg
            if(type==='user'){
                msgObj.messageText = Ask||''
                msgObj.messageType = 'question'
                msgObj.messageTime = CreateTime||''
            }
            else{
                msgObj.messageText = Answer||''
                msgObj.messageType = 'answer'
                msgObj.messageTime = ModifyTime||''
                msgObj.modelName = Model||''
                msgObj.isPlay = Boolean(isPlay)
            }
            return msgObj
        },
        //新建对话窗口
        handleAddNewWindow(){
            //禁止重复新建
            if(this.activeWindowId===0){
                this.$message.warning("您已建立对话窗口，请输入提问")
                return
            }
            //将相关值置空
            this.activeWindowId=0
            this.activeWindow=null
            this.historyList=[]
            this.model='GPT-4 Turbo'
            //this.inputText=''
            this.isTyping = false
        },
        //开始播放动画
        handleStartTyping(){
            this.isTyping = true
        },
        //结束播放动画
        handleFinishedTyping(item){
            this.isTyping = false
            const {messageId} = item
            const index = this.historyList.findIndex(i=>i.AiChatId===messageId)
            index!==-1&&(this.historyList[index].isPlay = false)
        },
        //编辑对话窗口名称
        changeWindowTitle(title){
            aiQAInterence.editTopicName({
                AiChatTopicId:this.activeWindowId,
                TopicName:title
            }).then(res=>{
                if(res.Ret!==200) return 
                this.$message.success('保存成功')
                this.getWindowList()
            })
        },
        //删除对话窗口
        deleteWindowItem(){
            const index = this.windowList.findIndex(i=>i.AiChatTopicId===this.activeWindowId)||0
            //更改activeWindowId 
            /**
             * 一般情况:指向下一个
             * 若当前为最后一个,指向上一个
             * 如果是唯一一个,则置为0
             */
            let AiChatTopicId = 0
            if(this.windowList.length===1){
                AiChatTopicId=0
            }else if(index===this.windowList.length-1){
                AiChatTopicId = this.windowList[index-1].AiChatTopicId
            }else {
                AiChatTopicId = this.windowList[index+1].AiChatTopicId
            }
            aiQAInterence.deleteTopic({
                AiChatTopicId:this.activeWindowId
            }).then(res=>{
                if(res.Ret!==200) return 
                this.getWindowList()
                this.changeActiveWindow({AiChatTopicId})
            })
        },
        //选择模型
        changeModel(value){
            //console.log('change',value)
            //非新建窗口时,模型之间切换需弹窗提示
            if(this.activeWindowId!==0&&value!==''){
                //弹窗提示:切换模型
                this.$confirm("切换回答模型，则切换后的模型无法联系上下文进行回答，确认切换吗？", "提示", {
                    type: "warning"
                }).then(()=>{
                    this.$message.success('切换模型成功')
                }).catch(()=>{
                    //this.$message.success('已取消切换模型')
                    this.model= this.modelOldValue
                    this.modelOldValue=''
                })

            }
            //新建窗口时,若选择了模型,则移除hint效果
            if(this.activeWindowId===0&&value!==''){
                this.showHint=false
            }
        },
        //点击模型选择框
        selectClick(){
            if(this.isTyping){
                this.$message.warning('请等待回答完成')
            }
        },
        //发送消息
        handleSendMsg(e){
            e.preventDefault()
            if(e.shiftKey===true) {
                this.inputText+='\n'
                return
            }
            if(this.isTyping||this.answerLoading){
                this.$message.warning('请等待回答完成')
                return
            }
            //新建窗口,未选择模型
            if(this.activeWindowId===0&&this.model===''){
                this.showHint = true
                this.$message.error('请选择模型')
                this.$nextTick(()=>{
                    this.$refs.modelSelect.focus()
                })
                return
            }
            if(this.inputText.length===0){
                this.$message.warning('请输入提问')
                return
            }
            this.answerLoading=true
            this.activeWindowId===0&&(this.activeWindowId = -1)
            //this.activeWindowId!==0&&this.getWindowDetail()
            //mock 加入到historyList中
            const msgObj = {
                AiChatId:-1,
                AiChatTopicId:0,
                Ask:this.inputText,
                Answer:'回答生成中...',
                CreateTime:'',
                ModifyTime:'',
                Model:this.model
            }
            this.historyList.push(msgObj)
            
            //滚动到底部
            this.$nextTick(()=>{
                const windowContentWrap = document.querySelector('.window-content-wrap')
                windowContentWrap.scrollTo({
                    top:windowContentWrap.scrollHeight,
                    behavior:'smooth'
                })
            })
            const inputText = this.inputText
            this.inputText = ''
            aiQAInterence.sendChatMsg({
                AiChatTopicId:this.activeWindowId<=0?0:this.activeWindowId,
                Ask:inputText,
                Model:this.model
            }).then(res=>{
                this.answerLoading=false
                //在回答未获取前切换了新窗口
                if(this.historyList.length===0){
                    this.getWindowList()
                    return
                }

                const msg = this.historyList[this.historyList.length-1]
                if(res.Ret!==200){
                    //提问失败
                    msg.Answer = res.ErrMsg||res.Msg||''
                    msg.isPlay = true
                    this.historyList.splice(this.historyList.length-1,1,msg)
                    return
                } 
                //提问成功,替换对应数据
                const {AiChatTopicId,Answer,Ask,Model} = res.Data
                //this.inputText=''
                if(this.activeWindowId<=0){
                    const windowItem = {
                        AiChatTopicId:AiChatTopicId||0,
                        TopicName:Ask,
                    }
                    this.windowList.push(windowItem)
                    this.activeWindow = windowItem
                    this.getWindowList()
                }
                //在回答未获取前切换了已有窗口
                if(this.activeWindowId>0&&this.activeWindowId!==AiChatTopicId) return

                this.activeWindowId = AiChatTopicId||0
                msg.Answer = Answer||''
                msg.Model = Model
                msg.isPlay = true
                this.historyList.splice(this.historyList.length-1,1,msg)
            }).catch(()=>{
                this.answerLoading=false
            })
        },
        //获取窗口列表
        getWindowList(){
            this.listWrapLoading = this.$loading({
                target:document.querySelector('.list-wrap'),
                background: 'rgba(244, 245, 249, 1)'
            });
            aiQAInterence.getTopicList().then(res=>{
                if(res.Ret!==200) return
                this.windowList = res.Data.List||[]
                this.listWrapLoading&&this.listWrapLoading.close()
            })
        }
    },
    mounted(){
        this.getWindowList()
    }
};
</script>

<style lang="scss">
.ai-content-wrap{
    .el-select.hint{
        .el-input.is-focus .el-input__inner{
            border-color: red;
        }
        .el-input__inner:focus{
            border-color: red;
        }
    }
}
</style>
<style scoped lang="scss">
$border-color:#3D52A1;
.ai-content-wrap{
    width:calc(100% - 64px);
    height:calc(100% - 64px);
    display: flex;
    position:relative;
    margin:30px;
    border:1px solid $border-color;
    border-radius: 32px;
    overflow: hidden;
    min-width: 960px;
    .window-list-wrap{
        width:380px;
        border-right: 1px solid #E2E2E2;
        padding:30px;
        box-sizing: border-box;
        background-color: #F4F5F9;
        display: flex;
        flex-direction: column;
        .window-title{
            display: flex;
            justify-content: space-between;
            align-items: center;
            .icon img{
                width:58px;
                height:58px;
            }
        }
        .add-btn{
            border:2px dashed $border-color;
            border-radius:16px;
            padding:14px;
            margin-top:40px;
            text-align: center;
            font-size: 16px;
            color:#333333;
            cursor: pointer;
            background-color: #F4F5F9;
            transition: background-color .5s, color .5s;
            &:hover{
                background-color: white;
                color: $border-color;
                border-style: solid;
                i{
                    color: $border-color;
                }
            }
            i{
                margin-right: 10px;
                font-weight: bold;
                font-size: 16px;
            }
        }
        .list-wrap{
            margin-top:30px;
            flex: 1;
            overflow-y: scroll;
            position:relative;
            .empty-list img{
                width:150px;
                height:150px;
                margin:0 auto;
                display: block;
            }
        }
    }
    .content-wrap{
        flex: 1;
        display: flex;
        flex-direction: column;
        min-width: 588px;
        .content-header{
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding:20px 30px;
            box-sizing: border-box;
            border-bottom: 1px solid #E2E2E2;
            .title-wrap{
                p{
                    color: #333333;
                    font-size: 18px;
                    margin-bottom: 5px;
                }
                span{
                    color: #999999;
                    line-height: 18px;
                }
            }
        }
        .window-content-wrap{
            flex: 1;
            /* border-bottom: 1px solid black; */
            padding:30px;
            text-align: center;
            overflow-y: scroll;
            overflow-x:hidden;
            position:relative;
            .content-item{
                text-align: left;
                .item{
                    width: 100%;
                    display: flex;
                    padding:15px 0;
                    border-bottom: 1px solid black;
                    .content-item-avatar{
                        width: 50px;
                        margin-right: 20px;
                        img{
                            width:38px;
                            height:38px;
                        }
                    }
                    .text{
                        flex: 1;
                    }
                }
            }
        }
        .input-box{
            padding:30px;
            position: relative;
            textarea{
                width:100%;
                border-radius: 16px;
                box-sizing: border-box;
                padding:20px 85px 20px 20px;
                font-size: 16px;
                resize: none;
                border-color: #E3E3E3;
                box-shadow: 0px 0px 12px rgba(0, 0, 0, 0.08);
            }
            .send-btn{
                position:absolute;
                bottom:50px;
                right:50px;
                padding:8px 12px;
                background-color: $border-color;
                border-radius: 6px;
                font-size: 14px;
                color: white;
                line-height: 14px;
                cursor: pointer;
                opacity: .7;
                transition: opacity .5s;
                img{
                    width:14px;
                    height:14px;
                    margin-right: 8px;
                }
                &:hover,&.canClick{
                    opacity: 1;
                }
            }
        }
    }
    .hidden-scrollbar{
        &::-webkit-scrollbar-track{
            display: none;
        }
        div::-webkit-scrollbar-track{
            display: none;
        }
    }
}
</style>
