import type { AnyFieldApi } from '@tanstack/react-form'
import type { FieldState, FormSchema, TypeWithI18N } from '@/app/components/base/form/types'
import { cn } from '@langgenius/dify-ui/cn'
import { FieldItem, FieldLabel, FieldRoot } from '@langgenius/dify-ui/field'
import { FieldsetLegend, FieldsetRoot } from '@langgenius/dify-ui/fieldset'
import { Radio } from '@langgenius/dify-ui/radio'
import { RadioGroup } from '@langgenius/dify-ui/radio-group'
import {
  Select,
  SelectContent,
  SelectItem,
  SelectItemIndicator,
  SelectItemText,
  SelectTrigger,
  SelectValue,
} from '@langgenius/dify-ui/select'
import { useStore } from '@tanstack/react-form'
import {
  isValidElement,
  memo,
  useCallback,
  useMemo,
} from 'react'
import { useTranslation } from 'react-i18next'
import { CheckboxList } from '@/app/components/base/checkbox-list'
import { FormItemValidateStatusEnum, FormTypeEnum } from '@/app/components/base/form/types'
import { Infotip } from '@/app/components/base/infotip'
import Input from '@/app/components/base/input'
import { useRenderI18nObject } from '@/hooks/use-i18n'
import { useTriggerPluginDynamicOptions } from '@/service/use-triggers'

const getExtraProps = (type: FormTypeEnum) => {
  switch (type) {
    case FormTypeEnum.secretInput:
      return { type: 'password', autoComplete: 'new-password' }
    case FormTypeEnum.textNumber:
      return { type: 'number' }
    default:
      return { type: 'text' }
  }
}

const getTranslatedContent = ({ content, render }: {
  content: React.ReactNode | string | null | undefined | TypeWithI18N<string> | Record<string, string>
  render: (content: TypeWithI18N<string> | Record<string, string>) => string
}): string => {
  if (isValidElement(content) || typeof content === 'string')
    return content as string

  if (typeof content === 'object' && content !== null)
    return render(content as TypeWithI18N<string>)

  return ''
}

type SelectOption = {
  label: string
  value: string
}

const getSingleSelectValue = (value: unknown, options: SelectOption[]) => {
  return options.find(option => option.value === value)?.value ?? null
}

const getSingleSelectLabel = (value: unknown, options: SelectOption[], placeholder: string | undefined) => {
  return options.find(option => option.value === value)?.label ?? placeholder
}

const VALIDATE_STATUS_STYLE_MAP: Record<FormItemValidateStatusEnum, { componentClassName: string, textClassName: string, infoFieldName: string }> = {
  [FormItemValidateStatusEnum.Error]: {
    componentClassName: 'border-components-input-border-destructive focus:border-components-input-border-destructive',
    textClassName: 'text-text-destructive',
    infoFieldName: 'errors',
  },
  [FormItemValidateStatusEnum.Warning]: {
    componentClassName: 'border-components-input-border-warning focus:border-components-input-border-warning',
    textClassName: 'text-text-warning',
    infoFieldName: 'warnings',
  },
  [FormItemValidateStatusEnum.Success]: {
    componentClassName: '',
    textClassName: '',
    infoFieldName: '',
  },
  [FormItemValidateStatusEnum.Validating]: {
    componentClassName: '',
    textClassName: '',
    infoFieldName: '',
  },
}

export type BaseFieldProps = {
  fieldClassName?: string
  labelClassName?: string
  inputContainerClassName?: string
  inputClassName?: string
  formSchema: FormSchema
  field: AnyFieldApi
  disabled?: boolean
  onChange?: (field: string, value: unknown) => void
  fieldState?: FieldState
}

const BaseField = ({
  fieldClassName,
  labelClassName,
  inputContainerClassName,
  inputClassName,
  formSchema,
  field,
  disabled: propsDisabled,
  onChange,
  fieldState,
}: BaseFieldProps) => {
  const renderI18nObject = useRenderI18nObject()
  const { t } = useTranslation()
  const {
    name,
    label,
    required,
    placeholder,
    options,
    labelClassName: formLabelClassName,
    disabled: formSchemaDisabled,
    type: formItemType,
    dynamicSelectParams,
    multiple = false,
    tooltip,
    showCopy,
    description,
    url,
    help,
  } = formSchema
  const disabled = propsDisabled || formSchemaDisabled

  const [translatedLabel, translatedPlaceholder, translatedTooltip, translatedDescription, translatedHelp] = useMemo(() => {
    const results = [
      label,
      placeholder,
      tooltip,
      description,
      help,
    ].map(v => getTranslatedContent({ content: v, render: renderI18nObject }))
    if (!results[1])
      results[1] = t('placeholder.input', { ns: 'common' })
    return results
  }, [label, placeholder, tooltip, description, help, renderI18nObject, t])

  const watchedVariables = useMemo(() => {
    const variables = new Set<string>()

    for (const option of options || []) {
      for (const condition of option.show_on || [])
        variables.add(condition.variable)
    }

    return Array.from(variables)
  }, [options])

  const watchedValues = useStore(field.form.store, (s) => {
    const result: Record<string, unknown> = {}
    for (const variable of watchedVariables)
      result[variable] = s.values[variable]

    return result
  })

  const memorizedOptions = useMemo(() => {
    return options?.filter((option) => {
      if (!option.show_on?.length)
        return true

      return option.show_on.every((condition) => {
        return watchedValues[condition.variable] === condition.value
      })
    }).map((option) => {
      return {
        label: getTranslatedContent({ content: option.label, render: renderI18nObject }),
        value: option.value,
      }
    }) || []
  }, [options, renderI18nObject, watchedValues])

  const value = useStore(field.form.store, s => s.values[field.name])
  const stringValue = typeof value === 'string' ? value : undefined
  const booleanValue = typeof value === 'boolean' ? value : undefined

  const { data: dynamicOptionsData, isLoading: isDynamicOptionsLoading, error: dynamicOptionsError } = useTriggerPluginDynamicOptions(
    dynamicSelectParams || {
      plugin_id: '',
      provider: '',
      action: '',
      parameter: '',
      credential_id: '',
    },
    formItemType === FormTypeEnum.dynamicSelect,
  )

  const dynamicOptions = useMemo(() => {
    if (!dynamicOptionsData?.options)
      return []
    return dynamicOptionsData.options.map(option => ({
      label: getTranslatedContent({ content: option.label, render: renderI18nObject }),
      value: option.value,
    }))
  }, [dynamicOptionsData, renderI18nObject])

  const handleChange = useCallback((value: unknown) => {
    field.handleChange(value)
    onChange?.(field.name, value)
  }, [field, onChange])
  const dynamicPlaceholder = isDynamicOptionsLoading
    ? t('dynamicSelect.loading', { ns: 'common' })
    : translatedPlaceholder
  const dynamicNoticeTitle = dynamicOptionsError
    ? t('dynamicSelect.error', { ns: 'common' })
    : (!dynamicOptions.length ? t('dynamicSelect.noData', { ns: 'common' }) : null)
  const dynamicNoticeClassName = dynamicOptionsError ? 'text-text-destructive-secondary' : undefined

  return (
    <>
      <div className={cn(fieldClassName)}>
        <div className={cn(labelClassName, formLabelClassName)}>
          {translatedLabel}
          {
            required && !isValidElement(label) && (
              <span className="ml-1 text-text-destructive-secondary">*</span>
            )
          }
          {translatedTooltip && (
            <Infotip aria-label={translatedTooltip} className="ml-0.5" popupClassName="w-[200px]">
              {translatedTooltip}
            </Infotip>
          )}
        </div>
        <div className={cn(inputContainerClassName)}>
          {
            [FormTypeEnum.textInput, FormTypeEnum.secretInput, FormTypeEnum.textNumber].includes(formItemType) && (
              <Input
                id={field.name}
                name={field.name}
                className={cn(inputClassName, VALIDATE_STATUS_STYLE_MAP[fieldState?.validateStatus as FormItemValidateStatusEnum]?.componentClassName)}
                value={value || ''}
                onChange={(e) => {
                  handleChange(e.target.value)
                }}
                onBlur={field.handleBlur}
                disabled={disabled}
                placeholder={translatedPlaceholder}
                {...getExtraProps(formItemType)}
                showCopyIcon={showCopy}
              />
            )
          }
          {
            formItemType === FormTypeEnum.select && (multiple
              ? (
                  <Select
                    multiple
                    items={memorizedOptions}
                    value={Array.isArray(value) ? value : []}
                    disabled={disabled}
                    onValueChange={handleChange}
                  >
                    <SelectTrigger id={field.name} aria-label={translatedLabel || field.name} className="px-2">
                      <SelectValue placeholder={translatedPlaceholder}>
                        {(selectedValue: string[]) => selectedValue.length
                          ? t('dynamicSelect.selected', { ns: 'common', count: selectedValue.length })
                          : translatedPlaceholder}
                      </SelectValue>
                    </SelectTrigger>
                    <SelectContent popupClassName="max-h-[320px] bg-components-panel-bg-blur">
                      {memorizedOptions.map(option => (
                        <SelectItem key={option.value} value={option.value}>
                          <SelectItemText>{option.label}</SelectItemText>
                          <SelectItemIndicator />
                        </SelectItem>
                      ))}
                    </SelectContent>
                  </Select>
                )
              : (
                  <Select
                    items={memorizedOptions}
                    value={getSingleSelectValue(value, memorizedOptions)}
                    disabled={disabled}
                    onValueChange={(next) => {
                      if (next == null)
                        return
                      handleChange(next)
                    }}
                  >
                    <SelectTrigger id={field.name} aria-label={translatedLabel || field.name} className="px-2">
                      <SelectValue placeholder={translatedPlaceholder}>
                        {nextValue => getSingleSelectLabel(nextValue, memorizedOptions, translatedPlaceholder)}
                      </SelectValue>
                    </SelectTrigger>
                    <SelectContent popupClassName="max-h-[320px] bg-components-panel-bg-blur">
                      {memorizedOptions.map(option => (
                        <SelectItem key={option.value} value={option.value}>
                          <SelectItemText>{option.label}</SelectItemText>
                          <SelectItemIndicator />
                        </SelectItem>
                      ))}
                    </SelectContent>
                  </Select>
                ))
          }
          {
            formItemType === FormTypeEnum.checkbox /* && multiple */ && (
              <CheckboxList
                name={field.name}
                title={name}
                value={value}
                onChange={v => field.handleChange(v)}
                options={memorizedOptions}
                maxHeight="200px"
              />
            )
          }
          {
            formItemType === FormTypeEnum.dynamicSelect && (multiple
              ? (
                  <Select
                    multiple
                    items={dynamicOptions}
                    value={Array.isArray(value) ? value : []}
                    disabled={disabled || isDynamicOptionsLoading}
                    onValueChange={field.handleChange}
                  >
                    <SelectTrigger id={field.name} aria-label={translatedLabel || field.name} className="px-2">
                      <SelectValue placeholder={dynamicPlaceholder}>
                        {(selectedValue: string[]) => selectedValue.length
                          ? t('dynamicSelect.selected', { ns: 'common', count: selectedValue.length })
                          : dynamicPlaceholder}
                      </SelectValue>
                    </SelectTrigger>
                    <SelectContent popupClassName="bg-components-panel-bg-blur">
                      {dynamicNoticeTitle && (
                        <div className={cn(
                          'flex h-[22px] items-center px-3 system-xs-medium-uppercase text-text-tertiary',
                          dynamicNoticeClassName,
                        )}
                        >
                          {dynamicNoticeTitle}
                        </div>
                      )}
                      {dynamicOptions.map(option => (
                        <SelectItem key={option.value} value={option.value}>
                          <SelectItemText>{option.label}</SelectItemText>
                          <SelectItemIndicator />
                        </SelectItem>
                      ))}
                    </SelectContent>
                  </Select>
                )
              : (
                  <Select
                    items={dynamicOptions}
                    value={getSingleSelectValue(value, dynamicOptions)}
                    disabled={disabled || isDynamicOptionsLoading}
                    onValueChange={(next) => {
                      if (next == null)
                        return
                      field.handleChange(next)
                    }}
                  >
                    <SelectTrigger id={field.name} aria-label={translatedLabel || field.name} className="px-2">
                      <SelectValue placeholder={dynamicPlaceholder}>
                        {nextValue => getSingleSelectLabel(nextValue, dynamicOptions, dynamicPlaceholder)}
                      </SelectValue>
                    </SelectTrigger>
                    <SelectContent popupClassName="bg-components-panel-bg-blur">
                      {dynamicNoticeTitle && (
                        <div className={cn(
                          'flex h-[22px] items-center px-3 system-xs-medium-uppercase text-text-tertiary',
                          dynamicNoticeClassName,
                        )}
                        >
                          {dynamicNoticeTitle}
                        </div>
                      )}
                      {dynamicOptions.map(option => (
                        <SelectItem key={option.value} value={option.value}>
                          <SelectItemText>{option.label}</SelectItemText>
                          <SelectItemIndicator />
                        </SelectItem>
                      ))}
                    </SelectContent>
                  </Select>
                ))
          }
          {
            formItemType === FormTypeEnum.radio && (
              <FieldRoot name={name} className="contents">
                <FieldsetRoot
                  render={(
                    <RadioGroup
                      value={stringValue}
                      onValueChange={optionValue => handleChange(optionValue)}
                      className={cn(
                        memorizedOptions.length >= 3 && 'flex-col items-stretch',
                      )}
                    />
                  )}
                >
                  <FieldsetLegend className="sr-only">{translatedLabel || name}</FieldsetLegend>
                  {
                    memorizedOptions.map(option => (
                      <FieldItem key={option.value} className={cn('min-w-0', memorizedOptions.length < 3 && 'flex-1 grow')}>
                        <FieldLabel
                          className={cn(
                            'hover:bg-components-option-card-option-hover-bg hover:border-components-option-card-option-hover-border flex h-8 w-full cursor-pointer items-center justify-center gap-2 rounded-lg border border-components-option-card-option-border bg-components-option-card-option-bg p-2 system-sm-regular text-text-secondary',
                            value === option.value && 'border-components-option-card-option-selected-border bg-components-option-card-option-selected-bg text-text-primary shadow-xs',
                            disabled && 'cursor-not-allowed opacity-50',
                            inputClassName,
                          )}
                        >
                          {
                            formSchema.showRadioUI && (
                              <Radio
                                className="mr-2"
                                value={option.value}
                                disabled={disabled}
                              />
                            )
                          }
                          {!formSchema.showRadioUI && (
                            <Radio
                              className="sr-only"
                              value={option.value}
                              disabled={disabled}
                            />
                          )}
                          {option.label}
                        </FieldLabel>
                      </FieldItem>
                    ))
                  }
                </FieldsetRoot>
              </FieldRoot>
            )
          }
          {
            formItemType === FormTypeEnum.boolean && (
              <FieldRoot name={name} className="contents">
                <FieldsetRoot
                  render={(
                    <RadioGroup<boolean>
                      className="w-fit gap-3"
                      value={booleanValue}
                      onValueChange={v => field.handleChange(v)}
                    />
                  )}
                >
                  <FieldsetLegend className="sr-only">{translatedLabel || name}</FieldsetLegend>
                  <FieldItem>
                    <FieldLabel className="flex items-center gap-1.5 system-sm-regular text-text-secondary">
                      <Radio value={true} />
                      True
                    </FieldLabel>
                  </FieldItem>
                  <FieldItem>
                    <FieldLabel className="flex items-center gap-1.5 system-sm-regular text-text-secondary">
                      <Radio value={false} />
                      False
                    </FieldLabel>
                  </FieldItem>
                </FieldsetRoot>
              </FieldRoot>
            )
          }
          {fieldState?.validateStatus && [FormItemValidateStatusEnum.Error, FormItemValidateStatusEnum.Warning].includes(fieldState?.validateStatus) && (
            <div className={cn(
              'mt-1 px-0 py-[2px] system-xs-regular',
              VALIDATE_STATUS_STYLE_MAP[fieldState?.validateStatus].textClassName,
            )}
            >
              {fieldState?.[VALIDATE_STATUS_STYLE_MAP[fieldState?.validateStatus].infoFieldName as keyof FieldState]}
            </div>
          )}
        </div>
      </div>
      {description && (
        <div className="mt-4 system-xs-regular text-text-tertiary">
          {translatedDescription}
        </div>
      )}
      {
        url && (
          <a
            className="mt-4 flex items-center system-xs-regular text-text-accent"
            href={url}
            target="_blank"
          >
            <span className="break-all">
              {translatedHelp}
            </span>
            <div className="ml-1 i-ri-external-link-line size-3 shrink-0" />
          </a>
        )
      }
    </>

  )
}

export default memo(BaseField)
