'use client'
import type { FC } from 'react'
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import useSWR from 'swr'
import { basePath } from '@/utils/var'
import { useTranslation } from 'react-i18next'
import { useContext } from 'use-context-selector'
import { usePathname } from 'next/navigation'
import produce from 'immer'
import { useBoolean, useGetState } from 'ahooks'
import { clone, isEqual } from 'lodash-es'
import { CodeBracketIcon } from '@heroicons/react/20/solid'
import { useShallow } from 'zustand/react/shallow'
import AgentSettingButton from '@/app/components/app/configuration/config/agent-setting-button'
import useAdvancedPromptConfig from '@/app/components/app/configuration/hooks/use-advanced-prompt-config'
import EditHistoryModal from '@/app/components/app/configuration/config-prompt/conversation-history/edit-modal'
import {
  useDebugWithSingleOrMultipleModel,
  useFormattingChangedDispatcher,
} from '@/app/components/app/configuration/debug/hooks'
import type { ModelAndParameter } from '@/app/components/app/configuration/debug/types'
import Button from '@/app/components/base/button'
import Divider from '@/app/components/base/divider'
import Loading from '@/app/components/base/loading'
import AppPublisher from '@/app/components/app/app-publisher/features-wrapper'
import type {
  AnnotationReplyConfig,
  DatasetConfigs,
  Inputs,
  ModelConfig,
  ModerationConfig,
  MoreLikeThisConfig,
  PromptConfig,
  PromptVariable,
  TextToSpeechConfig,
} from '@/models/debug'
import type { ExternalDataTool } from '@/models/common'
import type { DataSet } from '@/models/datasets'
import type { ModelConfig as BackendModelConfig, VisionSettings } from '@/types/app'
import ConfigContext from '@/context/debug-configuration'
import Config from '@/app/components/app/configuration/config'
import Debug from '@/app/components/app/configuration/debug'
import Confirm from '@/app/components/base/confirm'
import { ModelFeatureEnum, ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
import { ToastContext } from '@/app/components/base/toast'
import { fetchAppDetail, updateAppModelConfig } from '@/service/apps'
import { promptVariablesToUserInputsForm, userInputsFormToPromptVariables } from '@/utils/model-config'
import { fetchDatasets } from '@/service/datasets'
import { useProviderContext } from '@/context/provider-context'
import { AgentStrategy, AppType, ModelModeType, RETRIEVE_TYPE, Resolution, TransferMethod } from '@/types/app'
import { PromptMode } from '@/models/debug'
import { ANNOTATION_DEFAULT, DATASET_DEFAULT, DEFAULT_AGENT_SETTING, DEFAULT_CHAT_PROMPT_CONFIG, DEFAULT_COMPLETION_PROMPT_CONFIG } from '@/config'
import SelectDataSet from '@/app/components/app/configuration/dataset-config/select-dataset'
import { useModalContext } from '@/context/modal-context'
import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
import Drawer from '@/app/components/base/drawer'
import ModelParameterModal from '@/app/components/header/account-setting/model-provider-page/model-parameter-modal'
import type { FormValue } from '@/app/components/header/account-setting/model-provider-page/declarations'
import {
  useModelListAndDefaultModelAndCurrentProviderAndModel,
  useTextGenerationCurrentProviderAndModelAndModelList,
} from '@/app/components/header/account-setting/model-provider-page/hooks'
import type { Collection } from '@/app/components/tools/types'
import { useStore as useAppStore } from '@/app/components/app/store'
import {
  getMultipleRetrievalConfig,
  getSelectedDatasetsMode,
} from '@/app/components/workflow/nodes/knowledge-retrieval/utils'
import { FeaturesProvider } from '@/app/components/base/features'
import type { Features as FeaturesData, FileUpload } from '@/app/components/base/features/types'
import { FILE_EXTS } from '@/app/components/base/prompt-editor/constants'
import { SupportUploadFileTypes } from '@/app/components/workflow/types'
import NewFeaturePanel from '@/app/components/base/features/new-feature-panel'
import { fetchFileUploadConfig } from '@/service/common'
import {
  correctModelProvider,
  correctToolProvider,
} from '@/utils'
import PluginDependency from '@/app/components/workflow/plugin-dependency'
import { supportFunctionCall } from '@/utils/tool-call'
import { MittProvider } from '@/context/mitt-context'
import { fetchAndMergeValidCompletionParams } from '@/utils/completion-params'
import Toast from '@/app/components/base/toast'
import { fetchCollectionList } from '@/service/tools'
import { useAppContext } from '@/context/app-context'

type PublishConfig = {
  modelConfig: ModelConfig
  completionParams: FormValue
}

const Configuration: FC = () => {
  const { t } = useTranslation()
  const { notify } = useContext(ToastContext)
  const { isLoadingCurrentWorkspace, currentWorkspace } = useAppContext()

  const { appDetail, showAppConfigureFeaturesModal, setAppSidebarExpand, setShowAppConfigureFeaturesModal } = useAppStore(useShallow(state => ({
    appDetail: state.appDetail,
    setAppSidebarExpand: state.setAppSidebarExpand,
    showAppConfigureFeaturesModal: state.showAppConfigureFeaturesModal,
    setShowAppConfigureFeaturesModal: state.setShowAppConfigureFeaturesModal,
  })))
  const { data: fileUploadConfigResponse } = useSWR({ url: '/files/upload' }, fetchFileUploadConfig)

  const latestPublishedAt = useMemo(() => appDetail?.model_config?.updated_at, [appDetail])
  const [formattingChanged, setFormattingChanged] = useState(false)
  const { setShowAccountSettingModal } = useModalContext()
  const [hasFetchedDetail, setHasFetchedDetail] = useState(false)
  const isLoading = !hasFetchedDetail
  const pathname = usePathname()
  const matched = pathname.match(/\/app\/([^/]+)/)
  const appId = (matched?.length && matched[1]) ? matched[1] : ''
  const [mode, setMode] = useState('')
  const [publishedConfig, setPublishedConfig] = useState<PublishConfig | null>(null)

  const [conversationId, setConversationId] = useState<string | null>('')

  const media = useBreakpoints()
  const isMobile = media === MediaType.mobile
  const [isShowDebugPanel, { setTrue: showDebugPanel, setFalse: hideDebugPanel }] = useBoolean(false)

  const [introduction, setIntroduction] = useState<string>('')
  const [suggestedQuestions, setSuggestedQuestions] = useState<string[]>([])
  const [controlClearChatMessage, setControlClearChatMessage] = useState(0)
  const [prevPromptConfig, setPrevPromptConfig] = useState<PromptConfig>({
    prompt_template: '',
    prompt_variables: [],
  })
  const [moreLikeThisConfig, setMoreLikeThisConfig] = useState<MoreLikeThisConfig>({
    enabled: false,
  })
  const [suggestedQuestionsAfterAnswerConfig, setSuggestedQuestionsAfterAnswerConfig] = useState<MoreLikeThisConfig>({
    enabled: false,
  })
  const [speechToTextConfig, setSpeechToTextConfig] = useState<MoreLikeThisConfig>({
    enabled: false,
  })
  const [textToSpeechConfig, setTextToSpeechConfig] = useState<TextToSpeechConfig>({
    enabled: false,
    voice: '',
    language: '',
  })
  const [citationConfig, setCitationConfig] = useState<MoreLikeThisConfig>({
    enabled: false,
  })
  const [annotationConfig, doSetAnnotationConfig] = useState<AnnotationReplyConfig>({
    id: '',
    enabled: false,
    score_threshold: ANNOTATION_DEFAULT.score_threshold,
    embedding_model: {
      embedding_provider_name: '',
      embedding_model_name: '',
    },
  })
  const formattingChangedDispatcher = useFormattingChangedDispatcher()
  const setAnnotationConfig = (config: AnnotationReplyConfig, notSetFormatChanged?: boolean) => {
    doSetAnnotationConfig(config)
    if (!notSetFormatChanged)
      formattingChangedDispatcher()
  }

  const [moderationConfig, setModerationConfig] = useState<ModerationConfig>({
    enabled: false,
  })
  const [externalDataToolsConfig, setExternalDataToolsConfig] = useState<ExternalDataTool[]>([])
  const [inputs, setInputs] = useState<Inputs>({})
  const [query, setQuery] = useState('')
  const [completionParams, doSetCompletionParams] = useState<FormValue>({})
  const [_, setTempStop, getTempStop] = useGetState<string[]>([])
  const setCompletionParams = (value: FormValue) => {
    const params = { ...value }

    // eslint-disable-next-line ts/no-use-before-define
    if ((!params.stop || params.stop.length === 0) && (modeModeTypeRef.current === ModelModeType.completion)) {
      params.stop = getTempStop()
      setTempStop([])
    }
    doSetCompletionParams(params)
  }

  const [modelConfig, doSetModelConfig] = useState<ModelConfig>({
    provider: 'langgenius/openai/openai',
    model_id: 'gpt-3.5-turbo',
    mode: ModelModeType.unset,
    configs: {
      prompt_template: '',
      prompt_variables: [] as PromptVariable[],
    },
    more_like_this: null,
    opening_statement: '',
    suggested_questions: [],
    sensitive_word_avoidance: null,
    speech_to_text: null,
    text_to_speech: null,
    file_upload: null,
    suggested_questions_after_answer: null,
    retriever_resource: null,
    annotation_reply: null,
    dataSets: [],
    agentConfig: DEFAULT_AGENT_SETTING,
  })
  const isAgent = mode === 'agent-chat'

  const isOpenAI = modelConfig.provider === 'langgenius/openai/openai'

  const [collectionList, setCollectionList] = useState<Collection[]>([])
  const [datasetConfigs, doSetDatasetConfigs] = useState<DatasetConfigs>({
    retrieval_model: RETRIEVE_TYPE.multiWay,
    reranking_model: {
      reranking_provider_name: '',
      reranking_model_name: '',
    },
    top_k: DATASET_DEFAULT.top_k,
    score_threshold_enabled: false,
    score_threshold: DATASET_DEFAULT.score_threshold,
    datasets: {
      datasets: [],
    },
  })
  const datasetConfigsRef = useRef(datasetConfigs)
  const setDatasetConfigs = useCallback((newDatasetConfigs: DatasetConfigs) => {
    doSetDatasetConfigs(newDatasetConfigs)
    datasetConfigsRef.current = newDatasetConfigs
  }, [])

  const setModelConfig = (newModelConfig: ModelConfig) => {
    doSetModelConfig(newModelConfig)
  }

  const modelModeType = modelConfig.mode
  const modeModeTypeRef = useRef(modelModeType)
  useEffect(() => {
    modeModeTypeRef.current = modelModeType
  }, [modelModeType])

  const [dataSets, setDataSets] = useState<DataSet[]>([])
  const contextVar = modelConfig.configs.prompt_variables.find(item => item.is_context_var)?.key
  const hasSetContextVar = !!contextVar
  const [isShowSelectDataSet, { setTrue: showSelectDataSet, setFalse: hideSelectDataSet }] = useBoolean(false)
  const selectedIds = dataSets.map(item => item.id)
  const [rerankSettingModalOpen, setRerankSettingModalOpen] = useState(false)
  const {
    currentModel: currentRerankModel,
    currentProvider: currentRerankProvider,
  } = useModelListAndDefaultModelAndCurrentProviderAndModel(ModelTypeEnum.rerank)
  const handleSelect = (data: DataSet[]) => {
    if (isEqual(data.map(item => item.id), dataSets.map(item => item.id))) {
      hideSelectDataSet()
      return
    }

    formattingChangedDispatcher()
    let newDatasets = data
    if (data.find(item => !item.name)) { // has not loaded selected dataset
      const newSelected = produce(data, (draft) => {
        data.forEach((item, index) => {
          if (!item.name) { // not fetched database
            const newItem = dataSets.find(i => i.id === item.id)
            if (newItem)
              draft[index] = newItem
          }
        })
      })
      setDataSets(newSelected)
      newDatasets = newSelected
    }
    else {
      setDataSets(data)
    }
    hideSelectDataSet()
    const {
      allExternal,
      allInternal,
      mixtureInternalAndExternal,
      mixtureHighQualityAndEconomic,
      inconsistentEmbeddingModel,
    } = getSelectedDatasetsMode(newDatasets)

    if (
      (allInternal && (mixtureHighQualityAndEconomic || inconsistentEmbeddingModel))
      || mixtureInternalAndExternal
      || allExternal
    )
      setRerankSettingModalOpen(true)

    const { datasets, retrieval_model, score_threshold_enabled, ...restConfigs } = datasetConfigs

    const retrievalConfig = getMultipleRetrievalConfig({
      top_k: restConfigs.top_k,
      score_threshold: restConfigs.score_threshold,
      reranking_model: restConfigs.reranking_model && {
        provider: restConfigs.reranking_model.reranking_provider_name,
        model: restConfigs.reranking_model.reranking_model_name,
      },
      reranking_mode: restConfigs.reranking_mode,
      weights: restConfigs.weights,
      reranking_enable: restConfigs.reranking_enable,
    }, newDatasets, dataSets, {
      provider: currentRerankProvider?.provider,
      model: currentRerankModel?.model,
    })

    setDatasetConfigs({
      ...datasetConfigsRef.current,
      ...retrievalConfig,
      reranking_model: {
        reranking_provider_name: retrievalConfig?.reranking_model?.provider || '',
        reranking_model_name: retrievalConfig?.reranking_model?.model || '',
      },
      retrieval_model,
      score_threshold_enabled,
      datasets,
    })
  }

  const [isShowHistoryModal, { setTrue: showHistoryModal, setFalse: hideHistoryModal }] = useBoolean(false)

  const syncToPublishedConfig = (_publishedConfig: PublishConfig) => {
    const modelConfig = _publishedConfig.modelConfig
    setModelConfig(_publishedConfig.modelConfig)
    setCompletionParams(_publishedConfig.completionParams)
    setDataSets(modelConfig.dataSets || [])
    // reset feature
    setIntroduction(modelConfig.opening_statement!)
    setMoreLikeThisConfig(modelConfig.more_like_this || {
      enabled: false,
    })
    setSuggestedQuestionsAfterAnswerConfig(modelConfig.suggested_questions_after_answer || {
      enabled: false,
    })
    setSpeechToTextConfig(modelConfig.speech_to_text || {
      enabled: false,
    })
    setTextToSpeechConfig(modelConfig.text_to_speech || {
      enabled: false,
      voice: '',
      language: '',
    })
    setCitationConfig(modelConfig.retriever_resource || {
      enabled: false,
    })
  }

  const { isAPIKeySet } = useProviderContext()
  const {
    currentModel: currModel,
    textGenerationModelList,
  } = useTextGenerationCurrentProviderAndModelAndModelList(
    {
      provider: modelConfig.provider,
      model: modelConfig.model_id,
    },
  )

  const isFunctionCall = supportFunctionCall(currModel?.features)

  // Fill old app data missing model mode.
  useEffect(() => {
    if (hasFetchedDetail && !modelModeType) {
      const mode = currModel?.model_properties.mode as (ModelModeType | undefined)
      if (mode) {
        const newModelConfig = produce(modelConfig, (draft: ModelConfig) => {
          draft.mode = mode
        })
        setModelConfig(newModelConfig)
      }
    }
  }, [textGenerationModelList, hasFetchedDetail, modelModeType, currModel, modelConfig])

  const [promptMode, doSetPromptMode] = useState(PromptMode.simple)
  const isAdvancedMode = promptMode === PromptMode.advanced
  const [canReturnToSimpleMode, setCanReturnToSimpleMode] = useState(true)
  const setPromptMode = async (mode: PromptMode) => {
    if (mode === PromptMode.advanced) {
      // eslint-disable-next-line ts/no-use-before-define
      await migrateToDefaultPrompt()
      setCanReturnToSimpleMode(true)
    }

    doSetPromptMode(mode)
  }
  const [visionConfig, doSetVisionConfig] = useState({
    enabled: false,
    number_limits: 2,
    detail: Resolution.low,
    transfer_methods: [TransferMethod.local_file],
  })

  const handleSetVisionConfig = (config: VisionSettings, notNoticeFormattingChanged?: boolean) => {
    doSetVisionConfig({
      enabled: config.enabled || false,
      number_limits: config.number_limits || 2,
      detail: config.detail || Resolution.low,
      transfer_methods: config.transfer_methods || [TransferMethod.local_file],
    })
    if (!notNoticeFormattingChanged)
      formattingChangedDispatcher()
  }

  const {
    chatPromptConfig,
    setChatPromptConfig,
    completionPromptConfig,
    setCompletionPromptConfig,
    currentAdvancedPrompt,
    setCurrentAdvancedPrompt,
    hasSetBlockStatus,
    setConversationHistoriesRole,
    migrateToDefaultPrompt,
  } = useAdvancedPromptConfig({
    appMode: mode,
    modelName: modelConfig.model_id,
    promptMode,
    modelModeType,
    prePrompt: modelConfig.configs.prompt_template,
    hasSetDataSet: dataSets.length > 0,
    onUserChangedPrompt: () => {
      setCanReturnToSimpleMode(false)
    },
    completionParams,
    setCompletionParams,
    setStop: setTempStop,
  })
  const setModel = async ({
    modelId,
    provider,
    mode: modeMode,
    features,
  }: { modelId: string; provider: string; mode: string; features: string[] }) => {
    if (isAdvancedMode) {
      const appMode = mode

      if (modeMode === ModelModeType.completion) {
        if (appMode !== AppType.completion) {
          if (!completionPromptConfig.prompt?.text || !completionPromptConfig.conversation_histories_role.assistant_prefix || !completionPromptConfig.conversation_histories_role.user_prefix)
            await migrateToDefaultPrompt(true, ModelModeType.completion)
        }
        else {
          if (!completionPromptConfig.prompt?.text)
            await migrateToDefaultPrompt(true, ModelModeType.completion)
        }
      }
      if (modeMode === ModelModeType.chat) {
        if (chatPromptConfig.prompt.length === 0)
          await migrateToDefaultPrompt(true, ModelModeType.chat)
      }
    }
    const newModelConfig = produce(modelConfig, (draft: ModelConfig) => {
      draft.provider = provider
      draft.model_id = modelId
      draft.mode = modeMode as ModelModeType
    })

    setModelConfig(newModelConfig)
    const supportVision = features && features.includes(ModelFeatureEnum.vision)

    handleSetVisionConfig({
      ...visionConfig,
      enabled: supportVision,
    }, true)

    try {
      const { params: filtered, removedDetails } = await fetchAndMergeValidCompletionParams(
        provider,
        modelId,
        completionParams,
        isAdvancedMode,
      )
      if (Object.keys(removedDetails).length)
        Toast.notify({ type: 'warning', message: `${t('common.modelProvider.parametersInvalidRemoved')}: ${Object.entries(removedDetails).map(([k, reason]) => `${k} (${reason})`).join(', ')}` })
      setCompletionParams(filtered)
    }
    catch (e) {
      Toast.notify({ type: 'error', message: t('common.error') })
      setCompletionParams({})
    }
  }

  const isShowVisionConfig = !!currModel?.features?.includes(ModelFeatureEnum.vision)
  const isShowDocumentConfig = !!currModel?.features?.includes(ModelFeatureEnum.document)
  const isShowAudioConfig = !!currModel?.features?.includes(ModelFeatureEnum.audio)
  const isAllowVideoUpload = !!currModel?.features?.includes(ModelFeatureEnum.video)
  // *** web app features ***
  const featuresData: FeaturesData = useMemo(() => {
    return {
      moreLikeThis: modelConfig.more_like_this || { enabled: false },
      opening: {
        enabled: !!modelConfig.opening_statement,
        opening_statement: modelConfig.opening_statement || '',
        suggested_questions: modelConfig.suggested_questions || [],
      },
      moderation: modelConfig.sensitive_word_avoidance || { enabled: false },
      speech2text: modelConfig.speech_to_text || { enabled: false },
      text2speech: modelConfig.text_to_speech || { enabled: false },
      file: {
        image: {
          detail: modelConfig.file_upload?.image?.detail || Resolution.high,
          enabled: !!modelConfig.file_upload?.image?.enabled,
          number_limits: modelConfig.file_upload?.image?.number_limits || 3,
          transfer_methods: modelConfig.file_upload?.image?.transfer_methods || ['local_file', 'remote_url'],
        },
        enabled: !!(modelConfig.file_upload?.enabled || modelConfig.file_upload?.image?.enabled),
        allowed_file_types: modelConfig.file_upload?.allowed_file_types || [],
        allowed_file_extensions: modelConfig.file_upload?.allowed_file_extensions || [...FILE_EXTS[SupportUploadFileTypes.image], ...FILE_EXTS[SupportUploadFileTypes.video]].map(ext => `.${ext}`),
        allowed_file_upload_methods: modelConfig.file_upload?.allowed_file_upload_methods || modelConfig.file_upload?.image?.transfer_methods || ['local_file', 'remote_url'],
        number_limits: modelConfig.file_upload?.number_limits || modelConfig.file_upload?.image?.number_limits || 3,
        fileUploadConfig: fileUploadConfigResponse,
      } as FileUpload,
      suggested: modelConfig.suggested_questions_after_answer || { enabled: false },
      citation: modelConfig.retriever_resource || { enabled: false },
      annotationReply: modelConfig.annotation_reply || { enabled: false },
    }
  }, [fileUploadConfigResponse, modelConfig])
  const handleFeaturesChange = useCallback((flag: any) => {
    setShowAppConfigureFeaturesModal(true)
    if (flag)
      formattingChangedDispatcher()
  }, [formattingChangedDispatcher, setShowAppConfigureFeaturesModal])
  const handleAddPromptVariable = useCallback((variable: PromptVariable[]) => {
    const newModelConfig = produce(modelConfig, (draft: ModelConfig) => {
      draft.configs.prompt_variables = [...draft.configs.prompt_variables, ...variable]
    })
    setModelConfig(newModelConfig)
  }, [modelConfig])

  useEffect(() => {
    (async () => {
      const collectionList = await fetchCollectionList()
      if (basePath) {
        collectionList.forEach((item) => {
          if (typeof item.icon == 'string' && !item.icon.includes(basePath))
            item.icon = `${basePath}${item.icon}`
        })
      }
      setCollectionList(collectionList)
      fetchAppDetail({ url: '/apps', id: appId }).then(async (res: any) => {
        setMode(res.mode)
        const modelConfig = res.model_config
        const promptMode = modelConfig.prompt_type === PromptMode.advanced ? PromptMode.advanced : PromptMode.simple
        doSetPromptMode(promptMode)
        if (promptMode === PromptMode.advanced) {
          if (modelConfig.chat_prompt_config && modelConfig.chat_prompt_config.prompt.length > 0)
            setChatPromptConfig(modelConfig.chat_prompt_config)
          else
            setChatPromptConfig(clone(DEFAULT_CHAT_PROMPT_CONFIG))
          setCompletionPromptConfig(modelConfig.completion_prompt_config || clone(DEFAULT_COMPLETION_PROMPT_CONFIG) as any)
          setCanReturnToSimpleMode(false)
        }

        const model = res.model_config.model

        let datasets: any = null
        // old dataset struct
        if (modelConfig.agent_mode?.tools?.find(({ dataset }: any) => dataset?.enabled))
          datasets = modelConfig.agent_mode?.tools.filter(({ dataset }: any) => dataset?.enabled)
        // new dataset struct
        else if (modelConfig.dataset_configs.datasets?.datasets?.length > 0)
          datasets = modelConfig.dataset_configs?.datasets?.datasets

        if (dataSets && datasets?.length && datasets?.length > 0) {
          const { data: dataSetsWithDetail } = await fetchDatasets({ url: '/datasets', params: { page: 1, ids: datasets.map(({ dataset }: any) => dataset.id) } })
          datasets = dataSetsWithDetail
          setDataSets(datasets)
        }

        setIntroduction(modelConfig.opening_statement)
        setSuggestedQuestions(modelConfig.suggested_questions || [])
        if (modelConfig.more_like_this)
          setMoreLikeThisConfig(modelConfig.more_like_this)

        if (modelConfig.suggested_questions_after_answer)
          setSuggestedQuestionsAfterAnswerConfig(modelConfig.suggested_questions_after_answer)

        if (modelConfig.speech_to_text)
          setSpeechToTextConfig(modelConfig.speech_to_text)

        if (modelConfig.text_to_speech)
          setTextToSpeechConfig(modelConfig.text_to_speech)

        if (modelConfig.retriever_resource)
          setCitationConfig(modelConfig.retriever_resource)

        if (modelConfig.annotation_reply) {
          let annotationConfig = modelConfig.annotation_reply
          if (modelConfig.annotation_reply.enabled) {
            annotationConfig = {
              ...modelConfig.annotation_reply,
              embedding_model: {
                ...modelConfig.annotation_reply.embedding_model,
                embedding_provider_name: correctModelProvider(modelConfig.annotation_reply.embedding_model.embedding_provider_name),
              },
            }
          }
          setAnnotationConfig(annotationConfig, true)
        }

        if (modelConfig.sensitive_word_avoidance)
          setModerationConfig(modelConfig.sensitive_word_avoidance)

        if (modelConfig.external_data_tools)
          setExternalDataToolsConfig(modelConfig.external_data_tools)

        const config = {
          modelConfig: {
            provider: correctModelProvider(model.provider),
            model_id: model.name,
            mode: model.mode,
            configs: {
              prompt_template: modelConfig.pre_prompt || '',
              prompt_variables: userInputsFormToPromptVariables(
                [
                  ...modelConfig.user_input_form,
                  ...(
                    modelConfig.external_data_tools?.length
                      ? modelConfig.external_data_tools.map((item: any) => {
                        return {
                          external_data_tool: {
                            variable: item.variable as string,
                            label: item.label as string,
                            enabled: item.enabled,
                            type: item.type as string,
                            config: item.config,
                            required: true,
                            icon: item.icon,
                            icon_background: item.icon_background,
                          },
                        }
                      })
                      : []
                  ),
                ],
                modelConfig.dataset_query_variable,
              ),
            },
            more_like_this: modelConfig.more_like_this,
            opening_statement: modelConfig.opening_statement,
            suggested_questions: modelConfig.suggested_questions,
            sensitive_word_avoidance: modelConfig.sensitive_word_avoidance,
            speech_to_text: modelConfig.speech_to_text,
            text_to_speech: modelConfig.text_to_speech,
            file_upload: modelConfig.file_upload,
            suggested_questions_after_answer: modelConfig.suggested_questions_after_answer,
            retriever_resource: modelConfig.retriever_resource,
            annotation_reply: modelConfig.annotation_reply,
            external_data_tools: modelConfig.external_data_tools,
            dataSets: datasets || [],
            agentConfig: res.mode === 'agent-chat' ? {
              max_iteration: DEFAULT_AGENT_SETTING.max_iteration,
              ...modelConfig.agent_mode,
              // remove dataset
              enabled: true, // modelConfig.agent_mode?.enabled is not correct. old app: the value of app with dataset's is always true
              tools: modelConfig.agent_mode?.tools.filter((tool: any) => {
                return !tool.dataset
              }).map((tool: any) => {
                const toolInCollectionList = collectionList.find(c => tool.provider_id === c.id)
                return {
                  ...tool,
                  isDeleted: res.deleted_tools?.some((deletedTool: any) => deletedTool.id === tool.id && deletedTool.tool_name === tool.tool_name),
                  notAuthor: toolInCollectionList?.is_team_authorization === false,
                  ...(tool.provider_type === 'builtin' ? {
                    provider_id: correctToolProvider(tool.provider_name, !!toolInCollectionList),
                    provider_name: correctToolProvider(tool.provider_name, !!toolInCollectionList),
                  } : {}),
                }
              }),
            } : DEFAULT_AGENT_SETTING,
          },
          completionParams: model.completion_params,
        }

        if (modelConfig.file_upload)
          handleSetVisionConfig(modelConfig.file_upload.image, true)

        syncToPublishedConfig(config)
        setPublishedConfig(config)
        const retrievalConfig = getMultipleRetrievalConfig({
          ...modelConfig.dataset_configs,
          reranking_model: modelConfig.dataset_configs.reranking_model && {
            provider: modelConfig.dataset_configs.reranking_model.reranking_provider_name,
            model: modelConfig.dataset_configs.reranking_model.reranking_model_name,
          },
        }, datasets, datasets, {
          provider: currentRerankProvider?.provider,
          model: currentRerankModel?.model,
        })
        setDatasetConfigs({
          retrieval_model: RETRIEVE_TYPE.multiWay,
          ...modelConfig.dataset_configs,
          ...retrievalConfig,
          ...(retrievalConfig.reranking_model ? {
            reranking_model: {
              reranking_model_name: retrievalConfig.reranking_model.model,
              reranking_provider_name: correctModelProvider(retrievalConfig.reranking_model.provider),
            },
          } : {}),
        })
        setHasFetchedDetail(true)
      })
    })()
  }, [appId])

  const promptEmpty = (() => {
    if (mode !== AppType.completion)
      return false

    if (isAdvancedMode) {
      if (modelModeType === ModelModeType.chat)
        return chatPromptConfig.prompt.every(({ text }: any) => !text)

      else
        return !completionPromptConfig.prompt?.text
    }

    else { return !modelConfig.configs.prompt_template }
  })()
  const cannotPublish = (() => {
    if (mode !== AppType.completion) {
      if (!isAdvancedMode)
        return false

      if (modelModeType === ModelModeType.completion) {
        if (!hasSetBlockStatus.history || !hasSetBlockStatus.query)
          return true

        return false
      }

      return false
    }
    else { return promptEmpty }
  })()
  const contextVarEmpty = mode === AppType.completion && dataSets.length > 0 && !hasSetContextVar
  const onPublish = async (modelAndParameter?: ModelAndParameter, features?: FeaturesData) => {
    const modelId = modelAndParameter?.model || modelConfig.model_id
    const promptTemplate = modelConfig.configs.prompt_template
    const promptVariables = modelConfig.configs.prompt_variables

    if (promptEmpty) {
      notify({ type: 'error', message: t('appDebug.otherError.promptNoBeEmpty') })
      return
    }
    if (isAdvancedMode && mode !== AppType.completion) {
      if (modelModeType === ModelModeType.completion) {
        if (!hasSetBlockStatus.history) {
          notify({ type: 'error', message: t('appDebug.otherError.historyNoBeEmpty') })
          return
        }
        if (!hasSetBlockStatus.query) {
          notify({ type: 'error', message: t('appDebug.otherError.queryNoBeEmpty') })
          return
        }
      }
    }
    if (contextVarEmpty) {
      notify({ type: 'error', message: t('appDebug.feature.dataSet.queryVariable.contextVarNotEmpty') })
      return
    }
    const postDatasets = dataSets.map(({ id }) => ({
      dataset: {
        enabled: true,
        id,
      },
    }))

    const fileUpload = { ...features?.file }
    delete fileUpload?.fileUploadConfig

    // new model config data struct
    const data: BackendModelConfig = {
      // Simple Mode prompt
      pre_prompt: !isAdvancedMode ? promptTemplate : '',
      prompt_type: promptMode,
      chat_prompt_config: {},
      completion_prompt_config: {},
      user_input_form: promptVariablesToUserInputsForm(promptVariables),
      dataset_query_variable: contextVar || '',
      //  features
      more_like_this: features?.moreLikeThis as any,
      opening_statement: features?.opening?.enabled ? (features.opening?.opening_statement || '') : '',
      suggested_questions: features?.opening?.enabled ? (features.opening?.suggested_questions || []) : [],
      sensitive_word_avoidance: features?.moderation as any,
      speech_to_text: features?.speech2text as any,
      text_to_speech: features?.text2speech as any,
      file_upload: fileUpload as any,
      suggested_questions_after_answer: features?.suggested as any,
      retriever_resource: features?.citation as any,
      agent_mode: {
        ...modelConfig.agentConfig,
        strategy: isFunctionCall ? AgentStrategy.functionCall : AgentStrategy.react,
      },
      model: {
        provider: modelAndParameter?.provider || modelConfig.provider,
        name: modelId,
        mode: modelConfig.mode,
        completion_params: modelAndParameter?.parameters || completionParams as any,
      },
      dataset_configs: {
        ...datasetConfigs,
        datasets: {
          datasets: [...postDatasets],
        } as any,
      },
    }

    if (isAdvancedMode) {
      data.chat_prompt_config = chatPromptConfig
      data.completion_prompt_config = completionPromptConfig
    }

    await updateAppModelConfig({ url: `/apps/${appId}/model-config`, body: data })
    const newModelConfig = produce(modelConfig, (draft: any) => {
      draft.opening_statement = introduction
      draft.more_like_this = moreLikeThisConfig
      draft.suggested_questions_after_answer = suggestedQuestionsAfterAnswerConfig
      draft.speech_to_text = speechToTextConfig
      draft.text_to_speech = textToSpeechConfig
      draft.retriever_resource = citationConfig
      draft.dataSets = dataSets
    })
    setPublishedConfig({
      modelConfig: newModelConfig,
      completionParams,
    })
    notify({ type: 'success', message: t('common.api.success') })

    setCanReturnToSimpleMode(false)
    return true
  }

  const [showUseGPT4Confirm, setShowUseGPT4Confirm] = useState(false)

  const {
    debugWithMultipleModel,
    multipleModelConfigs,
    handleMultipleModelConfigsChange,
  } = useDebugWithSingleOrMultipleModel(appId)

  const handleDebugWithMultipleModelChange = () => {
    handleMultipleModelConfigsChange(
      true,
      [
        { id: `${Date.now()}`, model: modelConfig.model_id, provider: modelConfig.provider, parameters: completionParams },
        { id: `${Date.now()}-no-repeat`, model: '', provider: '', parameters: {} },
      ],
    )
    setAppSidebarExpand('collapse')
  }

  if (isLoading || isLoadingCurrentWorkspace || !currentWorkspace.id) {
    return <div className='flex h-full items-center justify-center'>
      <Loading type='area' />
    </div>
  }
  const value = {
    appId,
    isAPIKeySet,
    isTrailFinished: false,
    mode,
    modelModeType,
    promptMode,
    isAdvancedMode,
    isAgent,
    isOpenAI,
    isFunctionCall,
    collectionList,
    setPromptMode,
    canReturnToSimpleMode,
    setCanReturnToSimpleMode,
    chatPromptConfig,
    completionPromptConfig,
    currentAdvancedPrompt,
    setCurrentAdvancedPrompt,
    conversationHistoriesRole: completionPromptConfig.conversation_histories_role,
    showHistoryModal,
    setConversationHistoriesRole,
    hasSetBlockStatus,
    conversationId,
    introduction,
    setIntroduction,
    suggestedQuestions,
    setSuggestedQuestions,
    setConversationId,
    controlClearChatMessage,
    setControlClearChatMessage,
    prevPromptConfig,
    setPrevPromptConfig,
    moreLikeThisConfig,
    setMoreLikeThisConfig,
    suggestedQuestionsAfterAnswerConfig,
    setSuggestedQuestionsAfterAnswerConfig,
    speechToTextConfig,
    setSpeechToTextConfig,
    textToSpeechConfig,
    setTextToSpeechConfig,
    citationConfig,
    setCitationConfig,
    annotationConfig,
    setAnnotationConfig,
    moderationConfig,
    setModerationConfig,
    externalDataToolsConfig,
    setExternalDataToolsConfig,
    formattingChanged,
    setFormattingChanged,
    inputs,
    setInputs,
    query,
    setQuery,
    completionParams,
    setCompletionParams,
    modelConfig,
    setModelConfig,
    showSelectDataSet,
    dataSets,
    setDataSets,
    datasetConfigs,
    datasetConfigsRef,
    setDatasetConfigs,
    hasSetContextVar,
    isShowVisionConfig,
    visionConfig,
    setVisionConfig: handleSetVisionConfig,
    isAllowVideoUpload,
    isShowDocumentConfig,
    isShowAudioConfig,
    rerankSettingModalOpen,
    setRerankSettingModalOpen,
  }
  return (
    <ConfigContext.Provider value={value}>
      <FeaturesProvider features={featuresData}>
        <MittProvider>
          <div className="flex h-full flex-col">
            <div className='relative flex h-[200px] grow pt-14'>
              {/* Header */}
              <div className='bg-default-subtle absolute left-0 top-0 h-14 w-full'>
                <div className='flex h-14 items-center justify-between px-6'>
                  <div className='flex items-center'>
                    <div className='system-xl-semibold text-text-primary'>{t('appDebug.orchestrate')}</div>
                    <div className='flex h-[14px] items-center space-x-1 text-xs'>
                      {isAdvancedMode && (
                        <div className='system-xs-medium-uppercase ml-1 flex h-5 items-center rounded-md border border-components-button-secondary-border px-1.5 uppercase text-text-tertiary'>{t('appDebug.promptMode.advanced')}</div>
                      )}
                    </div>
                  </div>
                  <div className='flex items-center'>
                    {/* Agent Setting */}
                    {isAgent && (
                      <AgentSettingButton
                        isChatModel={modelConfig.mode === ModelModeType.chat}
                        agentConfig={modelConfig.agentConfig}

                        isFunctionCall={isFunctionCall}
                        onAgentSettingChange={(config) => {
                          const nextConfig = produce(modelConfig, (draft: ModelConfig) => {
                            draft.agentConfig = config
                          })
                          setModelConfig(nextConfig)
                        }}
                      />
                    )}
                    {/* Model and Parameters */}
                    {!debugWithMultipleModel && (
                      <>
                        <ModelParameterModal
                          isAdvancedMode={isAdvancedMode}
                          mode={mode}
                          provider={modelConfig.provider}
                          completionParams={completionParams}
                          modelId={modelConfig.model_id}
                          setModel={setModel as any}
                          onCompletionParamsChange={(newParams: FormValue) => {
                            setCompletionParams(newParams)
                          }}
                          debugWithMultipleModel={debugWithMultipleModel}
                          onDebugWithMultipleModelChange={handleDebugWithMultipleModelChange}
                        />
                        <Divider type='vertical' className='mx-2 h-[14px]' />
                      </>
                    )}
                    {isMobile && (
                      <Button className='mr-2 !h-8 !text-[13px] font-medium' onClick={showDebugPanel}>
                        <span className='mr-1'>{t('appDebug.operation.debugConfig')}</span>
                        <CodeBracketIcon className="h-4 w-4 text-text-tertiary" />
                      </Button>
                    )}
                    <AppPublisher {...{
                      publishDisabled: cannotPublish,
                      publishedAt: (latestPublishedAt || 0) * 1000,
                      debugWithMultipleModel,
                      multipleModelConfigs,
                      onPublish,
                      publishedConfig: publishedConfig!,
                      resetAppConfig: () => syncToPublishedConfig(publishedConfig!),
                    }} />
                  </div>
                </div>
              </div>
              <div className={`flex h-full w-full shrink-0 flex-col sm:w-1/2 ${debugWithMultipleModel && 'max-w-[560px]'}`}>
                <Config />
              </div>
              {!isMobile && <div className="relative flex h-full w-1/2 grow flex-col overflow-y-auto " style={{ borderColor: 'rgba(0, 0, 0, 0.02)' }}>
                <div className='flex grow flex-col rounded-tl-2xl border-l-[0.5px] border-t-[0.5px] border-components-panel-border bg-chatbot-bg '>
                  <Debug
                    isAPIKeySet={isAPIKeySet}
                    onSetting={() => setShowAccountSettingModal({ payload: 'provider' })}
                    inputs={inputs}
                    modelParameterParams={{
                      setModel: setModel as any,
                      onCompletionParamsChange: setCompletionParams,
                    }}
                    debugWithMultipleModel={debugWithMultipleModel}
                    multipleModelConfigs={multipleModelConfigs}
                    onMultipleModelConfigsChange={handleMultipleModelConfigsChange}
                  />
                </div>
              </div>}
            </div>
          </div>
          {showUseGPT4Confirm && (
            <Confirm
              title={t('appDebug.trailUseGPT4Info.title')}
              content={t('appDebug.trailUseGPT4Info.description')}
              isShow={showUseGPT4Confirm}
              onConfirm={() => {
                setShowAccountSettingModal({ payload: 'provider' })
                setShowUseGPT4Confirm(false)
              }}
              onCancel={() => setShowUseGPT4Confirm(false)}
            />
          )}

          {isShowSelectDataSet && (
            <SelectDataSet
              isShow={isShowSelectDataSet}
              onClose={hideSelectDataSet}
              selectedIds={selectedIds}
              onSelect={handleSelect}
            />
          )}

          {isShowHistoryModal && (
            <EditHistoryModal
              isShow={isShowHistoryModal}
              saveLoading={false}
              onClose={hideHistoryModal}
              data={completionPromptConfig.conversation_histories_role}
              onSave={(data) => {
                setConversationHistoriesRole(data)
                hideHistoryModal()
              }}
            />
          )}
          {isMobile && (
            <Drawer showClose isOpen={isShowDebugPanel} onClose={hideDebugPanel} mask footer={null}>
              <Debug
                isAPIKeySet={isAPIKeySet}
                onSetting={() => setShowAccountSettingModal({ payload: 'provider' })}
                inputs={inputs}
                modelParameterParams={{
                  setModel: setModel as any,
                  onCompletionParamsChange: setCompletionParams,
                }}
                debugWithMultipleModel={debugWithMultipleModel}
                multipleModelConfigs={multipleModelConfigs}
                onMultipleModelConfigsChange={handleMultipleModelConfigsChange}
              />
            </Drawer>
          )}
          {showAppConfigureFeaturesModal && (
            <NewFeaturePanel
              show
              inWorkflow={false}
              showFileUpload={false}
              isChatMode={mode !== 'completion'}
              disabled={false}
              onChange={handleFeaturesChange}
              onClose={() => setShowAppConfigureFeaturesModal(false)}
              promptVariables={modelConfig.configs.prompt_variables}
              onAutoAddPromptVariable={handleAddPromptVariable}
            />
          )}
          <PluginDependency />
        </MittProvider>
      </FeaturesProvider>
    </ConfigContext.Provider>
  )
}
export default React.memo(Configuration)
