'use client'
import type { FC, ReactNode } from 'react'
import type { ModelConfig, Node, NodeOutPutVar, Variable } from '../../../../types'
import { cn } from '@langgenius/dify-ui/cn'
import { Popover, PopoverContent, PopoverTrigger } from '@langgenius/dify-ui/popover'
import { Switch } from '@langgenius/dify-ui/switch'
import { Tooltip, TooltipContent, TooltipTrigger } from '@langgenius/dify-ui/tooltip'
import { RiDeleteBinLine } from '@remixicon/react'
import { useBoolean } from 'ahooks'
import copy from 'copy-to-clipboard'
import * as React from 'react'
import { useCallback, useRef } from 'react'
import { useTranslation } from 'react-i18next'
import ActionButton from '@/app/components/base/action-button'
import { Copy, CopyCheck } from '@/app/components/base/icons/src/vender/line/files'
import { Variable02 } from '@/app/components/base/icons/src/vender/solid/development'
import { Jinja } from '@/app/components/base/icons/src/vender/workflow'
import PromptEditor from '@/app/components/base/prompt-editor'
import { PROMPT_EDITOR_INSERT_QUICKLY } from '@/app/components/base/prompt-editor/plugins/update-block'
import CodeEditor from '@/app/components/workflow/nodes/_base/components/editor/code-editor/editor-support-vars'
import ToggleExpandBtn from '@/app/components/workflow/nodes/_base/components/toggle-expand-btn'
import useToggleExpend from '@/app/components/workflow/nodes/_base/hooks/use-toggle-expend'
import { useStore } from '@/app/components/workflow/store'
import { useEventEmitterContextContext } from '@/context/event-emitter'
import { useWorkflowVariableType } from '../../../../hooks/use-workflow-variables'
import { BlockEnum, EditionType } from '../../../../types'
import { CodeLanguage } from '../../../code/types'
import PromptGeneratorBtn from '../../../llm/components/prompt-generator-btn'
import Wrap from '../editor/wrap'

type Props = Readonly<{
  className?: string
  headerClassName?: string
  instanceId?: string
  nodeId?: string
  editorId?: string
  title: string | React.JSX.Element
  value: string
  onChange: (value: string) => void
  readOnly?: boolean
  showRemove?: boolean
  onRemove?: () => void
  justVar?: boolean
  isChatModel?: boolean
  isChatApp?: boolean
  isShowContext?: boolean
  hasSetBlockStatus?: {
    context: boolean
    history: boolean
    query: boolean
  }
  nodesOutputVars?: NodeOutPutVar[]
  availableNodes?: Node[]
  isSupportFileVar?: boolean
  isSupportPromptGenerator?: boolean
  onGenerated?: (prompt: string) => void
  modelConfig?: ModelConfig
  // for jinja
  isSupportJinja?: boolean
  editionType?: EditionType
  onEditionTypeChange?: (editionType: EditionType) => void
  varList?: Variable[]
  handleAddVariable?: (payload: any) => void
  containerBackgroundClassName?: string
  gradientBorder?: boolean
  titleTooltip?: ReactNode
  inputClassName?: string
  editorContainerClassName?: string
  placeholder?: string
  placeholderClassName?: string
  titleClassName?: string
  required?: boolean
}>

const Editor: FC<Props> = ({
  className,
  headerClassName,
  instanceId,
  nodeId,
  editorId,
  title,
  value,
  onChange,
  readOnly,
  showRemove,
  onRemove,
  justVar,
  isChatModel,
  isChatApp,
  isShowContext,
  hasSetBlockStatus,
  nodesOutputVars,
  availableNodes = [],
  isSupportFileVar,
  isSupportPromptGenerator,
  isSupportJinja,
  editionType,
  onEditionTypeChange,
  varList = [],
  handleAddVariable,
  onGenerated,
  modelConfig,
  containerBackgroundClassName: containerClassName,
  gradientBorder = true,
  titleTooltip,
  inputClassName,
  placeholder,
  placeholderClassName,
  titleClassName,
  editorContainerClassName,
  required,
}) => {
  const { t } = useTranslation()
  const { eventEmitter } = useEventEmitterContextContext()
  const controlPromptEditorRerenderKey = useStore((s) => s.controlPromptEditorRerenderKey)

  const isShowHistory = !isChatModel && isChatApp

  const ref = useRef<HTMLDivElement>(null)
  const { wrapClassName, wrapStyle, isExpand, setIsExpand, editorExpandHeight } = useToggleExpend({
    ref,
    isInNode: true,
  })
  const [isCopied, setIsCopied] = React.useState(false)
  const handleCopy = useCallback(() => {
    copy(value)
    setIsCopied(true)
  }, [value])

  const [isFocus, { setTrue: setFocus, setFalse: setBlur }] = useBoolean(false)

  const handleInsertVariable = () => {
    setFocus()
    eventEmitter?.emit({ type: PROMPT_EDITOR_INSERT_QUICKLY, instanceId } as any)
  }

  const getVarType = useWorkflowVariableType()
  const pipelineId = useStore((s) => s.pipelineId)
  const setShowInputFieldPanel = useStore((s) => s.setShowInputFieldPanel)

  return (
    <Wrap className={cn(className, wrapClassName)} style={wrapStyle} isInNode isExpand={isExpand}>
      <div
        ref={ref}
        className={cn(
          isFocus
            ? gradientBorder &&
                'bg-linear-to-r from-components-input-border-active-prompt-1 to-components-input-border-active-prompt-2'
            : 'bg-transparent',
          isExpand && 'h-full',
          'rounded-[9px]! p-0.5',
          containerClassName,
        )}
      >
        <div
          className={cn(
            isFocus ? 'bg-background-default' : 'bg-components-input-bg-normal',
            isExpand && 'flex h-full flex-col',
            'rounded-lg',
            containerClassName,
          )}
        >
          <div className={cn('flex items-center justify-between pt-1 pr-2 pl-3', headerClassName)}>
            <div className="flex gap-2">
              <div
                className={cn(
                  'text-xs/4 font-semibold text-text-secondary uppercase',
                  titleClassName,
                )}
              >
                {title} {required && <span className="text-text-destructive">*</span>}
              </div>
              {!!titleTooltip && (
                <Popover>
                  <PopoverTrigger
                    openOnHover
                    aria-label={
                      typeof titleTooltip === 'string'
                        ? titleTooltip
                        : typeof title === 'string'
                          ? title
                          : 'Help'
                    }
                    render={
                      <button
                        type="button"
                        className="flex size-4 shrink-0 items-center justify-center rounded-sm p-px outline-hidden hover:bg-state-base-hover focus-visible:ring-1 focus-visible:ring-components-input-border-hover"
                      >
                        <span
                          aria-hidden
                          className="i-ri-question-line size-3.5 text-text-quaternary hover:text-text-tertiary"
                        />
                      </button>
                    }
                  />
                  <PopoverContent popupClassName="max-w-[300px] px-3 py-2 system-xs-regular text-text-tertiary">
                    {titleTooltip}
                  </PopoverContent>
                </Popover>
              )}
            </div>
            <div className="flex items-center">
              <div className="text-xs leading-[18px] font-medium text-text-tertiary">
                {value?.length || 0}
              </div>
              {isSupportPromptGenerator && (
                <PromptGeneratorBtn
                  nodeId={nodeId!}
                  editorId={editorId}
                  className="ml-[5px]"
                  onGenerated={onGenerated}
                  modelConfig={modelConfig}
                  currentPrompt={value}
                />
              )}

              <div className="mx-2 h-3 w-px bg-divider-regular"></div>
              {/* Operations */}
              <div className="flex items-center space-x-[2px]">
                {isSupportJinja && (
                  <div
                    className={cn(
                      editionType === EditionType.jinja2 &&
                        'border-components-button-ghost-bg-hover bg-components-button-ghost-bg-hover',
                      'flex h-[22px] items-center space-x-0.5 rounded-[5px] border border-transparent px-1.5 hover:border-components-button-ghost-bg-hover',
                    )}
                  >
                    <Popover>
                      <PopoverTrigger
                        openOnHover
                        aria-label={t(($) => $['common.enableJinja'], { ns: 'workflow' })}
                        render={
                          <button
                            type="button"
                            className="flex h-4 w-7 items-center justify-center rounded-sm outline-hidden hover:bg-state-base-hover focus-visible:ring-1 focus-visible:ring-components-input-border-hover"
                          >
                            <Jinja className="h-3 w-6 text-text-quaternary" />
                          </button>
                        }
                      />
                      <PopoverContent popupClassName="px-3 py-2 system-xs-regular text-text-tertiary">
                        <div>
                          <div>{t(($) => $['common.enableJinja'], { ns: 'workflow' })}</div>
                          <a
                            className="text-text-accent hover:underline"
                            target="_blank"
                            rel="noopener noreferrer"
                            href="https://jinja.palletsprojects.com/en/2.10.x/"
                          >
                            {t(($) => $['common.learnMore'], { ns: 'workflow' })}
                          </a>
                        </div>
                      </PopoverContent>
                    </Popover>
                    <Switch
                      size="sm"
                      checked={editionType === EditionType.jinja2}
                      onCheckedChange={(checked) => {
                        onEditionTypeChange?.(checked ? EditionType.jinja2 : EditionType.basic)
                      }}
                    />
                  </div>
                )}
                {!readOnly && (
                  <Tooltip>
                    <TooltipTrigger
                      render={
                        <ActionButton onClick={handleInsertVariable}>
                          <Variable02 className="size-4" />
                        </ActionButton>
                      }
                    />
                    <TooltipContent>
                      {t(($) => $['common.insertVarTip'], { ns: 'workflow' })}
                    </TooltipContent>
                  </Tooltip>
                )}
                {showRemove && (
                  <ActionButton onClick={onRemove}>
                    <RiDeleteBinLine className="size-4" />
                  </ActionButton>
                )}
                {!isCopied ? (
                  <ActionButton onClick={handleCopy}>
                    <Copy className="size-4" />
                  </ActionButton>
                ) : (
                  <ActionButton>
                    <CopyCheck className="size-4" />
                  </ActionButton>
                )}
                <ToggleExpandBtn isExpand={isExpand} onExpandChange={setIsExpand} />
              </div>
            </div>
          </div>

          {/* Min: 80 Max: 560. Header: 24 */}
          <div className={cn('pb-2', isExpand && 'flex grow flex-col')}>
            {!(isSupportJinja && editionType === EditionType.jinja2) ? (
              <div
                className={cn(
                  isExpand ? 'grow' : 'max-h-[536px]',
                  'relative min-h-[56px] overflow-y-auto px-3',
                  editorContainerClassName,
                )}
              >
                <PromptEditor
                  key={controlPromptEditorRerenderKey}
                  placeholder={placeholder}
                  placeholderClassName={placeholderClassName}
                  instanceId={instanceId}
                  compact
                  className={cn('min-h-[56px]', inputClassName)}
                  style={isExpand ? { height: editorExpandHeight - 5 } : {}}
                  value={value}
                  contextBlock={{
                    show: justVar ? false : isShowContext,
                    selectable: !hasSetBlockStatus?.context,
                    canNotAddContext: true,
                  }}
                  historyBlock={{
                    show: justVar ? false : isShowHistory,
                    selectable: !hasSetBlockStatus?.history,
                    history: {
                      user: 'Human',
                      assistant: 'Assistant',
                    },
                  }}
                  queryBlock={{
                    show: false, // use [sys.query] instead of query block
                    selectable: false,
                  }}
                  workflowVariableBlock={{
                    show: true,
                    variables: nodesOutputVars || [],
                    getVarType: getVarType as any,
                    workflowNodesMap: availableNodes.reduce((acc, node) => {
                      acc[node.id] = {
                        title: node.data.title,
                        type: node.data.type,
                        width: node.width,
                        height: node.height,
                        position: node.position,
                        ...(node.data.type === BlockEnum.LLM && {
                          modelProvider: (node.data as { model?: ModelConfig }).model?.provider,
                        }),
                      }
                      if (node.data.type === BlockEnum.Start) {
                        acc.sys = {
                          title: t(($) => $['blocks.start'], { ns: 'workflow' }),
                          type: BlockEnum.Start,
                        }
                      }
                      return acc
                    }, {} as any),
                    showManageInputField: !!pipelineId,
                    onManageInputField: () => setShowInputFieldPanel?.(true),
                  }}
                  onChange={onChange}
                  onBlur={setBlur}
                  onFocus={setFocus}
                  editable={!readOnly}
                  isSupportFileVar={isSupportFileVar}
                />
                {/* to patch Editor not support dynamic change editable status */}
                {readOnly && <div className="absolute inset-0 z-10"></div>}
              </div>
            ) : (
              <div
                className={cn(
                  isExpand ? 'grow' : 'max-h-[536px]',
                  'relative min-h-[56px] overflow-y-auto px-3',
                  editorContainerClassName,
                )}
              >
                <CodeEditor
                  availableVars={nodesOutputVars || []}
                  varList={varList}
                  onAddVar={handleAddVariable}
                  isInNode
                  readOnly={readOnly}
                  language={CodeLanguage.python3}
                  value={value}
                  onChange={onChange}
                  noWrapper
                  isExpand={isExpand}
                  className={inputClassName}
                />
              </div>
            )}
          </div>
        </div>
      </div>
    </Wrap>
  )
}
export default React.memo(Editor)
