'use client'

import type { FC, ReactElement } from 'react'
import type { VarType as VarKindType } from '../../../tool/types'
import type { CredentialFormSchema, CredentialFormSchemaSelect } from '@/app/components/header/account-setting/model-provider-page/declarations'
import type { Tool } from '@/app/components/tools/types'
import type { TriggerWithProvider } from '@/app/components/workflow/block-selector/types'
import type { Node, ToolWithProvider, ValueSelector, Var } from '@/app/components/workflow/types'
import { cn } from '@langgenius/dify-ui/cn'
import { PopoverTrigger } from '@langgenius/dify-ui/popover'
import { PreviewCard, PreviewCardContent, PreviewCardTrigger } from '@langgenius/dify-ui/preview-card'
import { Tooltip, TooltipContent, TooltipTrigger } from '@langgenius/dify-ui/tooltip'
import { RiArrowDownSLine, RiCloseLine, RiErrorWarningFill, RiLoader4Line, RiMoreLine } from '@remixicon/react'
import { useTranslation } from 'react-i18next'
import Badge from '@/app/components/base/badge'
import { Line3 } from '@/app/components/base/icons/src/public/common'
import { Variable02 } from '@/app/components/base/icons/src/vender/solid/development'
import { VarBlockIcon } from '@/app/components/workflow/block-icon'
import TypeSelector from '@/app/components/workflow/nodes/_base/components/selector'
import { VariableIconWithColor } from '@/app/components/workflow/nodes/_base/components/variable/variable-label'
import RemoveButton from '../remove-button'
import ConstantField from './constant-field'

export type HoverPopup
  = | { kind: 'full-path', panel: ReactElement }
    | { kind: 'invalid-variable', message: string }

type Props = Readonly<{
  className?: string
  controlFocus: number
  currentProvider?: ToolWithProvider | TriggerWithProvider
  currentTool?: Tool
  handleClearVar: () => void
  handleVarKindTypeChange: (value: VarKindType) => void
  handleVariableJump: (nodeId: string) => void
  hasValue: boolean
  inputRef: React.RefObject<HTMLInputElement | null>
  inTable?: boolean
  isAddBtnTrigger?: boolean
  isConstant: boolean
  isException: boolean
  isFocus: boolean
  isInTable?: boolean
  isJustShowValue?: boolean
  isLoading: boolean
  isShowAPart: boolean
  isShowNodeName: boolean
  isSupportConstantValue?: boolean
  maxNodeNameWidth: number
  maxTypeWidth: number
  maxVarNameWidth: number
  onChange: (value: ValueSelector | string, varKindType: VarKindType, varInfo?: Var) => void
  onRemove?: () => void
  open: boolean
  outputVarNode?: Node['data'] | null
  outputVarNodeId?: string
  placeholder?: string
  readonly: boolean
  schemaWithDynamicSelect?: Partial<CredentialFormSchema>
  setControlFocus: (value: number) => void
  setOpen: (value: boolean) => void
  showErrorIcon?: boolean
  hoverPopup: HoverPopup | null
  triggerRef: React.RefObject<HTMLDivElement | null>
  type?: string
  typePlaceHolder?: string
  value: ValueSelector | string
  valueTypePlaceHolder?: string
  varKindType: VarKindType
  varKindTypes: Array<{ label: string, value: VarKindType }>
  varName: string
  variableCategory: string
}>

const VarReferencePickerTrigger: FC<Props> = ({
  className,
  controlFocus,
  handleClearVar,
  handleVarKindTypeChange,
  handleVariableJump,
  hasValue,
  inputRef,
  isAddBtnTrigger,
  isConstant,
  isException,
  isFocus,
  isInTable,
  isJustShowValue,
  isLoading,
  isShowAPart,
  isShowNodeName,
  isSupportConstantValue,
  maxNodeNameWidth,
  maxTypeWidth,
  maxVarNameWidth,
  onChange,
  onRemove,
  open,
  outputVarNode,
  outputVarNodeId,
  placeholder,
  readonly,
  schemaWithDynamicSelect,
  setControlFocus,
  setOpen,
  showErrorIcon = false,
  hoverPopup,
  triggerRef,
  type,
  typePlaceHolder,
  value,
  valueTypePlaceHolder,
  varKindType,
  varKindTypes,
  varName,
  variableCategory,
}) => {
  const { t } = useTranslation()
  const handleTriggerReadonlyClick = (e: React.MouseEvent<HTMLElement>) => {
    if (!readonly)
      return
    e.preventDefault()
    e.stopPropagation()
  }

  const pill = (
    <div className={cn('h-full items-center rounded-[5px] px-1.5', hasValue ? 'inline-flex bg-components-badge-white-to-dark' : 'flex')}>
      {hasValue
        ? (
            <>
              {isShowNodeName && (
                <div
                  className="flex items-center"
                  onClick={(e) => {
                    if (e.metaKey || e.ctrlKey)
                      handleVariableJump(outputVarNodeId || '')
                  }}
                >
                  <div className="h-3 px-px">
                    {'type' in (outputVarNode || {}) && outputVarNode?.type && (
                      <VarBlockIcon
                        type={outputVarNode.type}
                        className="text-text-primary"
                      />
                    )}
                  </div>
                  <div
                    className="mx-0.5 truncate text-xs font-medium text-text-secondary"
                    title={outputVarNode?.title as string | undefined}
                    style={{ maxWidth: maxNodeNameWidth }}
                  >
                    {outputVarNode?.title as string | undefined}
                  </div>
                  <Line3 className="mr-0.5"></Line3>
                </div>
              )}
              {isShowAPart && (
                <div className="flex items-center">
                  <RiMoreLine className="size-3 text-text-secondary" />
                  <Line3 className="mr-0.5 text-divider-deep"></Line3>
                </div>
              )}
              <div className="flex items-center text-text-accent">
                {isLoading && <RiLoader4Line className="size-3.5 animate-spin text-text-secondary" />}
                <VariableIconWithColor
                  variables={value as ValueSelector}
                  variableCategory={variableCategory}
                  isExceptionVariable={isException}
                />
                <div
                  className={cn('ml-0.5 truncate text-xs font-medium', isException && 'text-text-warning')}
                  title={varName}
                  style={{ maxWidth: maxVarNameWidth }}
                >
                  {varName}
                </div>
              </div>
              <div
                className="ml-0.5 truncate text-center system-xs-regular text-text-tertiary capitalize"
                title={type}
                style={{ maxWidth: maxTypeWidth }}
              >
                {type}
              </div>
              {showErrorIcon && <RiErrorWarningFill data-testid="var-reference-picker-error-icon" className="ml-0.5 size-3 text-text-destructive" />}
            </>
          )
        : (
            <div className={`overflow-hidden ${readonly ? 'text-components-input-text-disabled' : 'text-components-input-text-placeholder'} system-sm-regular text-ellipsis`}>
              {isLoading
                ? (
                    <div className="flex items-center">
                      <RiLoader4Line className="mr-1 size-3.5 animate-spin text-text-secondary" />
                      <span>{placeholder}</span>
                    </div>
                  )
                : placeholder}
            </div>
          )}
    </div>
  )

  const hoveredPill = hoverPopup?.kind === 'full-path'
    ? (
        <PreviewCard>
          <PreviewCardTrigger delay={300} closeDelay={200} render={pill} />
          <PreviewCardContent popupClassName="border-0 bg-transparent p-0 shadow-none">
            {hoverPopup.panel}
          </PreviewCardContent>
        </PreviewCard>
      )
    : hoverPopup?.kind === 'invalid-variable'
      ? (
          <Tooltip>
            <TooltipTrigger render={pill} />
            <TooltipContent>{hoverPopup.message}</TooltipContent>
          </Tooltip>
        )
      : pill

  const variablePicker = (
    <div className="h-full grow">
      <div ref={isSupportConstantValue ? triggerRef : null} className={cn('h-full', isSupportConstantValue && 'flex items-center rounded-lg bg-components-panel-bg py-1 pl-1')}>
        {hoveredPill}
      </div>
    </div>
  )

  const resolvedVariablePicker = isSupportConstantValue
    ? (
        readonly
          ? variablePicker
          : (
              <PopoverTrigger
                nativeButton={false}
                render={variablePicker}
                onClick={handleTriggerReadonlyClick}
              />
            )
      )
    : variablePicker

  const triggerContent = (
    <div
      className={cn(className, 'group/picker-trigger-wrap relative flex!', !readonly && 'cursor-pointer')}
      data-testid="var-reference-picker-trigger"
      onClick={() => {
        if (!isConstant || readonly)
          return
        setControlFocus(Date.now())
      }}
    >
      <>
        {isAddBtnTrigger
          ? (
              <div>
                <button
                  type="button"
                  aria-label={t('operation.add', { ns: 'common' })}
                  className="cursor-pointer rounded-md border-none bg-transparent p-1 select-none hover:bg-state-base-hover focus-visible:ring-1 focus-visible:ring-components-input-border-active focus-visible:outline-hidden"
                  onClick={() => {}}
                >
                  <span className="i-ri-add-line size-4 text-text-tertiary" aria-hidden="true" />
                </button>
              </div>
            )
          : (
              <div ref={!isSupportConstantValue ? triggerRef : null} className={cn((open || isFocus) ? 'border-gray-300' : 'border-gray-100', 'group/wrap relative flex h-8 w-full items-center', !isSupportConstantValue && 'rounded-lg bg-components-input-bg-normal p-1', isInTable && 'border-none bg-transparent', readonly && 'bg-components-input-bg-disabled', isJustShowValue && 'h-6 bg-transparent p-0')}>
                {isSupportConstantValue
                  ? (
                      <div
                        onClick={(e) => {
                          e.stopPropagation()
                          setOpen(false)
                          setControlFocus(Date.now())
                        }}
                        className="mr-1 flex h-full items-center space-x-1"
                      >
                        <TypeSelector
                          noLeft
                          trigger={(
                            <div className="flex h-8 items-center rounded-lg bg-components-input-bg-normal px-2">
                              <div className="mr-1 system-sm-regular text-components-input-text-filled">{varKindTypes.find(item => item.value === varKindType)?.label}</div>
                              <RiArrowDownSLine className="size-4 text-text-quaternary" />
                            </div>
                          )}
                          popupClassName="top-8"
                          readonly={readonly}
                          value={varKindType}
                          options={varKindTypes}
                          onChange={handleVarKindTypeChange}
                          showChecked
                        />
                      </div>
                    )
                  : (!hasValue && (
                      <div className="mr-1 ml-1.5">
                        <Variable02 className={`size-4 ${readonly ? 'text-components-input-text-disabled' : 'text-components-input-text-placeholder'}`} />
                      </div>
                    ))}
                {isConstant
                  ? (
                      <ConstantField
                        value={value as string}
                        onChange={onChange as ((value: string | number, varKindType: VarKindType, varInfo?: Var) => void)}
                        schema={schemaWithDynamicSelect as CredentialFormSchemaSelect}
                        readonly={readonly}
                        isLoading={isLoading}
                      />
                    )
                  : resolvedVariablePicker}
                {(hasValue && !readonly && !isInTable && !isJustShowValue) && (
                  <button
                    type="button"
                    aria-label={t('operation.clear', { ns: 'common' })}
                    className="group invisible absolute top-[50%] right-1 h-5 translate-y-[-50%] cursor-pointer rounded-md border-none bg-transparent p-1 group-hover/wrap:visible hover:bg-state-base-hover"
                    onClick={handleClearVar}
                  >
                    <RiCloseLine className="size-3.5 text-text-tertiary group-hover:text-text-secondary" aria-hidden="true" />
                  </button>
                )}
                {!hasValue && valueTypePlaceHolder && (
                  <Badge
                    className="absolute top-[50%] right-1 translate-y-[-50%] capitalize"
                    text={valueTypePlaceHolder}
                    uppercase={false}
                  />
                )}
              </div>
            )}
        {!readonly && isInTable && (
          <RemoveButton
            className="absolute top-0.5 right-1 hidden group-hover/picker-trigger-wrap:block"
            onClick={() => onRemove?.()}
          />
        )}

        {!hasValue && typePlaceHolder && (
          <Badge
            className="absolute top-1.5 right-2"
            text={typePlaceHolder}
            uppercase={false}
          />
        )}
      </>
      <input ref={inputRef} className="sr-only" value={controlFocus} readOnly />
    </div>
  )

  if (!isSupportConstantValue) {
    if (readonly)
      return triggerContent

    return (
      <PopoverTrigger
        nativeButton={false}
        render={triggerContent}
        onClick={handleTriggerReadonlyClick}
      />
    )
  }

  return triggerContent
}

export default VarReferencePickerTrigger
