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

const { t } = useI18n()

const router = useRouter()

const personalAppConfigStore = usePersonalAppConfigStore()
const userStore = useUserStore()

const { baseInfo, commConfig, commModelConfig, knowledgeConfig, databaseConfig, unitIds } =
  storeToRefs(personalAppConfigStore)

const emitter = inject<Emitter<MittEvents>>('emitter')

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

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

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 = {
  agentTitle: [
    {
      required: true,
      message: t(
        'personal_space_module.agent_module.agent_setting_module.agent_config_module.agent_title_input_rule_message',
      ),
      trigger: 'blur',
    },
  ],
}

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

watch(
  () => personalAppConfigStore.$state,
  () => {
    if (!baseInfo.value.agentId) {
      handleCreatePersonalAgent()
    }
  },
  { deep: true },
)

watch(
  () => personalAppConfigStore.$state,
  () => {
    handleSavePersonalAppConfig()
  },
  { deep: true },
)

onMounted(async () => {
  await handleEquityInfoValidate()

  emitter?.on('isGetAgentDetail', () => {
    ;['preamble', 'featuredQuestions']
      .filter((property) => {
        const commConfigProperty = commConfig.value[property as keyof PersonalAppConfigState['commConfig']]
        return commConfigProperty && !(Array.isArray(commConfigProperty) && commConfigProperty.length === 0)
      })
      .forEach((property) => {
        commConfigExpandedNames.value.push(property)
      })
  })
})

onUnmounted(() => {
  handleStopGenerate()
  emitter?.off('isGetAgentDetail')
})

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

// 更新保存应用配置
async function handleSaveAgentApplication() {
  if (!baseInfo.value.agentTitle) {
    return
  }

  await fetchSaveAgentApplication<PersonalAppConfigState>(personalAppConfigStore.$state)
}

// 新建应用
async function handleCreatePersonalAgent() {
  if (!baseInfo.value.agentTitle) {
    return
  }

  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 (!baseInfo.value.agentSystem) return

  isShowOptimizeAgentSystemModal.value = true
}

function handleSettingDefaultPrompt() {
  baseInfo.value.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() {
  if (generateAgentAvatarLoading.value || !baseInfo.value.agentTitle) {
    return
  }

  generateAgentAvatarLoading.value = true
  generateAgentAvatarController = new AbortController()

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

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

async function handleAIGeneratePreamble() {
  if (generatePreambleLoading.value) {
    return
  }

  !commConfigExpandedNames.value.includes('preamble') && commConfigExpandedNames.value.push('preamble')

  generatePreambleLoading.value = true

  generatePreambleController = new AbortController()

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

  if (res.code === 0) {
    try {
      const content = res.data.replace(/^```json|```$/g, '')
      const preamble = JSON.parse(content)['output']
      commConfig.value.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() {
  if (generateFeaturedQuestionsLoading.value) {
    return
  }

  !commConfigExpandedNames.value.includes('featuredQuestions') &&
    commConfigExpandedNames.value.push('featuredQuestions')

  generateFeaturedQuestionsLoading.value = true
  generateFeaturedQuestionsController = new AbortController()

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

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

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

  await handleCreateAgentTitleAndDesc(autoConfigInputValue)
    .then(() => {
      personalAppFormRef.value?.validate()
      Promise.all([
        handleAIGenerateAgentAvatar(),
        handleAIGeneratePreamble(),
        handleAIGenerateFeaturedQuestions(),
        handleAIGenerateAgentSystem(),
      ])
        .finally(() => {
          isFullScreenLoading.value = false
          emitter?.emit('resetAgent')
        })
        .catch(() => {
          handleStopGenerate()
        })
    })
    .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) {
    baseInfo.value.agentTitle = res.data.agentTitle
    baseInfo.value.agentDesc = res.data.agentDesc
  }
}

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

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

    fetchCustomEventSource({
      path: '/api/rest/agentApplicationInfoRest/createAgentSystem.json',
      payload: {
        input: personalAppConfigStore.baseInfo.agentTitle || personalAppConfigStore.baseInfo.agentSystem,
      },
      controller: generateAgentSystemController,
      onResponse: (data) => {
        if (data && data.message) {
          useThrottleFn(
            () => {
              nextTick(() => {
                baseInfo.value.agentSystem += data.message
                agentSystemInputRef.value!.textareaElRef!.scrollTop =
                  agentSystemInputRef.value?.textareaElRef?.scrollHeight || 0
              })
            },
            1000,
            true,
          )()
        }
      },
      onRequestError: () => {
        reject()
        blockAnswerResponse()
      },
      onError: () => {
        reject()
        blockAnswerResponse()
      },
      onFinally: () => {
        blockAnswerResponse()
        resolve('')
        generateAgentSystemController = null
      },
    })
  })
}

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

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

async function handleEquityInfoValidate() {
  if (!userStore.isLogin) {
    router.push({
      name: 'Login',
      query: { redirect: encodeURIComponent(router.currentRoute.value.fullPath) },
    })
  }

  await userStore.fetchUpdateEquityInfo()

  if (
    userStore.equityInfo.usedAgentCount >= userStore.equityInfo.maxAgentCount &&
    userStore.equityInfo.maxAgentCount !== 0 &&
    !baseInfo.value.agentId
  ) {
    window.$message
      .ctWarning(t('equity_module.agents_created_exceeds_tip'), '', t('common_module.back'))
      .then(() => {
        router.replace({ name: 'Equity' })
      })
      .catch(() => {
        router.back()
      })
  }
}
</script>

<template>
  <div class="flex h-full flex-[3_3_0%] flex-col overflow-hidden">
    <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:comm-model-config="commModelConfig" />
    </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="['baseInfo']" class="px-5" display-directive="show">
          <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="baseInfo"
            class="my-[13px]!"
          >
            <div class="justify-left flex items-start pl-5">
              <div class="relative mr-2 w-[72px]">
                <UploadImage
                  v-model:image-url="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]"
                >
                  <LoadingOne theme="outline" size="18" fill="#fff" :stroke-width="3" />
                </div>

                <div
                  class="text-theme-color flex-center mt-3 h-[28px] gap-[5px] rounded-md border border-[#d4d6d9] px-2"
                  :class="
                    generateAgentAvatarLoading || !baseInfo.agentTitle
                      ? 'cursor-not-allowed opacity-50'
                      : 'cursor-pointer hover:border-[#d4e5ff] hover:bg-[#e6f0ff]'
                  "
                  @click="handleAIGenerateAgentAvatar"
                >
                  <div
                    class="mt-[-2px] h-[14px] w-[14px] bg-[length:100%_100%]"
                    :class="
                      generateAgentAvatarLoading
                        ? 'bg-[url(@/assets/images/loading.gif)]'
                        : 'bg-[url(@/assets/svgs/star.svg)]'
                    "
                  />
                  <span class="text-xs">
                    {{
                      t(
                        'personal_space_module.agent_module.agent_setting_module.agent_config_module.ai_generate_picture',
                      )
                    }}
                  </span>
                </div>
              </div>
              <div class="flex flex-1">
                <NForm
                  ref="personalAppFormRef"
                  :model="baseInfo"
                  :rules="personalAppRules"
                  label-placement="left"
                  class="flex-1"
                >
                  <NFormItem feedback-class="p-0.5! text-xs!" path="agentTitle">
                    <NInput
                      v-model:value="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="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="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"
                  >
                    <NotebookOne theme="outline" size="16" fill="#000DFF" :stroke-width="3" class="mr-3" />
                    <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="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="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">
          <TrendTwo theme="filled" size="18" fill="#333" class="mr-1.5" :stroke-width="3" />
          <span>
            {{ t('personal_space_module.agent_module.agent_setting_module.agent_config_module.ability_expand') }}
          </span>
        </div>

        <div class="flex-1 overflow-auto">
          <AgentPlugin v-model:unit-ids="unitIds" />

          <AgentAssociatedKnowledge
            v-model:knowledge-config="knowledgeConfig"
            v-model:database-config="databaseConfig"
          />

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

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

          <AgentRoleSetting />
        </div>
      </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>
