<script setup lang="ts">
import { computed, nextTick, onMounted, onUnmounted, ref, watch } from 'vue'
import { useRouter } from 'vue-router'
import { FormInst, InputInst } from 'naive-ui'
import { useI18n } from 'vue-i18n'
import { useThrottleFn } from '@vueuse/core'
import CustomIcon from '@/components/custom-icon/custom-icon.vue'
import { Help, People, RightOne } from '@icon-park/vue-next'
import UploadImage from '@/components/upload-image/upload-image.vue'
import AutoConfigModal from './auto-config-modal.vue'
import OptimizeSystemModal from './optimize-system-modal.vue'
import { usePersonalAppConfigStore } from '@/store/modules/personal-app-config'
import { PersonalAppConfigState } from '@/store/types/personal-app-config'
import {
  fetchCreateAgentAvatar,
  fetchCreateAgentTitleAndDesc,
  fetchCreateFeaturedQuestions,
  fetchCreatePreamble,
  fetchGetDebugApplicationInfo,
  fetchGetLargeModelInfo,
  fetchSaveAgentApplication,
} from '@/apis/agent-application'
import { fetchCustomEventSource } from '@/composables/useEventSource'
import AgentModelSetting from './agent-model-setting.vue'
import AgentAssociatedKnowledge from './agent-associated-knowledge.vue'
import AgentMemorySetting from './agent-memory-setting.vue'
import AgentDialogueSetting from './agent-dialogue-setting.vue'

const { t } = useI18n()

const router = useRouter()

const personalAppConfigStore = usePersonalAppConfigStore()

const defaultPrompt = t(
  'personal_space_module.agent_module.agent_setting_module.agent_config_module.agent_system_template_message',
)

const currentLargeModelIcon = ref('') // 当前大模型icon

const commConfigExpandedNames = ref<string[]>(['continuousQuestion'])

const isInitGetAgentAppDetail = ref(false)

const isFullScreenLoading = ref(false) // 是否全面加载中

const isShowAutoConfigModal = ref(false) // 是否显示自动配置对话框
const autoConfigBtnLoading = ref(false) // 自动配置按钮加载状态
const isShowOptimizeAgentSystemModal = ref(false) // 是否显示优化角色指令对话框

const generateAgentAvatarLoading = ref(false) // 是否正在生成图片
const generatePreambleLoading = ref(false) // 是否正在生成开场白
const generateFeaturedQuestionsLoading = ref(false) // 是否正在生成推荐词

const personalAppFormRef = ref<FormInst | null>(null)
const agentSystemInputRef = ref<InputInst | null>(null)

const personalAppRules = {
  baseInfo: {
    agentTitle: [
      {
        required: true,
        message: t(
          'personal_space_module.agent_module.agent_setting_module.agent_config_module.agent_title_input_rule_message',
        ),
        trigger: 'blur',
      },
    ],
  },
}

const currentDiversityMode = ref('balance')

let generateAgentTitleAndDescController: AbortController | null = null
let generateAgentAvatarController: AbortController | null = null
let generatePreambleController: AbortController | null = null
let generateFeaturedQuestionsController: AbortController | null = null
let generateAgentSystemController: AbortController | null = null

const personalAppConfig = computed(() => {
  return personalAppConfigStore.$state
})

const isUpdatePersonalAgentConfig = computed(() => {
  return !isInitGetAgentAppDetail.value
})

watch(
  () => personalAppConfig.value,
  () => {
    isUpdatePersonalAgentConfig.value && handleUpdatePersonalAppId()
  },
  { deep: true, once: true },
)

watch(
  () => personalAppConfig.value,
  () => {
    isUpdatePersonalAgentConfig.value && handleSavePersonalAppConfig()
  },
  { deep: true },
)

onMounted(async () => {
  if (router.currentRoute.value.params.agentId) {
    isInitGetAgentAppDetail.value = true
    await handleGetAgentApplicationDetail(router.currentRoute.value.params.agentId as string)
    isInitGetAgentAppDetail.value = false
  }

  await handleGetLargeModelInfo()
})

onUnmounted(() => {
  handleStopGenerate()
})

const handleSavePersonalAppConfig = useThrottleFn(
  async () => {
    personalAppConfig.value.baseInfo.agentId && (await handleSaveAgentApplication())
  },
  () => (isFullScreenLoading.value ? 6000 : 2000),
  true,
)

async function handleGetAgentApplicationDetail(agentId: string) {
  const res = await fetchGetDebugApplicationInfo<PersonalAppConfigState>(agentId)

  if (res.code === 0) {
    personalAppConfigStore.updatePersonalAppConfigState({
      ...res.data,
      baseInfo: {
        ...res.data.baseInfo,
        agentAvatar:
          res.data.baseInfo.agentAvatar || 'https://gsst-poe-sit.gz.bcebos.com/data/20240911/1726041369632.webp',
      },
    })
    ;['preamble', 'featuredQuestions']
      .filter((property) => personalAppConfig.value.commConfig[property as keyof PersonalAppConfigState['commConfig']])
      .forEach((property) => {
        commConfigExpandedNames.value.push(property)
      })

    const { temperature, topP } = personalAppConfig.value.commModelConfig

    switch (temperature) {
      case 0.1:
        currentDiversityMode.value = topP === 0.1 ? 'accurate' : 'custom'
        break
      case 0.5:
        currentDiversityMode.value = topP === 0.7 ? 'balance' : 'custom'
        break
      case 0.95:
        currentDiversityMode.value = topP === 0.7 ? 'creative' : 'custom'
        break
      default:
        currentDiversityMode.value = 'custom'
    }
  }
}

// 获取大模型信息
async function handleGetLargeModelInfo() {
  const res = await fetchGetLargeModelInfo<{ icon: string }>(personalAppConfig.value.commModelConfig.largeModel)

  if (res.code === 0) {
    currentLargeModelIcon.value = res.data.icon
  }
}

// 保存应用配置
async function handleSaveAgentApplication() {
  await fetchSaveAgentApplication<PersonalAppConfigState>(personalAppConfigStore.$state)
}

// 更新保存应用ID
async function handleUpdatePersonalAppId() {
  const res = await fetchSaveAgentApplication<PersonalAppConfigState>(personalAppConfigStore.$state)

  if (res.code === 0) {
    personalAppConfigStore.updatePersonalAppConfigState({
      baseInfo: { ...personalAppConfigStore.baseInfo, agentId: res.data.baseInfo.agentId },
    })
  }
}

function handleShowAutoConfigModal() {
  isShowAutoConfigModal.value = true
  autoConfigBtnLoading.value = false
}

function handleShowOptimizeAgentSystemModal() {
  if (!personalAppConfig.value.baseInfo.agentSystem) return

  isShowOptimizeAgentSystemModal.value = true
}

function handleSettingDefaultPrompt() {
  personalAppConfig.value.baseInfo.agentSystem = defaultPrompt
}

function handleUploadAvatarOversize() {
  window.$message.error(
    t('personal_space_module.agent_module.agent_setting_module.agent_config_module.avatar_oversize_message'),
  )
}

async function handleAIGenerateAgentAvatar() {
  generateAgentAvatarLoading.value = true
  generateAgentAvatarController = new AbortController()

  const res = await fetchCreateAgentAvatar(
    {
      agentTitle: personalAppConfig.value.baseInfo.agentTitle,
      agentDesc: personalAppConfig.value.baseInfo.agentDesc,
    },
    generateAgentAvatarController,
  ).finally(() => (generateAgentAvatarLoading.value = false))

  if (res.code === 0) {
    personalAppConfig.value.baseInfo.agentAvatar = res.data as string
  }
}

async function handleAIGeneratePreamble() {
  !commConfigExpandedNames.value.includes('preamble') && commConfigExpandedNames.value.push('preamble')

  generatePreambleLoading.value = true

  generatePreambleController = new AbortController()

  const res = await fetchCreatePreamble<string>(
    {
      agentTitle: personalAppConfig.value.baseInfo.agentTitle,
      agentDesc: personalAppConfig.value.baseInfo.agentDesc,
      agentSystem: personalAppConfig.value.baseInfo.agentSystem,
    },
    generatePreambleController,
  ).finally(() => (generatePreambleLoading.value = false))

  if (res.code === 0) {
    try {
      const content = res.data.replace(/^```json|```$/g, '')
      const preamble = JSON.parse(content)['output']
      personalAppConfig.value.commConfig.preamble = preamble
    } catch (error) {
      window.$message.error(
        t('personal_space_module.agent_module.agent_setting_module.agent_config_module.generate_format_error_message'),
      )
    }
  }
}

async function handleAIGenerateFeaturedQuestions() {
  !commConfigExpandedNames.value.includes('featuredQuestions') &&
    commConfigExpandedNames.value.push('featuredQuestions')

  generateFeaturedQuestionsLoading.value = true
  generateFeaturedQuestionsController = new AbortController()

  const res = await fetchCreateFeaturedQuestions<string[]>(
    {
      agentTitle: personalAppConfig.value.baseInfo.agentTitle,
      agentDesc: personalAppConfig.value.baseInfo.agentDesc,
    },
    generateFeaturedQuestionsController,
  ).finally(() => (generateFeaturedQuestionsLoading.value = false))

  if (res.code === 0) {
    personalAppConfig.value.commConfig.featuredQuestions = res.data
  }
}

async function handleSettingAgent(autoConfigInputValue: string) {
  autoConfigBtnLoading.value = true
  isShowAutoConfigModal.value = false
  isFullScreenLoading.value = true

  await handleCreateAgentTitleAndDesc(autoConfigInputValue)
    .then(() => {
      Promise.all([
        handleAIGenerateAgentAvatar(),
        handleAIGeneratePreamble(),
        handleAIGenerateFeaturedQuestions(),
        handleAIGenerateAgentSystem(),
      ]).finally(() => {
        isFullScreenLoading.value = false
      })
    })
    .catch(() => {
      isFullScreenLoading.value = false
    })
}

async function handleCreateAgentTitleAndDesc(input: string) {
  generateAgentTitleAndDescController = new AbortController()
  const res = await fetchCreateAgentTitleAndDesc<{ agentTitle: string; agentDesc: string }>(
    { input },
    generateAgentTitleAndDescController,
  )

  if (res.code === 0) {
    personalAppConfig.value.baseInfo.agentTitle = res.data.agentTitle
    personalAppConfig.value.baseInfo.agentDesc = res.data.agentDesc
  }
}

function handleSettingAgentSystem(agentSystem: string) {
  personalAppConfig.value.baseInfo.agentSystem = agentSystem
  isShowOptimizeAgentSystemModal.value = false
}

function handleAIGenerateAgentSystem() {
  return new Promise((resolve, reject) => {
    personalAppConfig.value.baseInfo.agentSystem = ''
    generateAgentSystemController = new AbortController()

    fetchCustomEventSource({
      path: '/api/rest/agentApplicationInfoRest/createAgentSystem.json',
      payload: {
        input: personalAppConfigStore.baseInfo.agentTitle || personalAppConfigStore.baseInfo.agentSystem,
      },
      controller: generateAgentSystemController,
      onMessage: (data: any) => {
        if (data === '[DONE]') {
          blockAnswerResponse()
          resolve(data)
          return
        }

        if (data) {
          useThrottleFn(
            () => {
              nextTick(() => {
                personalAppConfig.value.baseInfo.agentSystem += data
                agentSystemInputRef.value!.textareaElRef!.scrollTop =
                  agentSystemInputRef.value?.textareaElRef?.scrollHeight || 0
              })
            },
            1000,
            true,
          )()
        }
      },
      onRequestError: () => {
        reject()
        blockAnswerResponse()
      },
      onError: () => {
        reject()
        blockAnswerResponse()
      },
      onFinally: () => {
        generateAgentSystemController = null
      },
    })
  })
}

function blockAnswerResponse() {
  generateAgentSystemController?.abort()
}

function handleStopGenerate() {
  generateAgentTitleAndDescController?.abort()
  generateAgentAvatarController?.abort()
  generatePreambleController?.abort()
  generateFeaturedQuestionsController?.abort()
  generateAgentSystemController?.abort()
  isFullScreenLoading.value = false
}
</script>

<template>
  <div class="flex h-full flex-[3_3_0%] flex-col">
    <div
      class="flex h-[56px] w-full items-center justify-between border-r border-[#e8e9eb] px-5 text-[#333] shadow-[inset_0_-1px_#e8e9eb]"
    >
      <div class="flex items-center">
        <span class="font-600 mr-4 text-base">
          {{ t('personal_space_module.agent_module.agent_setting_module.agent_config_module.title') }}
        </span>

        <div
          class="text-theme-color flex cursor-pointer items-center rounded-md border border-[#d4e5ff] bg-[#eef3fe] px-[11px] py-[7px] text-xs hover:opacity-80"
          @click="handleShowAutoConfigModal"
        >
          <div class="mr-2 mt-[-4px] h-[16px] w-[16px] bg-[url(@/assets/svgs/star.svg)] bg-[length:100%_100%]" />
          <span>
            {{ t('personal_space_module.agent_module.agent_setting_module.agent_config_module.ai_auto_config') }}
          </span>
        </div>
      </div>

      <AgentModelSetting
        v-model:personal-app-config="personalAppConfig"
        v-model:current-diversity-mode="currentDiversityMode"
        v-model:current-large-model-icon="currentLargeModelIcon"
      />
    </div>

    <div class="flex h-[calc(100vh-56px-56px)]">
      <div class="flex h-full flex-1 flex-col overflow-auto border-r border-[#e8e9eb] py-4">
        <div class="mb-1 flex h-6 items-center px-5 leading-6">
          <People theme="multi-color" size="16" :fill="['#333', '#333', '#333', '#333']" class="mr-1.5 text-lg" />
          <span>
            {{ t('personal_space_module.agent_module.agent_setting_module.agent_config_module.agent_setting') }}
          </span>
        </div>

        <NCollapse :default-expanded-names="['1']" class="px-5">
          <template #arrow>
            <RightOne theme="multi-color" size="17" :fill="['#333', '#333', '#333', '#333']" />
          </template>
          <NCollapseItem
            :title="t('personal_space_module.agent_module.agent_setting_module.agent_config_module.base_info')"
            name="1"
            class="my-[13px]!"
          >
            <div class="justify-left flex items-start pl-5">
              <div class="relative mr-2 w-[72px]">
                <UploadImage
                  v-model:image-url="personalAppConfig.baseInfo.agentAvatar"
                  :max-image-size="1024 * 1024 * 3"
                  @oversize="handleUploadAvatarOversize"
                >
                  <template #mask>
                    <span class="text-xs text-white">
                      {{
                        t('personal_space_module.agent_module.agent_setting_module.agent_config_module.update_avatar')
                      }}
                    </span>
                  </template>
                </UploadImage>

                <div
                  v-show="generateAgentAvatarLoading"
                  class="absolute left-0 top-0 z-10 flex h-[72px] w-[72px] cursor-not-allowed items-center justify-center rounded-xl bg-[#151b2680]"
                >
                  <CustomIcon icon="eos-icons:bubble-loading" class="text-xl text-white" />
                </div>

                <div
                  class="text-theme-color mt-3 flex h-[28px] items-center justify-between rounded-md border border-[#d4d6d9] px-2"
                  :class="
                    generateAgentAvatarLoading
                      ? 'cursor-not-allowed opacity-50'
                      : 'cursor-pointer hover:border-[#d4e5ff] hover:bg-[#e6f0ff]'
                  "
                  @click="handleAIGenerateAgentAvatar"
                >
                  <div class="mt-[-2px] h-[14px] w-[14px] bg-[url(@/assets/svgs/star.svg)] bg-[length:100%_100%]" />
                  <span class="text-xs">
                    {{ t('common_module.ai_generate') }}
                  </span>
                </div>
              </div>
              <div class="flex flex-1">
                <NForm
                  ref="personalAppFormRef"
                  :model="personalAppConfig"
                  :rules="personalAppRules"
                  label-placement="left"
                  class="flex-1"
                >
                  <NFormItem feedback-class="p-0.5! text-xs!" path="baseInfo.agentTitle">
                    <NInput
                      v-model:value="personalAppConfig.baseInfo.agentTitle"
                      :maxlength="50"
                      show-count
                      :placeholder="
                        t(
                          'personal_space_module.agent_module.agent_setting_module.agent_config_module.agent_title_input_placeholder',
                        )
                      "
                      class="h-[32px]! text-xs! rounded-md!"
                    />
                  </NFormItem>
                  <NFormItem feedback-style="display:none">
                    <NInput
                      v-model:value="personalAppConfig.baseInfo.agentDesc"
                      type="textarea"
                      :maxlength="100"
                      :rows="3"
                      show-count
                      :placeholder="
                        t(
                          'personal_space_module.agent_module.agent_setting_module.agent_config_module.agent_desc_input_placeholder',
                        )
                      "
                      class="not-resize rounded-md! text-xs!"
                      size="small"
                    />
                  </NFormItem>
                </NForm>
              </div>
            </div>
          </NCollapseItem>
        </NCollapse>

        <div class="flex flex-1 flex-col border-t border-[#e8e9eb] px-5">
          <div class="my-[13px] flex items-center justify-between">
            <div class="flex items-center pl-6">
              <span class="select-none">
                {{
                  t('personal_space_module.agent_module.agent_setting_module.agent_config_module.agent_system_prompt')
                }}
              </span>
              <NPopover style="width: 520px" trigger="hover">
                <template #trigger>
                  <Help
                    theme="outline"
                    size="15"
                    fill="#333"
                    :stroke-width="3"
                    class="ml-1 cursor-pointer text-base text-[#999] outline-none"
                  />
                </template>
                <span class="text-xs">
                  {{
                    t(
                      'personal_space_module.agent_module.agent_setting_module.agent_config_module.agent_system_popover_message',
                    )
                  }}
                </span>
              </NPopover>
            </div>

            <div class="flex items-center justify-center">
              <NPopover trigger="hover">
                <template #trigger>
                  <div
                    class="text-theme-color flex items-center border-r border-[#e8e9eb] pr-[9px]"
                    :class="
                      personalAppConfig.baseInfo.agentSystem
                        ? 'cursor-pointer hover:opacity-80'
                        : 'cursor-not-allowed opacity-50'
                    "
                    @click="handleShowOptimizeAgentSystemModal"
                  >
                    <div
                      class="mr-3 mt-[-2px] h-[16px] w-[16px] bg-[url(@/assets/svgs/star.svg)] bg-[length:100%_100%]"
                    />
                    <span class="text-xs">
                      {{
                        t(
                          'personal_space_module.agent_module.agent_setting_module.agent_config_module.optimize_agent_system_prompt',
                        )
                      }}
                    </span>
                  </div>
                </template>
                <p class="text-xs">
                  {{
                    t(
                      'personal_space_module.agent_module.agent_setting_module.agent_config_module.optimize_agent_system_popover_message',
                    )
                  }}
                </p>
              </NPopover>

              <NPopover style="width: 200px" content-style="padding: 10px 0;" trigger="hover">
                <template #trigger>
                  <div
                    class="text-theme-color flex cursor-pointer items-center pl-[9px] hover:opacity-80"
                    @click="handleSettingDefaultPrompt"
                  >
                    <CustomIcon icon="solar:book-2-broken" class="mr-3 text-base" />
                    <span class="text-xs">
                      {{
                        t(
                          'personal_space_module.agent_module.agent_setting_module.agent_config_module.agent_system_template',
                        )
                      }}
                    </span>
                  </div>
                </template>
                <p class="text-xs" style="white-space: pre-wrap">{{ defaultPrompt }}</p>
              </NPopover>
            </div>
          </div>

          <div class="flex flex-1 p-1 pl-6">
            <NInput
              ref="agentSystemInputRef"
              v-model:value="personalAppConfig.baseInfo.agentSystem"
              type="textarea"
              class="prompt-input not-resize text-xs! flex-1"
              :maxlength="1400"
              show-count
              :placeholder="
                t(
                  'personal_space_module.agent_module.agent_setting_module.agent_config_module.agent_system_input_placeholder',
                )
              "
            />
          </div>
        </div>
      </div>

      <div class="h-full flex-1 overflow-auto border-r border-[#e8e9eb] py-4">
        <div class="flex h-6 items-center px-5 leading-6">
          <CustomIcon icon="streamline:decent-work-and-economic-growth-solid" class="mr-1.5 text-base" />
          <span>
            {{ t('personal_space_module.agent_module.agent_setting_module.agent_config_module.ability_expand') }}
          </span>
        </div>

        <AgentAssociatedKnowledge v-model:knowledge-config="personalAppConfig.knowledgeConfig" />

        <AgentMemorySetting
          v-model:variable-structure="personalAppConfig.commConfig.variableStructure"
          v-model:is-long-memory="personalAppConfig.commConfig.isLongMemory"
        />

        <AgentDialogueSetting
          v-model:comm-config-expanded-names="commConfigExpandedNames"
          v-model:comm-config="personalAppConfig.commConfig"
          v-model:generate-featured-questions-loading="generateFeaturedQuestionsLoading"
          v-model:generate-preamble-loading="generatePreambleLoading"
          @generate-preamble="handleAIGeneratePreamble"
          @generate-featured-questions="handleAIGenerateFeaturedQuestions"
        />
      </div>
    </div>
  </div>

  <div
    v-show="isFullScreenLoading"
    class="z-999 fixed bottom-0 left-0 right-0 top-0 flex items-center justify-center bg-[#151b2680]"
  >
    <div class="flex h-14 w-[300px] items-center justify-between rounded-xl bg-white px-5">
      <div class="flex items-center">
        <div class="mr-2 h-4 w-4 bg-[url(@/assets/images/loading.gif)] bg-[length:100%_100%]" />
        <span class="text-theme-color">
          {{
            t('personal_space_module.agent_module.agent_setting_module.agent_config_module.generating_config_message')
          }}
        </span>
      </div>
      <div class="cursor-pointer text-[#5c5f66] hover:opacity-80" @click="handleStopGenerate">
        {{ t('personal_space_module.agent_module.agent_setting_module.agent_config_module.stop_generate') }}
      </div>
    </div>
  </div>

  <AutoConfigModal
    v-model:is-show-modal="isShowAutoConfigModal"
    :btn-loading="autoConfigBtnLoading"
    :modal-title="
      t(
        'personal_space_module.agent_module.agent_setting_module.agent_config_module.auto_config_modal_module.modal_title',
      )
    "
    @confirm="handleSettingAgent"
  />

  <OptimizeSystemModal
    v-model:is-show-modal="isShowOptimizeAgentSystemModal"
    :btn-loading="false"
    :modal-title="
      t(
        'personal_space_module.agent_module.agent_setting_module.agent_config_module.optimize_system_modal_module.modal_title',
      )
    "
    @confirm="handleSettingAgentSystem"
  />
</template>

<style lang="scss" scoped>
@include custom-scrollbar(0);

:deep(.n-form-item-feedback-wrapper) {
  --n-feedback-height: 14px;
}

:deep(.not-resize .n-input-wrapper) {
  resize: none !important;
}

:deep(.prompt-input.n-input--textarea) {
  --n-border: none !important;
  --n-border-focus: none !important;
  --n-border-hover: none !important;
  --n-box-shadow-focus: none !important;
}

:deep(.prompt-input .n-input-wrapper) {
  padding: 0;

  .n-scrollbar-rail,
  .n-scrollbar {
    --n-scrollbar-width: 0px !important;
    --n-scrollbar-height: 0px !important;
  }
}

:deep(.n-input__suffix),
:deep(.n-input-word-count) {
  font-size: 13px !important;
}

:deep(.prompt-input .n-input-word-count) {
  bottom: -12px !important;
  background: white !important;
}

:deep(.n-input--stateful) {
  --n-border-radius: 6px !important;

  font-size: 12px;
}
</style>
