import type { PromptVariable } from '@/models/debug'
import type { UserInputFormItem } from '@/types/app'
import { SupportUploadFileTypes } from '@/app/components/workflow/types'
/**
 * Test suite for model configuration transformation utilities
 *
 * This module handles the conversion between two different representations of user input forms:
 * 1. UserInputFormItem: The form structure used in the UI
 * 2. PromptVariable: The variable structure used in prompts and model configuration
 *
 * Key functions:
 * - userInputsFormToPromptVariables: Converts UI form items to prompt variables
 * - promptVariablesToUserInputsForm: Converts prompt variables back to form items
 * - formatBooleanInputs: Ensures boolean inputs are properly typed
 */
import {
  formatBooleanInputs,
  promptVariablesToUserInputsForm,
  userInputsFormToPromptVariables,
} from './model-config'

const getTextInput = (item: UserInputFormItem | undefined) => {
  if (!item || !('text-input' in item)) throw new Error('Expected text-input user input form item')

  return item['text-input']
}

const getSelectInput = (item: UserInputFormItem | undefined) => {
  if (!item || !('select' in item)) throw new Error('Expected select user input form item')

  return item.select
}

describe('Model Config Utilities', () => {
  describe('userInputsFormToPromptVariables', () => {
    /**
     * Test handling of null or undefined input
     * Should return empty array when no inputs provided
     */
    it('should return empty array for null input', () => {
      const result = userInputsFormToPromptVariables(null)
      expect(result).toEqual([])
    })

    /**
     * Test conversion of text-input (string) type
     * Text inputs are the most common form field type
     */
    it('should convert text-input to string prompt variable', () => {
      const userInputs: UserInputFormItem[] = [
        {
          'text-input': {
            label: 'User Name',
            variable: 'user_name',
            required: true,
            max_length: 100,
            default: '',
            hide: false,
          },
        },
      ]

      const result = userInputsFormToPromptVariables(userInputs)

      expect(result).toHaveLength(1)
      expect(result[0]).toEqual({
        key: 'user_name',
        name: 'User Name',
        required: true,
        type: 'string',
        max_length: 100,
        options: [],
        is_context_var: false,
        hide: false,
        default: '',
      })
    })

    /**
     * Test conversion of paragraph type
     * Paragraphs are multi-line text inputs
     */
    it('should convert paragraph to paragraph prompt variable', () => {
      const userInputs: UserInputFormItem[] = [
        {
          paragraph: {
            label: 'Description',
            variable: 'description',
            required: false,
            max_length: 500,
            default: '',
            hide: false,
          },
        },
      ]

      const result = userInputsFormToPromptVariables(userInputs)

      expect(result[0]).toEqual({
        key: 'description',
        name: 'Description',
        required: false,
        type: 'paragraph',
        max_length: 500,
        options: [],
        is_context_var: false,
        hide: false,
        default: '',
      })
    })

    /**
     * Test conversion of number type
     * Number inputs should preserve numeric constraints
     */
    it('should convert number input to number prompt variable', () => {
      const userInputs: UserInputFormItem[] = [
        {
          number: {
            label: 'Age',
            variable: 'age',
            required: true,
            default: '',
            hide: false,
          },
        },
      ]

      const result = userInputsFormToPromptVariables(userInputs)

      expect(result[0]).toEqual({
        key: 'age',
        name: 'Age',
        required: true,
        type: 'number',
        options: [],
        hide: false,
        default: '',
      })
    })

    /**
     * Test conversion of checkbox (boolean) type
     * Checkboxes are converted to 'checkbox' type in prompt variables
     */
    it('should convert checkbox to checkbox prompt variable', () => {
      const userInputs: UserInputFormItem[] = [
        {
          checkbox: {
            label: 'Accept Terms',
            variable: 'accept_terms',
            required: true,
            default: '',
            hide: false,
          },
        },
      ]

      const result = userInputsFormToPromptVariables(userInputs)

      expect(result[0]).toEqual({
        key: 'accept_terms',
        name: 'Accept Terms',
        required: true,
        type: 'checkbox',
        options: [],
        hide: false,
        default: '',
      })
    })

    /**
     * Test conversion of select (dropdown) type
     * Select inputs include options array
     */
    it('should convert select input to select prompt variable', () => {
      const userInputs: UserInputFormItem[] = [
        {
          select: {
            label: 'Country',
            variable: 'country',
            required: true,
            options: ['USA', 'Canada', 'Mexico'],
            default: 'USA',
            hide: false,
          },
        },
      ]

      const result = userInputsFormToPromptVariables(userInputs)

      expect(result[0]).toEqual({
        key: 'country',
        name: 'Country',
        required: true,
        type: 'select',
        options: ['USA', 'Canada', 'Mexico'],
        is_context_var: false,
        hide: false,
        default: 'USA',
      })
    })

    /**
     * Test conversion of file upload type
     * File inputs include configuration for allowed types and upload methods
     */
    it('should convert file input to file prompt variable', () => {
      const userInputs: UserInputFormItem[] = [
        {
          file: {
            label: 'Profile Picture',
            variable: 'profile_pic',
            required: false,
            allowed_file_types: [SupportUploadFileTypes.image],
            allowed_file_extensions: ['.jpg', '.png'],
            allowed_file_upload_methods: ['local_file', 'remote_url'],
            default: '',
            hide: false,
          },
        },
      ]

      const result = userInputsFormToPromptVariables(userInputs)

      expect(result[0]).toEqual({
        key: 'profile_pic',
        name: 'Profile Picture',
        required: false,
        type: 'file',
        config: {
          allowed_file_types: ['image'],
          allowed_file_extensions: ['.jpg', '.png'],
          allowed_file_upload_methods: ['local_file', 'remote_url'],
          number_limits: 1,
        },
        hide: false,
        default: '',
      })
    })

    /**
     * Test conversion of file-list type
     * File lists allow multiple file uploads with a max_length constraint
     */
    it('should convert file-list input to file-list prompt variable', () => {
      const userInputs: UserInputFormItem[] = [
        {
          'file-list': {
            label: 'Documents',
            variable: 'documents',
            required: true,
            allowed_file_types: [SupportUploadFileTypes.document],
            allowed_file_extensions: ['.pdf', '.docx'],
            allowed_file_upload_methods: ['local_file'],
            max_length: 5,
            default: '',
            hide: false,
          },
        },
      ]

      const result = userInputsFormToPromptVariables(userInputs)

      expect(result[0]).toEqual({
        key: 'documents',
        name: 'Documents',
        required: true,
        type: 'file-list',
        config: {
          allowed_file_types: ['document'],
          allowed_file_extensions: ['.pdf', '.docx'],
          allowed_file_upload_methods: ['local_file'],
          number_limits: 5,
        },
        hide: false,
        default: '',
      })
    })

    /**
     * Test conversion of external_data_tool type
     * External data tools have custom configuration and icons
     */
    it('should convert external_data_tool to prompt variable', () => {
      const userInputs: UserInputFormItem[] = [
        {
          external_data_tool: {
            label: 'API Data',
            variable: 'api_data',
            type: 'api',
            enabled: true,
            required: false,
            config: { endpoint: 'https://api.example.com' },
            icon: 'api-icon',
            icon_background: '#FF5733',
            hide: false,
          },
        },
      ]

      const result = userInputsFormToPromptVariables(userInputs)

      expect(result[0]).toEqual({
        key: 'api_data',
        name: 'API Data',
        required: false,
        type: 'api',
        enabled: true,
        config: { endpoint: 'https://api.example.com' },
        icon: 'api-icon',
        icon_background: '#FF5733',
        is_context_var: false,
        hide: false,
      })
    })

    /**
     * Test handling of dataset_query_variable
     * When a variable matches the dataset_query_variable, is_context_var should be true
     */
    it('should mark variable as context var when matching dataset_query_variable', () => {
      const userInputs: UserInputFormItem[] = [
        {
          'text-input': {
            label: 'Query',
            variable: 'query',
            required: true,
            max_length: 200,
            default: '',
            hide: false,
          },
        },
      ]

      const result = userInputsFormToPromptVariables(userInputs, 'query')

      expect(result[0]!.is_context_var).toBe(true)
    })

    /**
     * Test conversion of multiple mixed input types
     * Should handle an array with different input types correctly
     */
    it('should convert multiple mixed input types', () => {
      const userInputs: UserInputFormItem[] = [
        {
          'text-input': {
            label: 'Name',
            variable: 'name',
            required: true,
            max_length: 50,
            default: '',
            hide: false,
          },
        },
        {
          number: {
            label: 'Age',
            variable: 'age',
            required: false,
            default: '',
            hide: false,
          },
        },
        {
          select: {
            label: 'Gender',
            variable: 'gender',
            required: true,
            options: ['Male', 'Female', 'Other'],
            default: '',
            hide: false,
          },
        },
      ]

      const result = userInputsFormToPromptVariables(userInputs)

      expect(result).toHaveLength(3)
      expect(result[0]!.type).toBe('string')
      expect(result[1]!.type).toBe('number')
      expect(result[2]!.type).toBe('select')
    })
  })

  describe('promptVariablesToUserInputsForm', () => {
    /**
     * Test conversion of string prompt variable back to text-input
     */
    it('should convert string prompt variable to text-input', () => {
      const promptVariables: PromptVariable[] = [
        {
          key: 'user_name',
          name: 'User Name',
          required: true,
          type: 'string',
          max_length: 100,
          options: [],
        },
      ]

      const result = promptVariablesToUserInputsForm(promptVariables)

      expect(result).toHaveLength(1)
      expect(result[0]).toEqual({
        'text-input': {
          label: 'User Name',
          variable: 'user_name',
          required: true,
          max_length: 100,
          default: '',
          hide: undefined,
        },
      })
    })

    /**
     * Test conversion of paragraph prompt variable
     */
    it('should convert paragraph prompt variable to paragraph input', () => {
      const promptVariables: PromptVariable[] = [
        {
          key: 'description',
          name: 'Description',
          required: false,
          type: 'paragraph',
          max_length: 500,
          options: [],
        },
      ]

      const result = promptVariablesToUserInputsForm(promptVariables)

      expect(result[0]).toEqual({
        paragraph: {
          label: 'Description',
          variable: 'description',
          required: false,
          max_length: 500,
          default: '',
          hide: undefined,
        },
      })
    })

    /**
     * Test conversion of number prompt variable
     */
    it('should convert number prompt variable to number input', () => {
      const promptVariables: PromptVariable[] = [
        {
          key: 'age',
          name: 'Age',
          required: true,
          type: 'number',
          options: [],
        },
      ]

      const result = promptVariablesToUserInputsForm(promptVariables)

      expect(result[0]).toEqual({
        number: {
          label: 'Age',
          variable: 'age',
          required: true,
          default: '',
          hide: undefined,
        },
      })
    })

    /**
     * Test conversion of checkbox prompt variable
     */
    it('should convert checkbox prompt variable to checkbox input', () => {
      const promptVariables: PromptVariable[] = [
        {
          key: 'accept_terms',
          name: 'Accept Terms',
          required: true,
          type: 'checkbox',
          options: [],
        },
      ]

      const result = promptVariablesToUserInputsForm(promptVariables)

      expect(result[0]).toEqual({
        checkbox: {
          label: 'Accept Terms',
          variable: 'accept_terms',
          required: true,
          default: '',
          hide: undefined,
        },
      })
    })

    /**
     * Test conversion of select prompt variable
     */
    it('should convert select prompt variable to select input', () => {
      const promptVariables: PromptVariable[] = [
        {
          key: 'country',
          name: 'Country',
          required: true,
          type: 'select',
          options: ['USA', 'Canada', 'Mexico'],
          default: 'USA',
        },
      ]

      const result = promptVariablesToUserInputsForm(promptVariables)

      expect(result[0]).toEqual({
        select: {
          label: 'Country',
          variable: 'country',
          required: true,
          options: ['USA', 'Canada', 'Mexico'],
          default: 'USA',
          hide: undefined,
        },
      })
    })

    /**
     * Test filtering of invalid prompt variables
     * Variables without key or name should be filtered out
     */
    it('should filter out variables with empty key or name', () => {
      const promptVariables: PromptVariable[] = [
        {
          key: '',
          name: 'Empty Key',
          required: true,
          type: 'string',
          options: [],
        },
        {
          key: 'valid',
          name: '',
          required: true,
          type: 'string',
          options: [],
        },
        {
          key: '  ',
          name: 'Whitespace Key',
          required: true,
          type: 'string',
          options: [],
        },
        {
          key: 'valid_key',
          name: 'Valid Name',
          required: true,
          type: 'string',
          options: [],
        },
      ]

      const result = promptVariablesToUserInputsForm(promptVariables)

      expect(result).toHaveLength(1)
      expect(getTextInput(result[0]).variable).toBe('valid_key')
    })

    /**
     * Test conversion of external data tool prompt variable
     */
    it('should convert external data tool prompt variable', () => {
      const promptVariables: PromptVariable[] = [
        {
          key: 'api_data',
          name: 'API Data',
          required: false,
          type: 'api',
          enabled: true,
          config: { endpoint: 'https://api.example.com' },
          icon: 'api-icon',
          icon_background: '#FF5733',
        },
      ]

      const result = promptVariablesToUserInputsForm(promptVariables)

      expect(result[0]).toEqual({
        external_data_tool: {
          label: 'API Data',
          variable: 'api_data',
          enabled: true,
          type: 'api',
          config: { endpoint: 'https://api.example.com' },
          required: false,
          icon: 'api-icon',
          icon_background: '#FF5733',
          hide: undefined,
        },
      })
    })

    /**
     * Test that required defaults to true when not explicitly set to false
     */
    it('should default required to true when not false', () => {
      const promptVariables: PromptVariable[] = [
        {
          key: 'test1',
          name: 'Test 1',
          required: undefined,
          type: 'string',
          options: [],
        },
        {
          key: 'test2',
          name: 'Test 2',
          required: false,
          type: 'string',
          options: [],
        },
      ]

      const result = promptVariablesToUserInputsForm(promptVariables)

      expect(getTextInput(result[0]).required).toBe(true)
      expect(getTextInput(result[1]).required).toBe(false)
    })
  })

  describe('formatBooleanInputs', () => {
    /**
     * Test that null or undefined inputs are handled gracefully
     */
    it('should return inputs unchanged when useInputs is null', () => {
      const inputs = { key1: 'value1', key2: 'value2' }
      const result = formatBooleanInputs(null, inputs)
      expect(result).toEqual(inputs)
    })

    it('should return inputs unchanged when useInputs is undefined', () => {
      const inputs = { key1: 'value1', key2: 'value2' }
      const result = formatBooleanInputs(undefined, inputs)
      expect(result).toEqual(inputs)
    })

    /**
     * Test conversion of boolean input values to actual boolean type
     * This is important for proper type handling in the backend
     * Note: checkbox inputs are converted to type 'checkbox' by userInputsFormToPromptVariables
     */
    it('should convert boolean inputs to boolean type', () => {
      const useInputs: PromptVariable[] = [
        {
          key: 'accept_terms',
          name: 'Accept Terms',
          required: true,
          type: 'checkbox',
          options: [],
        },
        {
          key: 'subscribe',
          name: 'Subscribe',
          required: false,
          type: 'checkbox',
          options: [],
        },
      ]

      const inputs = {
        accept_terms: 'true',
        subscribe: '',
        other_field: 'value',
      }

      const result = formatBooleanInputs(useInputs, inputs)

      expect(result).toEqual({
        accept_terms: true,
        subscribe: false,
        other_field: 'value',
      })
    })

    /**
     * Test that non-boolean inputs are not affected
     */
    it('should not modify non-boolean inputs', () => {
      const useInputs: PromptVariable[] = [
        {
          key: 'name',
          name: 'Name',
          required: true,
          type: 'string',
          options: [],
        },
        {
          key: 'age',
          name: 'Age',
          required: true,
          type: 'number',
          options: [],
        },
      ]

      const inputs = {
        name: 'John Doe',
        age: 30,
      }

      const result = formatBooleanInputs(useInputs, inputs)

      expect(result).toEqual(inputs)
    })

    /**
     * Test handling of truthy and falsy values for boolean conversion
     * Note: checkbox inputs are converted to type 'checkbox' by userInputsFormToPromptVariables
     */
    it('should handle various truthy and falsy values', () => {
      const useInputs: PromptVariable[] = [
        {
          key: 'bool1',
          name: 'Bool 1',
          required: true,
          type: 'checkbox',
          options: [],
        },
        {
          key: 'bool2',
          name: 'Bool 2',
          required: true,
          type: 'checkbox',
          options: [],
        },
        {
          key: 'bool3',
          name: 'Bool 3',
          required: true,
          type: 'checkbox',
          options: [],
        },
        {
          key: 'bool4',
          name: 'Bool 4',
          required: true,
          type: 'checkbox',
          options: [],
        },
      ]

      const inputs = {
        bool1: 1,
        bool2: 0,
        bool3: 'yes',
        bool4: null,
      }

      const result = formatBooleanInputs(useInputs, inputs)

      expect(result?.bool1).toBe(true)
      expect(result?.bool2).toBe(false)
      expect(result?.bool3).toBe(true)
      expect(result?.bool4).toBe(false)
    })

    /**
     * Test that the function creates a new object and doesn't mutate the original
     * Note: checkbox inputs are converted to type 'checkbox' by userInputsFormToPromptVariables
     */
    it('should not mutate original inputs object', () => {
      const useInputs: PromptVariable[] = [
        {
          key: 'flag',
          name: 'Flag',
          required: true,
          type: 'checkbox',
          options: [],
        },
      ]

      const inputs = { flag: 'true', other: 'value' }
      const originalInputs = { ...inputs }

      formatBooleanInputs(useInputs, inputs)

      expect(inputs).toEqual(originalInputs)
    })
  })

  describe('Round-trip conversion', () => {
    /**
     * Test that converting from UserInputForm to PromptVariable and back
     * preserves the essential data (though some fields may have defaults applied)
     */
    it('should preserve data through round-trip conversion', () => {
      const originalUserInputs: UserInputFormItem[] = [
        {
          'text-input': {
            label: 'Name',
            variable: 'name',
            required: true,
            max_length: 50,
            default: '',
            hide: false,
          },
        },
        {
          select: {
            label: 'Type',
            variable: 'type',
            required: false,
            options: ['A', 'B', 'C'],
            default: 'A',
            hide: false,
          },
        },
      ]

      const promptVars = userInputsFormToPromptVariables(originalUserInputs)
      const backToUserInputs = promptVariablesToUserInputsForm(promptVars)

      expect(backToUserInputs).toHaveLength(2)
      expect(getTextInput(backToUserInputs[0]).variable).toBe('name')
      expect(getSelectInput(backToUserInputs[1]).variable).toBe('type')
      expect(getSelectInput(backToUserInputs[1]).options).toEqual(['A', 'B', 'C'])
    })
  })
})
