'use client'
import type { FC } from 'react'
import type { Condition } from '../types'
import { cn } from '@langgenius/dify-ui/cn'
import {
  Select,
  SelectContent,
  SelectItem,
  SelectItemIndicator,
  SelectItemText,
  SelectTrigger,
} from '@langgenius/dify-ui/select'
import * as React from 'react'
import { useCallback, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
import Input from '@/app/components/workflow/nodes/_base/components/input-support-select-var'
import useAvailableVarList from '@/app/components/workflow/nodes/_base/hooks/use-available-var-list'
import { FILE_TYPE_OPTIONS, TRANSFER_METHOD } from '@/app/components/workflow/nodes/constants'
import { getConditionValueAsString } from '@/app/components/workflow/nodes/utils'
import BoolValue from '../../../panel/chat-variable-panel/components/bool-value'
import { VarType } from '../../../types'
import ConditionOperator from '../../if-else/components/condition-list/condition-operator'
import { ComparisonOperator } from '../../if-else/types'
import { comparisonOperatorNotRequireValue, getOperators } from '../../if-else/utils'
import SubVariablePicker from './sub-variable-picker'

type VariableInputProps = React.ComponentProps<typeof Input>

const optionNameI18NPrefix = 'nodes.ifElse.optionName'

const VAR_INPUT_SUPPORTED_KEYS: Record<string, VarType> = {
  name: VarType.string,
  url: VarType.string,
  extension: VarType.string,
  mime_type: VarType.string,
  related_id: VarType.string,
  size: VarType.number,
}

type Props = Readonly<{
  condition: Condition
  varType: VarType
  onChange: (condition: Condition) => void
  hasSubVariable: boolean
  readOnly: boolean
  nodeId: string
}>

const getExpectedVarType = (condition: Condition, varType: VarType) => {
  return condition.key ? VAR_INPUT_SUPPORTED_KEYS[condition.key] : varType
}

const getSelectOptions = (
  condition: Condition,
  isSelect: boolean,
  t: ReturnType<typeof useTranslation>['t'],
) => {
  if (!isSelect) return []

  if (condition.key === 'type' || condition.comparison_operator === ComparisonOperator.allOf) {
    return FILE_TYPE_OPTIONS.map((item) => ({
      name: t(($) => $[`${optionNameI18NPrefix}.${item.i18nKey}`], { ns: 'workflow' }),
      value: item.value,
    }))
  }

  if (condition.key === 'transfer_method') {
    return TRANSFER_METHOD.map((item) => ({
      name: t(($) => $[`${optionNameI18NPrefix}.${item.i18nKey}`], { ns: 'workflow' }),
      value: item.value,
    }))
  }

  return []
}

const getFallbackInputType = ({
  hasSubVariable,
  condition,
  varType,
}: {
  hasSubVariable: boolean
  condition: Condition
  varType: VarType
}) => {
  return (hasSubVariable && condition.key === 'size') ||
    (!hasSubVariable && varType === VarType.number)
    ? 'number'
    : 'text'
}

const ValueInput = ({
  comparisonOperator,
  isSelect,
  isArrayValue,
  isBoolean,
  supportVariableInput,
  selectOptions,
  condition,
  readOnly,
  availableVars,
  availableNodesWithParent,
  onFocusChange,
  onChange,
  hasSubVariable,
  varType,
  t,
}: {
  comparisonOperator: ComparisonOperator
  isSelect: boolean
  isArrayValue: boolean
  isBoolean: boolean
  supportVariableInput: boolean
  selectOptions: Array<{ name: string; value: string }>
  condition: Condition
  readOnly: boolean
  availableVars: VariableInputProps['nodesOutputVars']
  availableNodesWithParent: VariableInputProps['availableNodes']
  onFocusChange: (value: boolean) => void
  onChange: (value: unknown) => void
  hasSubVariable: boolean
  varType: VarType
  t: ReturnType<typeof useTranslation>['t']
}) => {
  const [isFocus, setIsFocus] = useState(false)

  const handleFocusChange = (value: boolean) => {
    setIsFocus(value)
    onFocusChange(value)
  }

  if (comparisonOperatorNotRequireValue(comparisonOperator)) return null

  if (isSelect) {
    const selectedValue = isArrayValue
      ? (condition.value as string[])?.[0]
      : (condition.value as string)
    const selectedOption = selectOptions.find((option) => option.value === selectedValue) ?? null

    return (
      <Select
        value={selectedOption?.value ?? null}
        disabled={readOnly}
        onValueChange={(value) => value && onChange(value)}
      >
        <SelectTrigger className="h-8 grow text-[13px]">
          {selectedOption?.name ?? 'Select value'}
        </SelectTrigger>
        <SelectContent>
          {selectOptions.map((option) => (
            <SelectItem key={option.value} value={option.value}>
              <SelectItemText>{option.name}</SelectItemText>
              <SelectItemIndicator />
            </SelectItem>
          ))}
        </SelectContent>
      </Select>
    )
  }

  if (isBoolean) {
    return <BoolValue value={condition.value as boolean} onChange={onChange} />
  }

  if (supportVariableInput) {
    return (
      <Input
        instanceId="filter-condition-input"
        className={cn(
          isFocus
            ? 'border-components-input-border-active bg-components-input-bg-active shadow-xs'
            : 'border-components-input-border-hover bg-components-input-bg-normal',
          'w-0 grow rounded-lg border px-3 py-[6px]',
        )}
        value={getConditionValueAsString(condition)}
        onChange={onChange}
        readOnly={readOnly}
        nodesOutputVars={availableVars}
        availableNodes={availableNodesWithParent}
        onFocusChange={handleFocusChange}
        placeholder={
          !readOnly ? t(($) => $['nodes.http.insertVarPlaceholder'], { ns: 'workflow' })! : ''
        }
        placeholderClassName="leading-[21px]!"
      />
    )
  }

  return (
    <input
      type={getFallbackInputType({ hasSubVariable, condition, varType })}
      className="grow rounded-lg border border-components-input-border-hover bg-components-input-bg-normal px-3 py-[6px]"
      value={getConditionValueAsString(condition)}
      onChange={(e) => onChange(e.target.value)}
      readOnly={readOnly}
    />
  )
}

const FilterCondition: FC<Props> = ({
  condition = { key: '', comparison_operator: ComparisonOperator.equal, value: '' },
  varType,
  onChange,
  hasSubVariable,
  readOnly,
  nodeId,
}) => {
  const { t } = useTranslation()

  const expectedVarType = getExpectedVarType(condition, varType)
  const supportVariableInput = !!expectedVarType

  const { availableVars, availableNodesWithParent } = useAvailableVarList(nodeId, {
    onlyLeafNodeVar: false,
    filterVar: (varPayload) => {
      return expectedVarType ? varPayload.type === expectedVarType : true
    },
  })

  const isSelect = [
    ComparisonOperator.in,
    ComparisonOperator.notIn,
    ComparisonOperator.allOf,
  ].includes(condition.comparison_operator)
  const isArrayValue = condition.key === 'transfer_method' || condition.key === 'type'
  const isBoolean = varType === VarType.boolean

  const selectOptions = useMemo(
    () => getSelectOptions(condition, isSelect, t),
    [condition, isSelect, t],
  )

  const handleChange = useCallback(
    (key: string) => {
      return (value: any) => {
        onChange({
          ...condition,
          [key]: isArrayValue && key === 'value' ? [value] : value,
        })
      }
    },
    [condition, onChange, isArrayValue],
  )

  const handleSubVariableChange = useCallback(
    (value: string) => {
      const operators = getOperators(expectedVarType ?? VarType.string, { key: value })
      const newOperator = operators.length > 0 ? operators[0]! : ComparisonOperator.equal
      onChange({
        key: value,
        comparison_operator: newOperator,
        value: '',
      })
    },
    [onChange, expectedVarType],
  )

  return (
    <div>
      {hasSubVariable && (
        <SubVariablePicker
          className="mb-2"
          value={condition.key}
          onChange={handleSubVariableChange}
        />
      )}
      <div className="flex space-x-1">
        <ConditionOperator
          className="h-8 bg-components-input-bg-normal"
          varType={expectedVarType ?? varType ?? VarType.string}
          value={condition.comparison_operator}
          onSelect={handleChange('comparison_operator')}
          file={hasSubVariable ? { key: condition.key } : undefined}
          disabled={readOnly}
        />
        <ValueInput
          comparisonOperator={condition.comparison_operator}
          isSelect={isSelect}
          isArrayValue={isArrayValue}
          isBoolean={isBoolean}
          supportVariableInput={supportVariableInput}
          selectOptions={selectOptions}
          condition={condition}
          readOnly={readOnly}
          availableVars={availableVars}
          availableNodesWithParent={availableNodesWithParent}
          onFocusChange={(_value) => {}}
          onChange={handleChange('value')}
          hasSubVariable={hasSubVariable}
          varType={varType}
          t={t}
        />
      </div>
    </div>
  )
}

export default React.memo(FilterCondition)
