<script lang="tsx" setup>
import { defaultMockModelName, modelMappingList, triggerModelTermination } from '@/components/MarkdownPreview/models'
import * as TransformUtils from '@/components/MarkdownPreview/transform'
import MarkdownPreview from '@/components/MarkdownPreview/index.vue'
import { type InputInst } from 'naive-ui'
import type { SelectBaseOption } from 'naive-ui/es/select/src/interface'
import { isGithubDeployed } from '@/config'
const storageKey = 'kaConversationsChatList'
interface Message {
  id: number
  role: 'user' | 'assistant'
  content: string
  reader?: ReadableStreamDefaultReader<string> | null
}

const messages = ref<Message[]>([])

const addUserMessage = (text: string, reader: ReadableStreamDefaultReader<string> | null, content: string) => {

  // 用户消息，这里content字段要注意类型，理论上是string，传reader的话你要后续处理渲染逻辑
  messages.value.push({
    id: Date.now(),
    role: 'user',
    content: text, // 建议用户消息content设空，reader用在assistant消息更合理
    reader: null
  })
  // 机器人回复初始空内容和reader占位，reader这里应传你后续的reader流
  messages.value.push({
    id: Date.now() + 1,
    role: 'assistant',
    content,
    reader: reader || null
  })
  // 将滚动条置于底部
  setTimeout(() => {
    const chatContainer = document.querySelector('.chat-scroll__black')
    if (chatContainer) {
      chatContainer.scrollTop = chatContainer.scrollHeight
    }
  }, 0)


  // 保存会话列表
  localStorage.setItem(storageKey, JSON.stringify(messages.value))
}

const storageData = localStorage.getItem(storageKey)
if (storageData) {
  const storages = JSON.parse(storageData)
  messages.value = storages.map(acc => {
    if (acc.role) {
      const contentNew = new ReadableStream({
        start(controller) {
          // 将每一行数据作为单独的 chunk
          acc.content?.split('\n').forEach(line => {
            controller.enqueue(new TextEncoder().encode(`${ line }\n`))
          })
          controller.close()
        }
      })
      const contentReader = contentNew.pipeThrough(new TextDecoderStream())
        .pipeThrough(TransformUtils.splitStream('\n'))
        .getReader()
      acc.reader = contentReader
    }
    return acc
  })
}

const updateMessages = () => {
  localStorage.removeItem(storageKey)
  localStorage.removeItem('chatNotes')
  messages.value = []
}


import { UAParser } from 'ua-parser-js'
const businessStore = useBusinessStore()


const modelListSelections = computed(() => {
  return modelMappingList.map<SelectBaseOption>((modelItem) => {
    let disabled = false
    if (isGithubDeployed && modelItem.modelName !== defaultMockModelName) {
      disabled = true
    }

    return {
      label: modelItem.label,
      value: modelItem.modelName,
      // Github 演示环境禁用模型切换，拉取代码后可按自己需求修改
      disabled
    }
  })
})


const loading = ref(true)

setTimeout(() => {
  loading.value = false
}, 700)


const stylizingLoading = ref(false)


/**
 * 输入字符串
 */
const inputTextString = ref('')
const refInputTextString = ref<InputInst | null>()

/**
 * 输出字符串 Reader 流（风格化的）
 */
const outputTextReader = ref<ReadableStreamDefaultReader | null>()

const refReaderMarkdownPreview = ref<InstanceType<typeof MarkdownPreview>[]>([])

const onFailedReader = () => {
  outputTextReader.value = null
  stylizingLoading.value = false
  const count = messages.value.length ? messages.value.length - 1 : 0
  if (refReaderMarkdownPreview[count].value) {
    refReaderMarkdownPreview.value[count]?.initializeEnd()
  }
  // window.$ModalMessage.error('请求失败，请重试')
  setTimeout(() => {
    if (refInputTextString.value) {
      refInputTextString.value.focus()
    }
  })
  triggerModelTermination()
}
const onCompletedReader = () => {
  stylizingLoading.value = false
  setTimeout(() => {
    if (refInputTextString.value) {
      refInputTextString.value.focus()
    }
  })
  triggerModelTermination()
}

const handleCreateStylized = async () => {
  const count = messages.value.length ? messages.value.length - 1 : 0
  // 若正在加载，则点击后恢复初始状态
  if (stylizingLoading.value) {
    refReaderMarkdownPreview.value[count]?.abortReader()
    onCompletedReader()
    return
  }


  if (refInputTextString.value && !inputTextString.value.trim()) {
    inputTextString.value = ''
    refInputTextString.value.focus()
    return
  }

  refReaderMarkdownPreview.value[count]?.resetStatus()
  refReaderMarkdownPreview.value[count]?.initializeStart()

  stylizingLoading.value = true
  const textContent = inputTextString.value
  inputTextString.value = ''
  addUserMessage(textContent, null, '')
  const { error, content } = await businessStore.createAssistantWriterStylized({
    text: textContent
  })
  const contentNew = new ReadableStream({
    start(controller) {
      // 将每一行数据作为单独的 chunk
      content?.split('\n').forEach(line => {
        controller.enqueue(new TextEncoder().encode(`${ line }\n`))
      })
      controller.close()
    }
  })
  const contentReader = contentNew.pipeThrough(new TextDecoderStream())
    .pipeThrough(TransformUtils.splitStream('\n'))
    .getReader()

  if (error) {
    stylizingLoading.value = false
    onFailedReader()
    return
  }

  if (content) {
    stylizingLoading.value = false
    // 此处是为了解决reader 再次赋值内容不响应的问题
    messages.value.splice(-2)
    addUserMessage(textContent, contentReader, content)
    // outputTextReader.value = reader
  }
}


const keys = useMagicKeys()
const enterCommand = keys['Meta+Enter']
const enterCtrl = keys['Ctrl+Enter']

const activeElement = useActiveElement()
const notUsingInput = computed(() => activeElement.value?.tagName !== 'TEXTAREA')

const parser = new UAParser()
const isMacos = computed(() => {
  const os = parser.getOS()
  if (!os) return

  const osName = os.name ?? ''
  return osName
    .toLocaleLowerCase()
    .includes?.('macos')
})

const placeholder = computed(() => {
  return '基于知识库提问'
})

watch(
  () => enterCommand.value,
  () => {
    if (!isMacos.value || notUsingInput.value) return

    if (stylizingLoading.value) return

    if (!enterCommand.value) {
      handleCreateStylized()
    }
  },
  {
    deep: true
  }
)

watch(
  () => enterCtrl.value,
  () => {
    if (isMacos.value || notUsingInput.value) return

    if (stylizingLoading.value) return

    if (!enterCtrl.value) {
      handleCreateStylized()
    }
  },
  {
    deep: true
  }
)


const handleResetState = () => {
  inputTextString.value = ''
  const count = messages.value.length ? messages.value.length - 1 : 0
  stylizingLoading.value = false
  nextTick(() => {
    refInputTextString.value?.focus()
  })
  refReaderMarkdownPreview.value[count]?.abortReader()
  refReaderMarkdownPreview.value[count]?.resetStatus()
}
handleResetState()


</script>

<template>
  <LayoutCenterPanel
    :loading="loading"
  >
    <!-- 内容区域 -->
    <div
      flex="~ col"
      h-full
      class="content-warp-black"
    >
      <div
        flex="~ justify-between items-center"
      >
        <NavigationNavBar @update-messages="updateMessages">
          <template #right>
            <div
              flex="~ justify-center items-center wrap"
              class="text-16 line-height-16"
            >
              <span class="lt-xs:hidden">当前模型：</span>
              <div
                flex="~ justify-center items-center"
              >
                <n-select
                  v-model:value="businessStore.systemModelName"
                  class="w-280 lt-xs:w-260 pr-10 font-italic font-bold"
                  placeholder="请选择模型"
                  :disabled="stylizingLoading"
                  :options="modelListSelections"
                />
                <!-- <CustomTooltip
                  :disabled="false"
                >
                  <div>注意：</div>
                  <div>
                    演示环境仅支持 “模拟数据模型”
                  </div>
                  <div>
                    如需测试其他模型请克隆<a
                      href="https://github.com/pdsuwwz/chatgpt-vue3-light-mvp"
                      target="_blank"
                      class="px-2 underline c-warning font-bold"
                    >本仓库</a>到本地运行
                  </div>
                  <template #trigger>
                    <span
                      class="cursor-help font-bold c-primary text-17 i-ic:sharp-help"
                      ml-10
                      mr-24
                    ></span>
                  </template>
                </CustomTooltip> -->
              </div>
            </div>
          </template>
        </NavigationNavBar>
      </div>

      <template v-if="messages.length">
        <div
          flex="1 ~ col"
          min-h-0
          pb-20
        >
          <div class="chat-scroll__black">
            <div class="chat-scroll__warp">
              <div
                v-for="(msg, index) in messages"
                :key="msg.id"
                :class="`chat-items__black chat-items__${msg.role}`"
              >
                <div
                  v-if="msg.role === 'user'"
                  class="user-black"
                >
                  <span class="content">{{ msg.content }}</span>
                </div>
                <div
                  v-if="msg.role === 'assistant'"
                  class="assistant-black"
                >
                  <div class="avatar-black">
                    <span class="avatar"><img
                      src="../assets/images/robot_logo.png"
                      alt=""
                    ></span>
                    <span class="name">GOELIA</span>
                  </div>
                  <div
                    v-if="index == messages.length - 1 && stylizingLoading"
                    class="loading-black"
                  >
                    <span class="loading-text">正在搜索知识库资料...</span>
                    <div class="place-holder">
                      <span></span>
                      <span></span>
                    </div>
                  </div>
                  <MarkdownPreview
                    ref="refReaderMarkdownPreview"
                    v-model:reader="msg.reader"
                    :model="businessStore.currentModelItem?.modelName"
                    :transform-stream-fn="businessStore.currentModelItem?.transformStreamValue"
                    @failed="onFailedReader"
                    @completed="onCompletedReader"
                  />
                </div>
              </div>
            </div>
          </div>
        </div>
      </template>
      <div
        v-else
        flex="1 ~ col"
        min-h-0
        pb-20
        style="align-items: center;justify-content: center;color: #999;"
      >
        Hi，有任何关于导购知识问题，都尽管问！
      </div>

      <div
        flex="~ col items-center"
        flex-basis="10%"
        p="14px"
        py="0"
        class="bottom-block"
      >
        <!-- <div
          w-full
          flex="~ justify-start"
          class="px-1em pb-10"
        >
          <n-space>
            <PromptTag
              v-for="(textItem, idx) in promptTextList"
              :key="idx"
              :text="textItem"
            />
          </n-space>
        </div> -->
        <div
          relative
          flex="1"
          w-full
          style="margin-bottom: 10px;"
        >
          <n-input
            ref="refInputTextString"
            v-model:value="inputTextString"
            type="textarea"
            autofocus
            h-full
            class="textarea-resize-none text-15"
            :style="{
              '--n-border-radius': '20px',
              '--n-padding-left': '20px',
              '--n-padding-right': '20px',
              '--n-padding-vertical': '10px',
            }"
            :placeholder="placeholder"
          />
          <n-float-button
            position="absolute"
            :right="20"
            bottom="50%"
            :type="stylizingLoading ? 'primary' : 'default'"
            color
            :class="[
              stylizingLoading && 'opacity-90',
              'translate-y-50%'
            ]"
            @click.stop="handleCreateStylized()"
          >
            <div
              v-if="stylizingLoading"
              class="i-svg-spinners:pulse-2 c-#fff"
            ></div>
            <div
              v-else
              class="transform-rotate-z--90 text-22 c-#303133/70 i-hugeicons:start-up-02"
            ></div>
          </n-float-button>
        </div>
      </div>
    </div>
  </LayoutCenterPanel>
</template>

<style lang="scss">
  .bottom-block .n-input {
    border-radius: 14px;
  }
  .bottom-block .n-input.n-input--textarea .n-input__textarea-el {
    max-height: 60px;
  }
  .content-warp-black {
    .chat-scroll__black {
        height: 100%;
        overflow: hidden;
        padding-top: 10px;
        overflow-y: scroll;

        .chat-scroll__warp {
          padding: 0 20px;
        }

        .user-black {
          display: flex;
          align-items: center;
        }
        .chat-items__black {
          margin-bottom: 20px;
        }
        .chat-items__user {
          .user-black {
            justify-content: flex-end;
            .content {
              padding: 5px 10px;
              border-radius: 12px 0 12px 12px;
              background: #232323;
              font-size: 16px;
              color: #fff;
            }
          }
        }
        .avatar-black {
          display: flex;
          align-items: center;
          gap: 10px;
          .avatar {
            width: 30px;
            height: 30px;
            border-radius: 200px;

            img {
              display: block;
              max-width: 100%;
            }
          }
          .name {
            font-size: 13px;
            font-weight: bold;
            color: #232323;
          }
        }
        .loading-black {
          .loading-text {
            font-size: 14px;
            color: #999;
            line-height: 1.5;
            display: block;
          }
          .place-holder {
            span {
              display: block;
              width: 100%;
              background: #f7f7f7;
              height: 15px;
              border-radius: 4px;
              margin-top: 8px;

              &:last-child {
                width: 50%;
              }
            }
          }
        }
    }
  }
</style>
