import type { FC } from 'react'
import type { KnowledgeBaseNodeType } from './types'
import type { NodePanelProps, Var } from '@/app/components/workflow/types'
import { useQuery, useSuspenseQuery } from '@tanstack/react-query'
import { memo, useCallback, useMemo } from 'react'
import { useTranslation } from 'react-i18next'
import SummaryIndexSetting from '@/app/components/datasets/settings/summary-index-setting'
import { checkShowMultiModalTip } from '@/app/components/datasets/settings/utils'
import { ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
import { useModelList } from '@/app/components/header/account-setting/model-provider-page/hooks'
import { normalizeModelProviderModelsResponse } from '@/app/components/header/account-setting/model-provider-page/utils'
import {
  BoxGroup,
  BoxGroupField,
  Group,
} from '@/app/components/workflow/nodes/_base/components/layout'
import VarReferencePicker from '@/app/components/workflow/nodes/_base/components/variable/var-reference-picker'
import { systemFeaturesQueryOptions } from '@/features/system-features/client'
import { consoleQuery } from '@/service/client'
import { useNodesReadOnly } from '../../hooks/use-workflow'
import Split from '../_base/components/split'
import ChunkStructure from './components/chunk-structure'
import EmbeddingModel from './components/embedding-model'
import IndexMethod from './components/index-method'
import RetrievalSetting from './components/retrieval-setting'
import { useConfig } from './hooks/use-config'
import { useEmbeddingModelStatus } from './hooks/use-embedding-model-status'
import { ChunkStructureEnum, IndexMethodEnum } from './types'
import { getKnowledgeBaseValidationIssue, KnowledgeBaseValidationIssueCode } from './utils'

const Panel: FC<NodePanelProps<KnowledgeBaseNodeType>> = ({ id, data }) => {
  const { t } = useTranslation()
  const { data: deploymentEdition } = useSuspenseQuery({
    ...systemFeaturesQueryOptions(),
    select: ({ deployment_edition }) => deployment_edition,
  })
  const isNonCloudEdition = deploymentEdition === 'COMMUNITY' || deploymentEdition === 'ENTERPRISE'
  const { nodesReadOnly } = useNodesReadOnly()
  const { data: embeddingModelList } = useModelList(ModelTypeEnum.textEmbedding)
  const { data: rerankModelList } = useModelList(ModelTypeEnum.rerank)
  const chunkStructure = data.chunk_structure
  const indexChunkVariableSelector = data.index_chunk_variable_selector
  const indexingTechnique = data.indexing_technique
  const embeddingModel = data.embedding_model
  const retrievalModel = data.retrieval_model
  const retrievalSearchMethod = retrievalModel?.search_method
  const retrievalRerankingEnable = retrievalModel?.reranking_enable
  const embeddingModelProvider = data.embedding_model_provider
  const { data: embeddingProviderModelList } = useQuery(
    consoleQuery.workspaces.current.modelProviders.byProvider.models.get.queryOptions({
      input: { params: { provider: embeddingModelProvider || '' } },
      enabled: indexingTechnique === IndexMethodEnum.QUALIFIED && !!embeddingModelProvider,
      refetchOnWindowFocus: false,
      select: normalizeModelProviderModelsResponse,
    }),
  )

  const {
    handleChunkStructureChange,
    handleIndexMethodChange,
    handleKeywordNumberChange,
    handleEmbeddingModelChange,
    handleRetrievalSearchMethodChange,
    handleHybridSearchModeChange,
    handleRerankingModelEnabledChange,
    handleWeighedScoreChange,
    handleRerankingModelChange,
    handleTopKChange,
    handleScoreThresholdChange,
    handleScoreThresholdEnabledChange,
    handleInputVariableChange,
    handleSummaryIndexSettingChange,
  } = useConfig(id)

  const filterVar = useCallback(
    (variable: Var) => {
      if (!data.chunk_structure) return false
      switch (data.chunk_structure) {
        case ChunkStructureEnum.general:
          return (
            variable.schemaType === 'general_structure' ||
            variable.schemaType === 'multimodal_general_structure'
          )
        case ChunkStructureEnum.parent_child:
          return (
            variable.schemaType === 'parent_child_structure' ||
            variable.schemaType === 'multimodal_parent_child_structure'
          )
        case ChunkStructureEnum.question_answer:
          return variable.schemaType === 'qa_structure'
        default:
          return false
      }
    },
    [data.chunk_structure],
  )

  const chunkTypePlaceHolder = useMemo(() => {
    if (!data.chunk_structure) return ''
    let placeholder = ''
    switch (data.chunk_structure) {
      case ChunkStructureEnum.general:
        placeholder = '(multimodal_)general_structure'
        break
      case ChunkStructureEnum.parent_child:
        placeholder = '(multimodal_)parent_child_structure'
        break
      case ChunkStructureEnum.question_answer:
        placeholder = 'qa_structure'
        break
      default:
        return ''
    }
    return placeholder.charAt(0).toUpperCase() + placeholder.slice(1)
  }, [data.chunk_structure])

  const showMultiModalTip = useMemo(() => {
    return checkShowMultiModalTip({
      embeddingModel: {
        provider: data.embedding_model_provider ?? '',
        model: data.embedding_model ?? '',
      },
      rerankingEnable: !!data.retrieval_model?.reranking_enable,
      rerankModel: {
        rerankingProviderName: data.retrieval_model?.reranking_model?.reranking_provider_name ?? '',
        rerankingModelName: data.retrieval_model?.reranking_model?.reranking_model_name ?? '',
      },
      indexMethod: data.indexing_technique,
      embeddingModelList,
      rerankModelList,
    })
  }, [
    data.embedding_model_provider,
    data.embedding_model,
    data.retrieval_model?.reranking_enable,
    data.retrieval_model?.reranking_model,
    data.indexing_technique,
    embeddingModelList,
    rerankModelList,
  ])

  const validationPayload = useMemo(() => {
    return {
      chunk_structure: chunkStructure,
      index_chunk_variable_selector: indexChunkVariableSelector,
      indexing_technique: indexingTechnique,
      embedding_model: embeddingModel,
      embedding_model_provider: embeddingModelProvider,
      retrieval_model: {
        search_method: retrievalSearchMethod,
        reranking_enable: retrievalRerankingEnable,
        reranking_model: retrievalModel?.reranking_model,
      },
      _embeddingModelList: embeddingModelList,
      _embeddingProviderModelList: embeddingProviderModelList,
      _rerankModelList: rerankModelList,
    }
  }, [
    chunkStructure,
    indexChunkVariableSelector,
    indexingTechnique,
    embeddingModel,
    embeddingModelProvider,
    retrievalSearchMethod,
    retrievalRerankingEnable,
    retrievalModel?.reranking_model,
    embeddingModelList,
    embeddingProviderModelList,
    rerankModelList,
  ])

  const validationIssue = useMemo(() => {
    return getKnowledgeBaseValidationIssue(validationPayload)
  }, [validationPayload])
  const { status: embeddingModelStatus } = useEmbeddingModelStatus({
    embeddingModel,
    embeddingModelProvider,
    embeddingModelList,
  })

  const chunkStructureWarning =
    validationIssue?.code === KnowledgeBaseValidationIssueCode.chunkStructureRequired
  const chunksInputWarning =
    validationIssue?.code === KnowledgeBaseValidationIssueCode.chunksVariableRequired
  const embeddingModelWarning =
    indexingTechnique === IndexMethodEnum.QUALIFIED && embeddingModelStatus !== 'active'

  return (
    <div>
      <Group className="py-3" withBorderBottom={!!data.chunk_structure}>
        <ChunkStructure
          chunkStructure={data.chunk_structure}
          onChunkStructureChange={handleChunkStructureChange}
          warningDot={chunkStructureWarning}
          readonly={nodesReadOnly}
        />
      </Group>
      {!!data.chunk_structure && (
        <>
          <BoxGroupField
            boxGroupProps={{
              boxProps: { withBorderBottom: true },
            }}
            fieldProps={{
              fieldTitleProps: {
                title: t(($) => $['nodes.knowledgeBase.chunksInput'], { ns: 'workflow' }),
                tooltip: t(($) => $['nodes.knowledgeBase.chunksInputTip'], { ns: 'workflow' }),
                warningDot: chunksInputWarning,
              },
            }}
          >
            <VarReferencePicker
              nodeId={id}
              isShowNodeName
              value={data.index_chunk_variable_selector}
              onChange={handleInputVariableChange}
              readonly={nodesReadOnly}
              filterVar={filterVar}
              isFilterFileVar
              isSupportFileVar={false}
              preferSchemaType
              typePlaceHolder={chunkTypePlaceHolder}
            />
          </BoxGroupField>
          <BoxGroup>
            <div className="space-y-3">
              <IndexMethod
                chunkStructure={data.chunk_structure}
                indexMethod={data.indexing_technique}
                onIndexMethodChange={handleIndexMethodChange}
                keywordNumber={data.keyword_number}
                onKeywordNumberChange={handleKeywordNumberChange}
                readonly={nodesReadOnly}
              />
              {data.indexing_technique === IndexMethodEnum.QUALIFIED && (
                <EmbeddingModel
                  embeddingModel={data.embedding_model}
                  embeddingModelProvider={data.embedding_model_provider}
                  onEmbeddingModelChange={handleEmbeddingModelChange}
                  warningDot={embeddingModelWarning}
                  readonly={nodesReadOnly}
                />
              )}
              <div className="pt-1">
                <Split className="h-px" />
              </div>
              {data.indexing_technique === IndexMethodEnum.QUALIFIED &&
                [ChunkStructureEnum.general, ChunkStructureEnum.parent_child].includes(
                  data.chunk_structure,
                ) &&
                isNonCloudEdition && (
                  <>
                    <SummaryIndexSetting
                      summaryIndexSetting={data.summary_index_setting}
                      onSummaryIndexSettingChange={handleSummaryIndexSettingChange}
                      readonly={nodesReadOnly}
                    />
                    <div className="pt-1">
                      <Split className="h-px" />
                    </div>
                  </>
                )}
              <RetrievalSetting
                indexMethod={data.indexing_technique}
                searchMethod={data.retrieval_model.search_method}
                onRetrievalSearchMethodChange={handleRetrievalSearchMethodChange}
                hybridSearchMode={data.retrieval_model.reranking_mode}
                onHybridSearchModeChange={handleHybridSearchModeChange}
                weightedScore={data.retrieval_model.weights}
                onWeightedScoreChange={handleWeighedScoreChange}
                rerankingModelEnabled={data.retrieval_model.reranking_enable}
                onRerankingModelEnabledChange={handleRerankingModelEnabledChange}
                rerankingModel={data.retrieval_model.reranking_model}
                onRerankingModelChange={handleRerankingModelChange}
                topK={data.retrieval_model.top_k}
                onTopKChange={handleTopKChange}
                scoreThreshold={data.retrieval_model.score_threshold}
                onScoreThresholdChange={handleScoreThresholdChange}
                isScoreThresholdEnabled={data.retrieval_model.score_threshold_enabled}
                onScoreThresholdEnabledChange={handleScoreThresholdEnabledChange}
                showMultiModalTip={showMultiModalTip}
                readonly={nodesReadOnly}
              />
            </div>
          </BoxGroup>
        </>
      )}
    </div>
  )
}

export default memo(Panel)
