import type { NodeOutPutVar, Var } from '@/app/components/workflow/types'
import { VarType } from '@/app/components/workflow/types'
import {
  filterReferenceVars,
  getValueSelector,
  getVariableCategory,
  getVariableDisplayName,
} from '../var-reference-vars.helpers'

describe('var-reference-vars helpers', () => {
  it('should derive display names for flat and mapped variables', () => {
    expect(getVariableDisplayName('sys.files', false)).toBe('files')
    expect(getVariableDisplayName('current', true, true)).toBe('current_code')
    expect(getVariableDisplayName('foo', true, false)).toBe('foo')
  })

  it('should resolve variable categories', () => {
    expect(getVariableCategory({ isEnv: true, isChatVar: false })).toBe('environment')
    expect(getVariableCategory({ isEnv: false, isChatVar: true })).toBe('conversation')
    expect(getVariableCategory({ isEnv: false, isChatVar: false, isLoopVar: true })).toBe('loop')
    expect(getVariableCategory({ isEnv: false, isChatVar: false, isRagVariable: true })).toBe('rag')
  })

  it('should build selectors by variable scope and file support', () => {
    const itemData: Var = { variable: 'output', type: VarType.string }
    expect(getValueSelector({
      itemData,
      isFlat: true,
      isSupportFileVar: true,
      isFile: false,
      isSys: false,
      isEnv: false,
      isChatVar: false,
      nodeId: 'node-1',
      objPath: [],
    })).toEqual(['output'])

    expect(getValueSelector({
      itemData: { variable: 'env.apiKey', type: VarType.string },
      isFlat: false,
      isSupportFileVar: true,
      isFile: false,
      isSys: false,
      isEnv: true,
      isChatVar: false,
      nodeId: 'node-1',
      objPath: ['parent'],
    })).toEqual(['parent', 'env', 'apiKey'])

    expect(getValueSelector({
      itemData: { variable: 'file', type: VarType.file },
      isFlat: false,
      isSupportFileVar: false,
      isFile: true,
      isSys: false,
      isEnv: false,
      isChatVar: false,
      nodeId: 'node-1',
      objPath: [],
    })).toBeUndefined()
  })

  it('should filter out invalid vars and apply search text', () => {
    const vars = filterReferenceVars([
      {
        title: 'Node A',
        nodeId: 'node-a',
        vars: [
          { variable: 'valid_name', type: VarType.string },
          { variable: 'invalid-key', type: VarType.string },
        ],
      },
      {
        title: 'Node B',
        nodeId: 'node-b',
        vars: [{ variable: 'another_value', type: VarType.string }],
      },
    ] as NodeOutPutVar[], 'another')

    expect(vars).toHaveLength(1)
    expect(vars[0]!.title).toBe('Node B')
    expect(vars[0]!.vars).toEqual([expect.objectContaining({ variable: 'another_value' })])
  })

  it('should keep parent vars when search text matches a child variable', () => {
    const vars = filterReferenceVars([
      {
        title: 'Node A',
        nodeId: 'node-a',
        vars: [{
          variable: 'payload',
          type: VarType.object,
          children: [{ variable: 'child_name', type: VarType.string }],
        }],
      },
      {
        title: 'Node B',
        nodeId: 'node-b',
        vars: [{ variable: 'other_value', type: VarType.string }],
      },
    ] as NodeOutPutVar[], 'child')

    expect(vars).toHaveLength(1)
    expect(vars[0]!.title).toBe('Node A')
    expect(vars[0]!.vars).toEqual([expect.objectContaining({ variable: 'payload' })])
  })
})
