'use client'
import type { FC } from 'react'
import type { InputVar } from '../../../../types'
import type { FileEntity } from '@/app/components/base/file-uploader/types'
import { cn } from '@langgenius/dify-ui/cn'
import {
  Select,
  SelectContent,
  SelectItem,
  SelectItemIndicator,
  SelectItemText,
  SelectTrigger,
} from '@langgenius/dify-ui/select'
import { Textarea } from '@langgenius/dify-ui/textarea'
import { RiDeleteBinLine } from '@remixicon/react'
import { produce } from 'immer'
import * as React from 'react'
import { useCallback, useMemo } from 'react'
import { useTranslation } from 'react-i18next'
import { FileUploaderInAttachmentWrapper } from '@/app/components/base/file-uploader'
import { Line3 } from '@/app/components/base/icons/src/public/common'
import { BubbleX } from '@/app/components/base/icons/src/vender/line/others'
import { Variable02 } from '@/app/components/base/icons/src/vender/solid/development'
import TextGenerationImageUploader from '@/app/components/base/image-uploader/text-generation-image-uploader'
import Input from '@/app/components/base/input'
import { FILE_EXTS } from '@/app/components/base/prompt-editor/constants'
import { VarBlockIcon } from '@/app/components/workflow/block-icon'
import { useHooksStore } from '@/app/components/workflow/hooks-store'
import { Resolution, TransferMethod } from '@/types/app'
import { BlockEnum, InputVarType, SupportUploadFileTypes } from '../../../../types'
import { CodeLanguage } from '../../../code/types'
import CodeEditor from '../editor/code-editor'
import TextEditor from '../editor/text-editor'
import BoolInput from './bool-input'

type Props = Readonly<{
  payload: InputVar
  value: any
  onChange: (value: any) => void
  className?: string
  autoFocus?: boolean
  inStepRun?: boolean
}>

const FormItem: FC<Props> = ({
  payload,
  value,
  onChange,
  className,
  autoFocus,
  inStepRun = false,
}) => {
  const { t } = useTranslation()
  const { type } = payload
  const fileSettings = useHooksStore((s) => s.configsMap?.fileSettings)
  const jsonSchemaPlaceholder = React.useMemo(() => {
    const schema = (payload as any)?.json_schema
    if (!schema) return ''
    return typeof schema === 'string' ? schema : JSON.stringify(schema, null, 2)
  }, [payload])

  const handleArrayItemChange = useCallback(
    (index: number) => {
      return (newValue: any) => {
        const newValues = produce(value, (draft: any) => {
          draft[index] = newValue
        })
        onChange(newValues)
      }
    },
    [value, onChange],
  )

  const handleArrayItemRemove = useCallback(
    (index: number) => {
      return () => {
        const newValues = produce(value, (draft: any) => {
          draft.splice(index, 1)
        })
        onChange(newValues)
      }
    },
    [value, onChange],
  )
  const nodeKey = (() => {
    if (typeof payload.label === 'object') {
      const { nodeType, nodeName, variable, isChatVar } = payload.label
      return (
        <div className="flex h-full items-center">
          {!isChatVar && (
            <div className="flex items-center">
              <div className="p-px">
                <VarBlockIcon type={nodeType || BlockEnum.Start} />
              </div>
              <div
                className="mx-0.5 max-w-[150px] truncate text-xs font-medium text-text-secondary"
                title={nodeName}
              >
                {nodeName}
              </div>
              <Line3 className="mr-0.5"></Line3>
            </div>
          )}
          <div className="flex items-center text-primary-600">
            {!isChatVar && <Variable02 className="size-3.5" />}
            {isChatVar && <BubbleX className="size-3.5 text-util-colors-teal-teal-700" />}
            <div
              className={cn(
                'ml-0.5 max-w-[150px] truncate text-xs font-medium',
                isChatVar && 'text-text-secondary',
              )}
              title={variable}
            >
              {variable}
            </div>
          </div>
        </div>
      )
    }
    return ''
  })()

  const isBooleanType = type === InputVarType.checkbox
  const isArrayLikeType = [InputVarType.contexts, InputVarType.iterator].includes(type)
  const isContext = type === InputVarType.contexts
  const isIterator = type === InputVarType.iterator
  const isIteratorItemFile = isIterator && payload.isFileItem
  const singleFileValue = useMemo(() => {
    if (payload.variable === '#files#') return value || []

    return value ? [value] : []
  }, [payload.variable, value])
  const handleSingleFileChange = useCallback(
    (files: FileEntity[]) => {
      if (payload.variable === '#files#') onChange(files)
      else if (files.length) onChange(files[0])
      else onChange(null)
    },
    [onChange, payload.variable],
  )

  return (
    <div className={cn(className)}>
      {!isArrayLikeType && !isBooleanType && (
        <div className="mb-1 flex h-6 items-center gap-1 system-sm-semibold text-text-secondary">
          <div className="truncate">
            {typeof payload.label === 'object' ? nodeKey : payload.label}
          </div>
          {payload.hide === true ? (
            <span className="system-xs-regular text-text-tertiary">
              {t(($) => $['panel.optional_and_hidden'], { ns: 'workflow' })}
            </span>
          ) : (
            !payload.required && (
              <span className="system-xs-regular text-text-tertiary">
                {t(($) => $['panel.optional'], { ns: 'workflow' })}
              </span>
            )
          )}
        </div>
      )}
      <div className="grow">
        {type === InputVarType.textInput && (
          <Input
            value={value || ''}
            onChange={(e) => onChange(e.target.value)}
            placeholder={typeof payload.label === 'object' ? payload.label.variable : payload.label}
            autoFocus={autoFocus}
          />
        )}

        {type === InputVarType.number && (
          <Input
            type="number"
            value={value || ''}
            onChange={(e) => onChange(e.target.value)}
            placeholder={typeof payload.label === 'object' ? payload.label.variable : payload.label}
            autoFocus={autoFocus}
          />
        )}

        {type === InputVarType.paragraph && (
          <Textarea
            aria-label={typeof payload.label === 'object' ? payload.label.variable : payload.label}
            value={value || ''}
            onValueChange={(value) => onChange(value)}
            placeholder={typeof payload.label === 'object' ? payload.label.variable : payload.label}
            autoFocus={autoFocus}
          />
        )}

        {type === InputVarType.select && (
          <Select
            value={value || payload.default || null}
            onValueChange={(nextValue) => {
              if (!nextValue) return
              onChange(nextValue)
            }}
          >
            <SelectTrigger className="w-full">
              {String(
                value || payload.default || t(($) => $['placeholder.select'], { ns: 'common' }),
              )}
            </SelectTrigger>
            <SelectContent>
              {(payload.options || []).map((option) => (
                <SelectItem key={option} value={option}>
                  <SelectItemText>{option}</SelectItemText>
                  <SelectItemIndicator />
                </SelectItem>
              ))}
            </SelectContent>
          </Select>
        )}

        {isBooleanType && (
          <BoolInput
            name={payload.label as string}
            value={!!value}
            required={payload.required}
            onChange={onChange}
          />
        )}

        {type === InputVarType.json && (
          <CodeEditor
            value={value}
            title={<span>JSON</span>}
            language={CodeLanguage.json}
            onChange={onChange}
          />
        )}
        {type === InputVarType.jsonObject && (
          <CodeEditor
            value={value}
            language={CodeLanguage.json}
            onChange={onChange}
            noWrapper
            className="bg h-[80px] overflow-y-auto rounded-[10px] bg-components-input-bg-normal p-1"
            placeholder={<div className="whitespace-pre">{jsonSchemaPlaceholder}</div>}
          />
        )}
        {type === InputVarType.singleFile && (
          <FileUploaderInAttachmentWrapper
            value={singleFileValue}
            onChange={handleSingleFileChange}
            fileConfig={{
              allowed_file_types:
                inStepRun &&
                (!payload.allowed_file_types || payload.allowed_file_types.length === 0)
                  ? [
                      SupportUploadFileTypes.image,
                      SupportUploadFileTypes.document,
                      SupportUploadFileTypes.audio,
                      SupportUploadFileTypes.video,
                    ]
                  : payload.allowed_file_types,
              allowed_file_extensions:
                inStepRun &&
                (!payload.allowed_file_extensions || payload.allowed_file_extensions.length === 0)
                  ? [
                      ...(FILE_EXTS[SupportUploadFileTypes.image] ?? []),
                      ...(FILE_EXTS[SupportUploadFileTypes.document] ?? []),
                      ...(FILE_EXTS[SupportUploadFileTypes.audio] ?? []),
                      ...(FILE_EXTS[SupportUploadFileTypes.video] ?? []),
                    ]
                  : payload.allowed_file_extensions,
              allowed_file_upload_methods: inStepRun
                ? [TransferMethod.local_file, TransferMethod.remote_url]
                : payload.allowed_file_upload_methods,
              number_limits: 1,
              fileUploadConfig: fileSettings?.fileUploadConfig,
            }}
          />
        )}
        {(type === InputVarType.multiFiles || isIteratorItemFile) && (
          <FileUploaderInAttachmentWrapper
            value={value}
            onChange={(files) => onChange(files)}
            fileConfig={{
              allowed_file_types:
                (inStepRun || isIteratorItemFile) &&
                (!payload.allowed_file_types || payload.allowed_file_types.length === 0)
                  ? [
                      SupportUploadFileTypes.image,
                      SupportUploadFileTypes.document,
                      SupportUploadFileTypes.audio,
                      SupportUploadFileTypes.video,
                    ]
                  : payload.allowed_file_types,
              allowed_file_extensions:
                (inStepRun || isIteratorItemFile) &&
                (!payload.allowed_file_extensions || payload.allowed_file_extensions.length === 0)
                  ? [
                      ...(FILE_EXTS[SupportUploadFileTypes.image] ?? []),
                      ...(FILE_EXTS[SupportUploadFileTypes.document] ?? []),
                      ...(FILE_EXTS[SupportUploadFileTypes.audio] ?? []),
                      ...(FILE_EXTS[SupportUploadFileTypes.video] ?? []),
                    ]
                  : payload.allowed_file_extensions,
              allowed_file_upload_methods:
                inStepRun || isIteratorItemFile
                  ? [TransferMethod.local_file, TransferMethod.remote_url]
                  : payload.allowed_file_upload_methods,
              number_limits: inStepRun || isIteratorItemFile ? 5 : payload.max_length,
              fileUploadConfig: fileSettings?.fileUploadConfig,
            }}
          />
        )}
        {type === InputVarType.files && (
          <TextGenerationImageUploader
            settings={
              {
                ...fileSettings,
                detail: fileSettings?.image?.detail || Resolution.high,
                transfer_methods: fileSettings?.allowed_file_upload_methods || [],
              } as any
            }
            onFilesChange={(files) =>
              onChange(
                files
                  .filter((file) => file.progress !== -1)
                  .map((fileItem) => ({
                    type: 'image',
                    transfer_method: fileItem.type,
                    url: fileItem.url,
                    upload_file_id: fileItem.fileId,
                  })),
              )
            }
          />
        )}

        {isContext && (
          <div className="space-y-2">
            {(value || []).map((item: any, index: number) => (
              <CodeEditor
                key={index}
                value={item}
                title={<span>JSON</span>}
                headerRight={
                  (value as any).length > 1 ? (
                    <RiDeleteBinLine
                      onClick={handleArrayItemRemove(index)}
                      className="mr-1 size-3.5 cursor-pointer text-text-tertiary"
                    />
                  ) : undefined
                }
                language={CodeLanguage.json}
                onChange={handleArrayItemChange(index)}
              />
            ))}
          </div>
        )}

        {isIterator && !isIteratorItemFile && (
          <div className="space-y-2">
            {(value || []).map((item: any, index: number) => (
              <TextEditor
                key={index}
                isInNode
                value={item}
                title={
                  <span>
                    {t(($) => $['variableConfig.content'], { ns: 'appDebug' })} {index + 1}{' '}
                  </span>
                }
                onChange={handleArrayItemChange(index)}
                headerRight={
                  (value as any).length > 1 ? (
                    <RiDeleteBinLine
                      onClick={handleArrayItemRemove(index)}
                      className="mr-1 size-3.5 cursor-pointer text-text-tertiary"
                    />
                  ) : undefined
                }
              />
            ))}
          </div>
        )}
      </div>
    </div>
  )
}
export default React.memo(FormItem)
