<template>
  <div :class="[wrapperClass, {open: show}]">
    <div :class="getClass('hd')">
      <div class="title">Argo Copilot</div>
      <div class="handle-icon">
        <i v-if="!loading && list.length" v-tooltip="'清除聊天记录'" class="icon-clean-up" @click="list = []">
          <svg class="icon" style="width: 1em;height: 1em;vertical-align: middle;fill: currentColor;overflow: hidden;" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="17234"><path d="M1017.287 371.558a38.74 38.74 0 0 0-15.53-13.14l-89.254-43.69-82.427-41.64L942.539 53.795c7.509-14.676-3.925-35.667-27.647-46.93S867.28-1.5 859.77 13.349L747.307 232.643l-74.577-36.52-115.876-57h-8.704l-2.048-2.56h-20.478l-1.536 0.853h-1.707l-1.536 1.024-1.706 1.024-1.366 1.024-1.536 1.024-1.194 1.365a4.608 4.608 0 0 0-1.365 1.195 10.24 10.24 0 0 0-1.366 1.365l-1.194 1.365-1.195 1.536-1.024 1.536-1.877 3.755a6.997 6.997 0 0 1-0.853 1.536 717.783 717.783 0 0 1-103.76 147.618l-1.706 2.048a846.288 846.288 0 0 1-87.547 83.11A989.81 989.81 0 0 1 24.404 551.77a40.958 40.958 0 0 0-6.314 71.335l651.568 389.098a42.323 42.323 0 0 0 15.018 5.12 38.398 38.398 0 0 0 48.125-3.925A992.2 992.2 0 0 0 946.635 720.38a770.687 770.687 0 0 0 77.307-327.832 37.886 37.886 0 0 0-6.655-21.162zM877.86 689.492a914.892 914.892 0 0 1-179.531 252.913l-144.035-85.328 90.448-86.353a36.52 36.52 0 0 0 0-52.391 38.568 38.568 0 0 0-53.586 0l-103.93 99.493-169.292-101.2 102.394-69.97a36.35 36.35 0 0 0 9.386-51.196 38.398 38.398 0 0 0-52.733-9.045l-129.358 88.57-131.576-80.037A1050.394 1050.394 0 0 0 361.964 444.77a949.706 949.706 0 0 0 75.43-69.287L901.581 634.37a780.756 780.756 0 0 1-23.721 55.292z m47.272-127.481L488.079 318.313a822.738 822.738 0 0 0 68.263-96.933l392.511 192.5a664.026 664.026 0 0 1-22.527 148.131z" p-id="17235" /></svg>
        </i>
        <i class="icon-close" @click="show = false">
          <svg class="icon" style="width: 1em;height: 1em;vertical-align: middle;fill: currentColor;overflow: hidden;" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="10634"><path d="M952.311261 921.328619 542.892591 510.919389 950.154131 102.671381c8.53028-8.55177 8.53028-22.416546 0-30.967292-8.532327-8.55177-22.360264-8.55177-30.892591 0l-407.262564 408.248008L104.737436 71.704089c-8.53028-8.55177-22.36231-8.55177-30.892591 0-8.529257 8.55177-8.529257 22.416546 0 30.967292l407.262564 408.248008L71.687716 921.328619c-8.529257 8.55177-8.529257 22.416546 0 30.967292 4.26514 4.27435 9.856485 6.41306 15.446807 6.41306 5.590322 0 11.181667-2.13871 15.446807-6.41306l409.41867-410.409231 409.41867 410.409231c4.266164 4.27435 9.855462 6.41306 15.446807 6.41306 5.591345 0 11.17962-2.13871 15.446807-6.41306C960.841541 943.745165 960.841541 929.879366 952.311261 921.328619z" fill="#272636" p-id="10635" /></svg>
        </i>
      </div>
    </div>
    <div ref="mainBody" :class="getClass('bd')">
      <div v-for="(item,i) in list" :key="item.id" class="item">
        <div class="user-profile" :class="[item.my ? 'my' : 'open-ai']">
          <i v-if="!item.my">
            <svg class="icon" style="width: 1em;height: 1em;vertical-align: middle;fill: currentColor;overflow: hidden;" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1517"><path d="M950.676002 419.057175a255.346807 255.346807 0 0 0-22.014863-209.48251 257.949339 257.949339 0 0 0-277.74565-123.72694A258.759964 258.759964 0 0 0 212.538139 178.386943a255.346807 255.346807 0 0 0-170.572521 123.726941 257.949339 257.949339 0 0 0 31.699696 302.789689 255.133485 255.133485 0 0 0 21.758876 209.525175 258.162662 258.162662 0 0 0 277.958972 123.726941A255.346807 255.346807 0 0 0 565.757223 1023.996587a258.375984 258.375984 0 0 0 246.259276-179.446729 255.560129 255.560129 0 0 0 170.529856-123.726941 258.375984 258.375984 0 0 0-31.870353-301.765742zM565.757223 957.013381a190.966133 190.966133 0 0 1-122.702994-44.371041l6.015689-3.455821 203.893466-117.668587a33.918248 33.918248 0 0 0 16.724469-29.054499v-287.430483l86.182214 49.832092a3.029177 3.029177 0 0 1 1.621249 2.218552v238.195693a192.160738 192.160738 0 0 1-191.734093 191.734094zM153.618516 780.979809a190.710147 190.710147 0 0 1-22.825487-128.590689l6.058354 3.626479 204.064123 117.711252a32.8943 32.8943 0 0 0 33.278281 0l249.288453-143.736574v99.493526a3.413157 3.413157 0 0 1-1.407927 2.645197L415.578315 851.205514a191.990081 191.990081 0 0 1-261.959799-70.225705zM99.861294 336.928085a191.350114 191.350114 0 0 1 100.944118-84.176984V494.957254a32.680978 32.680978 0 0 0 16.553811 28.841176l248.093849 143.139272-86.182214 49.832092a3.242499 3.242499 0 0 1-3.029177 0l-206.069353-118.863193A192.160738 192.160738 0 0 1 99.861294 335.904138z m708.102081 164.471503l-248.861809-144.504534L645.070458 307.23362a3.242499 3.242499 0 0 1 3.029177 0l206.069353 119.076514a191.734094 191.734094 0 0 1-28.841177 345.795467v-242.248817a33.704925 33.704925 0 0 0-17.364436-28.457196z m85.75557-128.97467l-6.01569-3.626479-203.680143-118.692534a33.107623 33.107623 0 0 0-33.491603 0L401.456378 393.842478V294.306288a2.815855 2.815855 0 0 1 1.194605-2.602533l206.069353-118.905856a191.990081 191.990081 0 0 1 284.998609 198.816394z m-539.278804 176.417552l-86.182214-49.661434a3.413157 3.413157 0 0 1-1.62125-2.431875V259.236099a191.990081 191.990081 0 0 1 314.65041-147.320388l-6.058354 3.413157-203.850801 117.668587a33.918248 33.918248 0 0 0-16.767134 29.054499z m46.802915-100.901454l111.012931-63.996693 111.226253 63.996693v127.950723l-110.799609 63.996693-111.226253-63.996693z" p-id="1518" /></svg>
          </i>
          <i v-else>
            <svg class="icon" style="width: 1em;height: 1em;vertical-align: middle;fill: currentColor;overflow: hidden;" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="52958"><path d="M930.996 192.783c2.554 5.838 4.743 12.65 6.325 20.434 1.58 7.784 2.432 15.933 2.432 24.326s-1.581 16.906-4.865 25.299-8.392 16.541-15.569 24.326c-7.784 7.784-14.717 14.595-20.92 20.433a737.434 737.434 0 0 0-16.055 15.569c-5.23 5.23-10.095 9.73-14.596 13.622L685.79 154.835c7.785-7.177 17.029-15.69 27.732-25.786 10.703-10.095 19.582-18.001 26.759-23.84 9.122-7.176 18.487-12.162 28.218-15.081 9.73-2.92 19.339-4.257 28.704-3.893 9.366 0.365 18.488 1.825 27.245 4.38 8.758 2.675 16.299 5.472 22.867 8.756 13.622 7.177 28.704 19.583 45.246 37.462 16.42 17.88 29.313 36.49 38.435 55.95zM173 667.625c3.892-3.892 13.014-13.136 27.245-27.731s32.11-32.597 53.517-54.004l359.05-359.05 181.959 182.93-209.203 209.203-77.843 78.816c-25.907 25.3-49.26 48.53-70.059 69.572s-37.948 38.435-51.571 52.058c-13.623 13.622-21.772 21.407-24.326 23.353-6.446 5.838-13.987 12.041-22.38 18.488-8.392 6.446-17.15 11.676-26.272 15.568-9.122 4.5-22.38 10.095-39.894 16.542-17.515 6.446-35.881 12.77-54.977 18.974-19.217 6.203-37.34 11.555-54.49 16.055s-29.92 7.42-38.435 8.757c-17.515 1.947-29.191-0.608-35.03-7.784-5.838-7.176-7.419-19.096-4.864-36.002 1.337-9.122 4.378-22.258 9.243-39.408 4.866-17.15 10.096-35.03 15.569-53.517s10.825-35.516 16.055-51.085c5.23-15.568 9.366-26.272 12.65-32.11 3.892-9.122 8.27-17.393 13.136-24.812 4.865-7.42 11.798-15.69 20.92-24.813z" p-id="52959" /></svg>
          </i>
        </div>
        <div class="content" :class="{'input-loading': list.length - 1 === i && loading, 'box-input-loading': list.length - 1 === i && loading && !item.content}" v-html="markdownit(item)">

        </div>
      </div>
    </div>
    <div :class="getClass('ft')">
      <xInput v-model="sendText" placeholder="请输入你想说的" @on-enterkey="send()"></xInput>
      <span v-if="!loading" class="send" @click="send()">
        <svg class="icon" style="width: 1em;height: 1em;vertical-align: middle;fill: currentColor;overflow: hidden;" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="9626"><path d="M565.747623 792.837176l260.819261 112.921839 126.910435-845.424882L66.087673 581.973678l232.843092 109.933785 562.612725-511.653099-451.697589 563.616588-5.996574 239.832274L565.747623 792.837176z" p-id="9627" /></svg>
      </span>
      <span v-else class="send-loading"></span>
    </div>
  </div>
</template>

<script>
import { LIB_NAME, uuid } from '../../../../src/util'
import { xInput } from '../../../vue-input/src'

const wrapperClass = `${LIB_NAME}-chart`

const fetchStream = (url, params) => {
  const { onmessage, onclose, ...otherParams } = params
  const push = async(controller, reader) => {
    const { value, done } = await reader.read()
    if (done) {
      controller.close()
      onclose && onclose()
    } else {
      onmessage && onmessage(new TextDecoder().decode(value))
      controller.enqueue(value)
      push(controller, reader)
    }
  }
  // 发送请求
  return fetch(url, otherParams)
    .then((response) => {
      if (!response.ok) {
        return Promise.reject(response)
      }
      // 以ReadableStream解析数据
      const reader = response.body.getReader()
      const stream = new ReadableStream({
        start(controller) {
          push(controller, reader)
        }
      })
      return stream
    })
    .then((stream) => new Response(stream, { headers: { 'Content-Type': 'text/html' }}).text())
}

let isLoadInit = false

export default {
  name: 'xChat',
  components: { xInput },
  data() {
    return {
      wrapperClass,
      show: false,
      loading: false,
      sendText: '',
      list: [],

      // 当前正在回复内容
      currentReply: ''
    }
  },
  updated() {
    this.$refs.mainBody.scrollTop = 1000000
  },
  created() {
  },
  methods: {
    init() {
      this.show = !this.show
      if (this.show && !isLoadInit) {
        this.loadCss('https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.8.0/build/styles/base16/solarized-dark.min.css')
        this.loadScript('https://cdn.jsdelivr.net/npm/markdown-it@13.0.1/dist/markdown-it.min.js')
        this.loadScript('https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.8.0/build/highlight.min.js')
        isLoadInit = true
      }
    },

    // 加载js资源
    loadScript(url) {
      return new Promise((resolve, reject) => {
        const scriptNodes = [].slice.call(document.querySelectorAll('script')).map(item => item.src)
        if (scriptNodes.includes(url)) return resolve()

        var c = document.createElement('script')
        c.type = 'text/javascript'
        c.async = true
        c.src = url
        c.onload = function() {
          resolve()
        }
        c.onerror = function(err) {
          reject(err)
        }
        document.body.appendChild(c)
      })
    },

    // 加载css资源
    loadCss(url) {
      return new Promise((resolve, reject) => {
        const linkNodes = [].slice.call(document.querySelectorAll('link')).map(item => item.href)
        if (linkNodes.includes(url)) return resolve()

        var link = document.createElement('link')
        link.type = 'text/css'
        link.rel = 'stylesheet'
        link.href = url
        link.onload = function() {
          resolve()
        }
        link.onerror = function(err) {
          reject(err)
        }
        document.head.appendChild(link)
      })
    },
    getUuid() {
      return uuid() + uuid() + uuid()
    },
    markdownit(item) {
      const text = item.content
      if (text && window.markdownit && !/class="reply-error"/.test(text)) {
        const md = window.markdownit({
          breaks: true,
          highlight: function(str, lang) {
            if (lang && hljs && hljs.getLanguage(lang)) {
              try {
                return '<pre class="hljs"><code>' +
                    hljs.highlight(str, { language: lang, ignoreIllegals: true }).value +
                    '</code></pre>'
              } catch (__) {}
            }
            return '<pre class="hljs"><code>' + md.utils.escapeHtml(str) + '</code></pre>'
          }
        })
        return md.render(text)
      }
      return text
    },
    getClass(name) {
      return wrapperClass + '-' + name
    },
    response(res) {
      this.currentReply = this.currentReply + res
      const v = this.currentReply.replace(/data:/, '').replace(/\n\ndata:/g, '')
      const index = this.list.length - 1
      this.$set(this.list[index], 'content', v)
    },
    send() {
      if (this.loading || !this.sendText.trim()) {
        return
      }
      const sendText = this.sendText
      this.loading = true
      this.sendText = ''
      this.currentReply = ''
      this.list.push({
        id: this.getUuid(),
        my: true,
        content: sendText
      }, {
        id: this.getUuid(),
        content: ''
      })
      fetchStream(`/chat/`, {
        method: 'POST',
        body: JSON.stringify({
          role: 'assistant',
          prompt: sendText
        }),
        headers: {
          'accept': 'text/event-stream',
          'Content-Type': 'application/json'
        },
        onmessage: (res) => {
          // console.log(res.replace(/\n/g, '|'))
          this.response(res)
        },

        onclose: () => {
          this.loading = false
        }
      }).then(res => {
        // this.loading = false
        // console.log(res.replace(/\n/g, '$'))
        // this.response(res, true)

      }).catch(e => {
        this.response(`<span class="reply-error"><i class="ans-icon-warn-solid"></i>${e.statusText || '出错了，稍后再试'}</span>`)
        this.loading = false
      })
    }
  }
}
</script>
