import type { SortableItem } from './types'
import type { MoreInfo, ValueSelector } from '@/app/components/workflow/types'
import type { InputVar } from '@/models/pipeline'
import { toast } from '@langgenius/dify-ui/toast'
import { useBoolean } from 'ahooks'
import { produce } from 'immer'
import { useCallback, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { useInputFieldPanel } from '@/app/components/rag-pipeline/hooks'
import { ChangeType } from '@/app/components/workflow/types'
import { usePipeline } from '../../../../hooks/use-pipeline'

const VARIABLE_PREFIX = 'rag'
type useFieldListProps = {
  initialInputFields: InputVar[]
  onInputFieldsChange: (value: InputVar[]) => void
  nodeId: string
  allVariableNames: string[]
}
export const useFieldList = ({ initialInputFields, onInputFieldsChange, nodeId, allVariableNames }: useFieldListProps) => {
  const { t } = useTranslation()
  const { toggleInputFieldEditPanel } = useInputFieldPanel()
  const [inputFields, setInputFields] = useState<InputVar[]>(initialInputFields)
  const inputFieldsRef = useRef<InputVar[]>(inputFields)
  const [removedVar, setRemovedVar] = useState<ValueSelector>([])
  const [removedIndex, setRemoveIndex] = useState(0)
  const { handleInputVarRename, isVarUsedInNodes, removeUsedVarInNodes } = usePipeline()
  const [isShowRemoveVarConfirm, { setTrue: showRemoveVarConfirm, setFalse: hideRemoveVarConfirm }] = useBoolean(false)
  const handleInputFieldsChange = useCallback((newInputFields: InputVar[]) => {
    setInputFields(newInputFields)
    inputFieldsRef.current = newInputFields
    onInputFieldsChange(newInputFields)
  }, [onInputFieldsChange])
  const handleListSortChange = useCallback((list: SortableItem[]) => {
    const newInputFields = list.map((item) => {
      const { id: _id, chosen: _chosen, selected: _selected, ...filed } = item
      return filed
    })
    handleInputFieldsChange(newInputFields)
  }, [handleInputFieldsChange])
  const editingFieldIndex = useRef<number>(-1)
  const handleCloseInputFieldEditor = useCallback(() => {
    toggleInputFieldEditPanel?.(null)
    editingFieldIndex.current = -1
  }, [toggleInputFieldEditPanel])
  const handleRemoveField = useCallback((index: number) => {
    const itemToRemove = inputFieldsRef.current[index]
    // Check if the variable is used in other nodes
    if (isVarUsedInNodes([VARIABLE_PREFIX, nodeId, itemToRemove!.variable || ''])) {
      showRemoveVarConfirm()
      setRemovedVar([VARIABLE_PREFIX, nodeId, itemToRemove!.variable || ''])
      setRemoveIndex(index as number)
      return
    }
    const newInputFields = inputFieldsRef.current.filter((_, i) => i !== index)
    handleInputFieldsChange(newInputFields)
  }, [handleInputFieldsChange, isVarUsedInNodes, nodeId, showRemoveVarConfirm])
  const onRemoveVarConfirm = useCallback(() => {
    const newInputFields = inputFieldsRef.current.filter((_, i) => i !== removedIndex)
    handleInputFieldsChange(newInputFields)
    removeUsedVarInNodes(removedVar)
    hideRemoveVarConfirm()
  }, [removedIndex, handleInputFieldsChange, removeUsedVarInNodes, removedVar, hideRemoveVarConfirm])
  const handleSubmitField = useCallback((data: InputVar, moreInfo?: MoreInfo) => {
    const isDuplicate = allVariableNames.some(name => name === data.variable && name !== inputFieldsRef.current[editingFieldIndex.current]?.variable)
    if (isDuplicate) {
      toast.error(t('inputFieldPanel.error.variableDuplicate', { ns: 'datasetPipeline' }))
      return
    }
    const newInputFields = produce(inputFieldsRef.current, (draft) => {
      const currentIndex = editingFieldIndex.current
      if (currentIndex === -1) {
        draft.push(data)
        return
      }
      draft[currentIndex] = data
    })
    handleInputFieldsChange(newInputFields)
    // Update variable name in nodes if it has changed
    if (moreInfo?.type === ChangeType.changeVarName)
      handleInputVarRename(nodeId, [VARIABLE_PREFIX, nodeId, moreInfo.payload?.beforeKey || ''], [VARIABLE_PREFIX, nodeId, moreInfo.payload?.afterKey || ''])
    handleCloseInputFieldEditor()
  }, [allVariableNames, handleCloseInputFieldEditor, handleInputFieldsChange, handleInputVarRename, nodeId, t])
  const handleOpenInputFieldEditor = useCallback((id?: string) => {
    const index = inputFieldsRef.current.findIndex(field => field.variable === id)
    editingFieldIndex.current = index
    toggleInputFieldEditPanel?.({
      onClose: handleCloseInputFieldEditor,
      onSubmit: handleSubmitField,
      initialData: inputFieldsRef.current[index],
    })
  }, [])
  return {
    inputFields,
    handleListSortChange,
    handleRemoveField,
    handleOpenInputFieldEditor,
    isShowRemoveVarConfirm,
    hideRemoveVarConfirm,
    onRemoveVarConfirm,
  }
}
