'use client'

import type { VarType as VarKindType } from '../../../tool/types'
import type { CredentialFormSchema, FormOption } from '@/app/components/header/account-setting/model-provider-page/declarations'
import type { CommonNodeType, Node, NodeOutPutVar, ValueSelector } from '@/app/components/workflow/types'
import { VAR_SHOW_NAME_MAP } from '@/app/components/workflow/constants'
import { getNodeInfoById, isConversationVar, isENV, isGlobalVar, isRagVariableVar, isSystemVar } from './utils'

type DynamicSchemaParams = {
  dynamicOptions: FormOption[] | null
  isLoading: boolean
  schema?: Partial<CredentialFormSchema>
  value: ValueSelector | string
}

type VariableCategoryParams = {
  isChatVar: boolean
  isEnv: boolean
  isGlobal: boolean
  isLoopVar: boolean
  isRagVar: boolean
}

type OutputVarNodeParams = {
  availableNodes: Node[]
  hasValue: boolean
  isConstant: boolean
  isIterationVar: boolean
  isLoopVar: boolean
  iterationNode: Node<CommonNodeType> | null
  loopNode: Node<CommonNodeType> | null
  outputVarNodeId: string
  startNode?: Node | null
  value: ValueSelector | string
}

export const getVarKindOptions = (variableLabel = 'Variable', constantLabel = 'Constant') => ([
  { label: variableLabel, value: 'variable' as VarKindType },
  { label: constantLabel, value: 'constant' as VarKindType },
])

export const getHasValue = (isConstant: boolean, value: ValueSelector | string) =>
  !isConstant && value.length > 0

export const getIsIterationVar = (
  isInIteration: boolean,
  value: ValueSelector | string,
  parentId?: string,
) => {
  if (!isInIteration || !Array.isArray(value))
    return false
  return value[0] === parentId && ['item', 'index'].includes(value[1]!)
}

export const getIsLoopVar = (
  isInLoop: boolean,
  value: ValueSelector | string,
  parentId?: string,
) => {
  if (!isInLoop || !Array.isArray(value))
    return false
  return value[0] === parentId && ['item', 'index'].includes(value[1]!)
}

export const getOutputVarNode = ({
  availableNodes,
  hasValue,
  isConstant,
  isIterationVar,
  isLoopVar,
  iterationNode,
  loopNode,
  outputVarNodeId,
  startNode,
  value,
}: OutputVarNodeParams) => {
  if (!hasValue || isConstant)
    return null

  if (isIterationVar)
    return iterationNode?.data ?? null

  if (isLoopVar)
    return loopNode?.data ?? null

  if (isSystemVar(value as ValueSelector))
    return startNode?.data ?? null

  const node = getNodeInfoById(availableNodes, outputVarNodeId)?.data
  if (!node)
    return null

  return {
    ...node,
    id: outputVarNodeId,
  }
}

export const getVarDisplayName = (
  hasValue: boolean,
  value: ValueSelector | string,
) => {
  if (!hasValue || !Array.isArray(value))
    return ''

  const showName = VAR_SHOW_NAME_MAP[value.join('.')]
  if (showName)
    return showName

  const isSystem = isSystemVar(value)
  const varName = value[value.length - 1] ?? ''
  return `${isSystem ? 'sys.' : ''}${varName}`
}

export const getVariableMeta = (
  outputVarNode: { type?: string } | null,
  value: ValueSelector | string,
  varName: string,
  availableVars: NodeOutPutVar[] = [],
  canValidateSpecialVars = false,
) => {
  const selector = value as ValueSelector
  const isSelectorValue = Array.isArray(selector)
  const isEnv = isSelectorValue && isENV(selector)
  const isChatVar = isSelectorValue && isConversationVar(selector)
  const isGlobal = isSelectorValue && isGlobalVar(selector)
  const isRagVar = isSelectorValue && isRagVariableVar(selector)
  const isSpecialVar = isEnv || isChatVar || isRagVar
  const hasAvailableSpecialVar = !canValidateSpecialVars || !isSelectorValue || availableVars.some(nodeWithVars =>
    nodeWithVars.vars.some(variable => variable.variable === selector.join('.')),
  )
  const isValidVar = Boolean(outputVarNode) || isGlobal || (isSpecialVar && hasAvailableSpecialVar)
  return {
    isChatVar,
    isEnv,
    isGlobal,
    isRagVar,
    isValidVar,
    isException: Boolean(varName && outputVarNode?.type),
  }
}

export const getVariableCategory = ({
  isChatVar,
  isEnv,
  isGlobal,
  isLoopVar,
  isRagVar,
}: VariableCategoryParams) => {
  if (isEnv)
    return 'environment'
  if (isChatVar)
    return 'conversation'
  if (isGlobal)
    return 'global'
  if (isLoopVar)
    return 'loop'
  if (isRagVar)
    return 'rag'
  return 'system'
}

export const getWidthAllocations = (
  triggerWidth: number,
  nodeTitle: string,
  varName: string,
  type: string,
) => {
  const availableWidth = triggerWidth - 56
  const totalTextLength = (nodeTitle + varName + type).length || 1
  const priorityWidth = nodeTitle ? 15 : 0
  const minVarNameWidth = varName ? 16 : 0
  return {
    maxNodeNameWidth: priorityWidth + Math.floor(nodeTitle.length / totalTextLength * availableWidth),
    maxTypeWidth: Math.floor(type.length / totalTextLength * availableWidth),
    maxVarNameWidth: Math.max(
      minVarNameWidth,
      -priorityWidth + Math.floor(varName.length / totalTextLength * availableWidth),
    ),
  }
}

export const getDynamicSelectSchema = ({
  dynamicOptions,
  isLoading,
  schema,
  value,
}: DynamicSchemaParams) => {
  if (schema?.type !== 'dynamic-select')
    return schema

  if (dynamicOptions) {
    return {
      ...schema,
      options: dynamicOptions,
    }
  }

  if (isLoading && value && typeof value === 'string') {
    return {
      ...schema,
      options: [{
        value,
        label: { en_US: value, zh_Hans: value },
        show_on: [],
      }],
    }
  }

  return {
    ...schema,
    options: [],
  }
}

export const getTooltipContent = (
  hasValue: boolean,
  isShowAPart: boolean,
  isValidVar: boolean,
) => {
  if (isValidVar && isShowAPart)
    return 'full-path'
  if (!isValidVar && hasValue)
    return 'invalid-variable'
  return null
}

export const getOutputVarNodeId = (hasValue: boolean, value: ValueSelector | string) =>
  hasValue && Array.isArray(value) ? value[0] : ''

export const isShowAPartSelector = (value: ValueSelector | string) =>
  Array.isArray(value) && value.length > 2 && !isRagVariableVar(value)
