'use client'
import type { ChangeEvent, FC } from 'react'
import type { Item as SelectItem } from './type-select'
import type { InputVar, InputVarType, MoreInfo } from '@/app/components/workflow/types'
import { Dialog, DialogContent, DialogTitle } from '@langgenius/dify-ui/dialog'
import { toast } from '@langgenius/dify-ui/toast'
import * as React from 'react'
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { useContext } from 'use-context-selector'
import { useStore as useAppStore } from '@/app/components/app/store'
import ConfigContext from '@/context/debug-configuration'
import { AppModeEnum } from '@/types/app'
import {
  checkKeys,
  getNewVarInWorkflow,
  replaceSpaceWithUnderscoreInVarNameInput,
} from '@/utils/var'
import ModalFoot from '../modal-foot'
import ConfigModalFormFields from './form-fields'
import {
  buildSelectOptions,
  createPayloadForType,
  getCheckboxDefaultSelectValue,
  getJsonSchemaEditorValue,
  isStringInputType,
  normalizeSelectDefaultValue,
  updatePayloadField,
  validateConfigModalPayload,
} from './utils'

type IConfigModalProps = {
  isCreate?: boolean
  payload?: InputVar
  isShow: boolean
  varKeys?: string[]
  onClose: () => void
  onConfirm: (newValue: InputVar, moreInfo?: MoreInfo) => void
  supportFile?: boolean
  showHiddenField?: boolean
}

const ConfigModal: FC<IConfigModalProps> = ({
  isCreate,
  payload,
  isShow,
  onClose,
  onConfirm,
  showHiddenField,
  supportFile,
}) => {
  const { modelConfig } = useContext(ConfigContext)
  const { t } = useTranslation()
  const [tempPayload, setTempPayload] = useState<InputVar>(() =>
    normalizeSelectDefaultValue(payload || (getNewVarInWorkflow('') as any)),
  )
  const { type, options, max_length } = tempPayload
  const modalRef = useRef<HTMLDivElement>(null)
  const appDetail = useAppStore((state) => state.appDetail)
  const isBasicApp =
    appDetail?.mode !== AppModeEnum.ADVANCED_CHAT && appDetail?.mode !== AppModeEnum.WORKFLOW
  const jsonSchemaStr = useMemo(
    () => getJsonSchemaEditorValue(type, tempPayload.json_schema),
    [tempPayload.json_schema, type],
  )
  useEffect(() => {
    // To fix the first input element auto focus, then directly close modal will raise error
    if (isShow) modalRef.current?.focus()
  }, [isShow])

  const isStringInput = isStringInputType(type)
  const checkVariableName = useCallback(
    (value: string, canBeEmpty?: boolean) => {
      const { isValid, errorMessageKey } = checkKeys([value], canBeEmpty)
      if (!isValid) {
        toast.error(
          t(($) => $[`varKeyError.${errorMessageKey}`], {
            ns: 'appDebug',
            key: t(($) => $['variableConfig.varName'], { ns: 'appDebug' }),
          }),
        )
        return false
      }
      return true
    },
    [t],
  )
  const handlePayloadChange = useCallback((key: string) => {
    return (value: any) => {
      setTempPayload((prev) => updatePayloadField(prev, key, value))
    }
  }, [])

  const handleJSONSchemaChange = useCallback(
    (value: string) => {
      const isEmpty = value == null || value.trim() === ''
      if (isEmpty) {
        handlePayloadChange('json_schema')(undefined)
        return null
      }
      try {
        const v = JSON.parse(value)
        handlePayloadChange('json_schema')(JSON.stringify(v, null, 2))
      } catch {
        return null
      }
    },
    [handlePayloadChange],
  )

  const selectOptions: SelectItem[] = useMemo(
    () =>
      buildSelectOptions({
        isBasicApp,
        supportFile,
        t,
      }),
    [isBasicApp, supportFile, t],
  )

  const handleTypeChange = useCallback((item: SelectItem) => {
    setTempPayload((prev) => createPayloadForType(prev, item.value as InputVarType))
  }, [])

  const handleVarKeyBlur = useCallback(
    (e: any) => {
      const varName = e.target.value
      if (!checkVariableName(varName, true) || tempPayload.label) return

      setTempPayload((prev) => {
        return {
          ...prev,
          label: varName,
        }
      })
    },
    [checkVariableName, tempPayload.label],
  )

  const handleVarNameChange = useCallback(
    (e: ChangeEvent<any>) => {
      replaceSpaceWithUnderscoreInVarNameInput(e.target)
      const value = e.target.value
      const { isValid, errorKey, errorMessageKey } = checkKeys([value], true)
      if (!isValid) {
        toast.error(
          t(($) => $[`varKeyError.${errorMessageKey}`], { ns: 'appDebug', key: errorKey }),
        )
        return
      }
      handlePayloadChange('variable')(e.target.value)
    },
    [handlePayloadChange, t],
  )

  const checkboxDefaultSelectValue = useMemo(
    () => getCheckboxDefaultSelectValue(tempPayload.default),
    [tempPayload.default],
  )

  const handleConfirm = () => {
    const { errorMessage, moreInfo, payloadToSave } = validateConfigModalPayload({
      tempPayload,
      payload,
      checkVariableName,
      t,
    })

    if (errorMessage) {
      toast.error(errorMessage)
      return
    }

    if (payloadToSave) onConfirm(payloadToSave, moreInfo)
  }

  return (
    <Dialog
      open={isShow}
      onOpenChange={(open) => {
        if (!open) onClose()
      }}
    >
      <DialogContent className="flex max-h-[calc(100dvh-2rem)] flex-col overflow-hidden! border-none p-0! text-left align-middle">
        <DialogTitle className="shrink-0 px-6 pt-6 title-2xl-semi-bold text-text-primary">
          {t(($) => $[`variableConfig.${isCreate ? 'addModalTitle' : 'editModalTitle'}`], {
            ns: 'appDebug',
          })}
        </DialogTitle>

        <div
          ref={modalRef}
          tabIndex={-1}
          data-testid="config-modal-scroll-area"
          className="min-h-0 min-w-0 flex-1 overflow-x-hidden overflow-y-auto px-6 py-4 pb-8"
        >
          <ConfigModalFormFields
            checkboxDefaultSelectValue={checkboxDefaultSelectValue}
            isStringInput={isStringInput}
            jsonSchemaStr={jsonSchemaStr}
            maxLength={max_length}
            modelId={modelConfig.model_id}
            onFilePayloadChange={(payload) => setTempPayload(payload as InputVar)}
            onJSONSchemaChange={handleJSONSchemaChange}
            onPayloadChange={handlePayloadChange}
            onTypeChange={handleTypeChange}
            onVarKeyBlur={handleVarKeyBlur}
            onVarNameChange={handleVarNameChange}
            options={options}
            selectOptions={selectOptions}
            showHiddenField={showHiddenField}
            tempPayload={tempPayload}
            t={t}
          />
        </div>
        <div className="shrink-0 px-6 pt-2 pb-6">
          <ModalFoot onConfirm={handleConfirm} onCancel={onClose} />
        </div>
      </DialogContent>
    </Dialog>
  )
}
export default React.memo(ConfigModal)
