/**
 * DynamicFieldRenderer 组件测试
 *
 * 测试范围:
 * - 基础渲染 (10+用例)
 * - 不同字段类型渲染 (15+用例)
 * - 数据绑定 (10+用例)
 * - 验证功能 (10+用例)
 * - 依赖处理 (5+用例)
 *
 * 总计: 40+ 用例
 */

import { describe, it, expect, vi, beforeEach } from 'vitest'
import { mount, VueWrapper } from '@vue/test-utils'
import { nextTick } from 'vue'
import DynamicFieldRenderer from '@/components/form/DynamicFieldRenderer.vue'
import { FieldConfig, FieldType } from '@/types/form'

describe('DynamicFieldRenderer 组件测试', () => {
  // 测试数据
  const mockFieldConfig: FieldConfig = {
    field_id: 'test_field_1',
    field_name: '测试字段',
    field_type: FieldType.TEXT,
    is_required: true,
    placeholder: '请输入测试字段',
    validation_rules: [
      {
        rule_type: 'length',
        rule_value: { min: 1, max: 100 }
      }
    ]
  }

  const mockModelValue = ref('')

  // 基础渲染测试 (10+用例)
  describe('基础渲染', () => {
    it('应该正确渲染组件', () => {
      const wrapper = mount(DynamicFieldRenderer, {
        props: {
          fieldConfig: mockFieldConfig,
          modelValue: mockModelValue.value
        }
      })
      expect(wrapper.exists()).toBe(true)
    })

    it('应该显示字段标签', () => {
      const wrapper = mount(DynamicFieldRenderer, {
        props: {
          fieldConfig: mockFieldConfig,
          modelValue: ''
        }
      })
      expect(wrapper.text()).toContain('测试字段')
    })

    it('应该显示必填标记', () => {
      const wrapper = mount(DynamicFieldRenderer, {
        props: {
          fieldConfig: mockFieldConfig,
          modelValue: ''
        }
      })
      expect(wrapper.find('.required-mark').exists()).toBe(true)
    })

    it('不应该显示非必填字段的必填标记', () => {
      const config = { ...mockFieldConfig, is_required: false }
      const wrapper = mount(DynamicFieldRenderer, {
        props: {
          fieldConfig: config,
          modelValue: ''
        }
      })
      expect(wrapper.find('.required-mark').exists()).toBe(false)
    })

    it('应该显示字段提示信息', () => {
      const config = {
        ...mockFieldConfig,
        help_text: '这是字段的帮助文本'
      }
      const wrapper = mount(DynamicFieldRenderer, {
        props: {
          fieldConfig: config,
          modelValue: ''
        }
      })
      expect(wrapper.text()).toContain('这是字段的帮助文本')
    })

    it('应该应用自定义CSS类', () => {
      const wrapper = mount(DynamicFieldRenderer, {
        props: {
          fieldConfig: mockFieldConfig,
          modelValue: '',
          customClass: 'custom-field-class'
        }
      })
      expect(wrapper.classes()).toContain('custom-field-class')
    })

    it('应该显示字段描述', () => {
      const config = {
        ...mockFieldConfig,
        description: '字段详细描述'
      }
      const wrapper = mount(DynamicFieldRenderer, {
        props: {
          fieldConfig: config,
          modelValue: ''
        }
      })
      expect(wrapper.text()).toContain('字段详细描述')
    })

    it('应该在禁用状态下渲染', () => {
      const wrapper = mount(DynamicFieldRenderer, {
        props: {
          fieldConfig: mockFieldConfig,
          modelValue: '',
          disabled: true
        }
      })
      const input = wrapper.find('input')
      expect(input.attributes('disabled')).toBeDefined()
    })

    it('应该在只读状态下渲染', () => {
      const wrapper = mount(DynamicFieldRenderer, {
        props: {
          fieldConfig: mockFieldConfig,
          modelValue: 'test value',
          readonly: true
        }
      })
      const input = wrapper.find('input')
      expect(input.attributes('readonly')).toBeDefined()
    })

    it('应该响应字段配置变化', async () => {
      const wrapper = mount(DynamicFieldRenderer, {
        props: {
          fieldConfig: mockFieldConfig,
          modelValue: ''
        }
      })

      await wrapper.setProps({
        fieldConfig: {
          ...mockFieldConfig,
          field_name: '更新后的字段名'
        }
      })

      await nextTick()
      expect(wrapper.text()).toContain('更新后的字段名')
    })
  })

  // 不同字段类型渲染测试 (15+用例)
  describe('不同字段类型渲染', () => {
    it('应该渲染文本输入框', () => {
      const config = { ...mockFieldConfig, field_type: FieldType.TEXT }
      const wrapper = mount(DynamicFieldRenderer, {
        props: {
          fieldConfig: config,
          modelValue: ''
        }
      })
      expect(wrapper.find('input[type="text"]').exists()).toBe(true)
    })

    it('应该渲染数字输入框', () => {
      const config = { ...mockFieldConfig, field_type: FieldType.NUMBER }
      const wrapper = mount(DynamicFieldRenderer, {
        props: {
          fieldConfig: config,
          modelValue: 0
        }
      })
      expect(wrapper.find('input[type="number"]').exists()).toBe(true)
    })

    it('应该渲染日期选择器', () => {
      const config = { ...mockFieldConfig, field_type: FieldType.DATE }
      const wrapper = mount(DynamicFieldRenderer, {
        props: {
          fieldConfig: config,
          modelValue: ''
        }
      })
      expect(wrapper.find('.date-picker').exists()).toBe(true)
    })

    it('应该渲染下拉选择框', () => {
      const config = {
        ...mockFieldConfig,
        field_type: FieldType.SELECT,
        options: [
          { label: '选项1', value: 'option1' },
          { label: '选项2', value: 'option2' }
        ]
      }
      const wrapper = mount(DynamicFieldRenderer, {
        props: {
          fieldConfig: config,
          modelValue: ''
        }
      })
      expect(wrapper.find('select').exists()).toBe(true)
    })

    it('应该渲染多选框', () => {
      const config = {
        ...mockFieldConfig,
        field_type: FieldType.MULTI_SELECT,
        options: [
          { label: '选项1', value: 'option1' },
          { label: '选项2', value: 'option2' }
        ]
      }
      const wrapper = mount(DynamicFieldRenderer, {
        props: {
          fieldConfig: config,
          modelValue: []
        }
      })
      expect(wrapper.find('.multi-select').exists()).toBe(true)
    })

    it('应该渲染单选框组', () => {
      const config = {
        ...mockFieldConfig,
        field_type: FieldType.RADIO,
        options: [
          { label: '选项1', value: 'option1' },
          { label: '选项2', value: 'option2' }
        ]
      }
      const wrapper = mount(DynamicFieldRenderer, {
        props: {
          fieldConfig: config,
          modelValue: ''
        }
      })
      expect(wrapper.find('.radio-group').exists()).toBe(true)
    })

    it('应该渲染复选框', () => {
      const config = { ...mockFieldConfig, field_type: FieldType.CHECKBOX }
      const wrapper = mount(DynamicFieldRenderer, {
        props: {
          fieldConfig: config,
          modelValue: false
        }
      })
      expect(wrapper.find('input[type="checkbox"]').exists()).toBe(true)
    })

    it('应该渲染文本域', () => {
      const config = { ...mockFieldConfig, field_type: FieldType.TEXTAREA }
      const wrapper = mount(DynamicFieldRenderer, {
        props: {
          fieldConfig: config,
          modelValue: ''
        }
      })
      expect(wrapper.find('textarea').exists()).toBe(true)
    })

    it('应该渲染富文本编辑器', () => {
      const config = { ...mockFieldConfig, field_type: FieldType.RICH_TEXT }
      const wrapper = mount(DynamicFieldRenderer, {
        props: {
          fieldConfig: config,
          modelValue: ''
        }
      })
      expect(wrapper.find('.rich-text-editor').exists()).toBe(true)
    })

    it('应该渲染文件上传组件', () => {
      const config = { ...mockFieldConfig, field_type: FieldType.FILE_UPLOAD }
      const wrapper = mount(DynamicFieldRenderer, {
        props: {
          fieldConfig: config,
          modelValue: []
        }
      })
      expect(wrapper.find('.file-upload').exists()).toBe(true)
    })

    it('应该渲染日期时间选择器', () => {
      const config = { ...mockFieldConfig, field_type: FieldType.DATETIME }
      const wrapper = mount(DynamicFieldRenderer, {
        props: {
          fieldConfig: config,
          modelValue: ''
        }
      })
      expect(wrapper.find('.datetime-picker').exists()).toBe(true)
    })

    it('应该渲染时间选择器', () => {
      const config = { ...mockFieldConfig, field_type: FieldType.TIME }
      const wrapper = mount(DynamicFieldRenderer, {
        props: {
          fieldConfig: config,
          modelValue: ''
        }
      })
      expect(wrapper.find('.time-picker').exists()).toBe(true)
    })

    it('应该渲染滑块', () => {
      const config = {
        ...mockFieldConfig,
        field_type: FieldType.SLIDER,
        validation_rules: [
          {
            rule_type: 'range',
            rule_value: { min: 0, max: 100 }
          }
        ]
      }
      const wrapper = mount(DynamicFieldRenderer, {
        props: {
          fieldConfig: config,
          modelValue: 50
        }
      })
      expect(wrapper.find('.slider').exists()).toBe(true)
    })

    it('应该渲染开关', () => {
      const config = { ...mockFieldConfig, field_type: FieldType.SWITCH }
      const wrapper = mount(DynamicFieldRenderer, {
        props: {
          fieldConfig: config,
          modelValue: false
        }
      })
      expect(wrapper.find('.switch').exists()).toBe(true)
    })

    it('应该渲染级联选择器', () => {
      const config = {
        ...mockFieldConfig,
        field_type: FieldType.CASCADER,
        options: [
          {
            label: '级别1',
            value: '1',
            children: [
              { label: '级别2-1', value: '1-1' },
              { label: '级别2-2', value: '1-2' }
            ]
          }
        ]
      }
      const wrapper = mount(DynamicFieldRenderer, {
        props: {
          fieldConfig: config,
          modelValue: []
        }
      })
      expect(wrapper.find('.cascader').exists()).toBe(true)
    })
  })

  // 数据绑定测试 (10+用例)
  describe('数据绑定', () => {
    it('应该正确绑定modelValue', async () => {
      const wrapper = mount(DynamicFieldRenderer, {
        props: {
          fieldConfig: mockFieldConfig,
          modelValue: 'initial value'
        }
      })
      const input = wrapper.find('input')
      expect(input.element.value).toBe('initial value')
    })

    it('应该在输入时触发update:modelValue事件', async () => {
      const wrapper = mount(DynamicFieldRenderer, {
        props: {
          fieldConfig: mockFieldConfig,
          modelValue: ''
        }
      })
      const input = wrapper.find('input')
      await input.setValue('new value')
      expect(wrapper.emitted('update:modelValue')).toBeTruthy()
      expect(wrapper.emitted('update:modelValue')![0]).toEqual(['new value'])
    })

    it('应该响应modelValue的变化', async () => {
      const wrapper = mount(DynamicFieldRenderer, {
        props: {
          fieldConfig: mockFieldConfig,
          modelValue: 'initial'
        }
      })

      await wrapper.setProps({ modelValue: 'updated' })
      await nextTick()

      const input = wrapper.find('input')
      expect(input.element.value).toBe('updated')
    })

    it('应该正确处理数字类型的值', async () => {
      const config = { ...mockFieldConfig, field_type: FieldType.NUMBER }
      const wrapper = mount(DynamicFieldRenderer, {
        props: {
          fieldConfig: config,
          modelValue: 0
        }
      })

      const input = wrapper.find('input')
      await input.setValue('123')
      expect(wrapper.emitted('update:modelValue')![0]).toEqual([123])
    })

    it('应该正确处理布尔类型的值', async () => {
      const config = { ...mockFieldConfig, field_type: FieldType.CHECKBOX }
      const wrapper = mount(DynamicFieldRenderer, {
        props: {
          fieldConfig: config,
          modelValue: false
        }
      })

      const checkbox = wrapper.find('input[type="checkbox"]')
      await checkbox.setChecked()
      expect(wrapper.emitted('update:modelValue')![0]).toEqual([true])
    })

    it('应该正确处理数组类型的值', async () => {
      const config = {
        ...mockFieldConfig,
        field_type: FieldType.MULTI_SELECT,
        options: [
          { label: '选项1', value: 'option1' },
          { label: '选项2', value: 'option2' }
        ]
      }
      const wrapper = mount(DynamicFieldRenderer, {
        props: {
          fieldConfig: config,
          modelValue: []
        }
      })

      // 模拟选择操作
      wrapper.vm.handleSelect('option1')
      await nextTick()

      expect(wrapper.emitted('update:modelValue')).toBeTruthy()
    })

    it('应该正确处理日期类型的值', async () => {
      const config = { ...mockFieldConfig, field_type: FieldType.DATE }
      const dateValue = '2025-01-24'
      const wrapper = mount(DynamicFieldRenderer, {
        props: {
          fieldConfig: config,
          modelValue: ''
        }
      })

      wrapper.vm.handleDateChange(dateValue)
      await nextTick()

      expect(wrapper.emitted('update:modelValue')![0]).toEqual([dateValue])
    })

    it('应该在清空时触发正确的事件', async () => {
      const wrapper = mount(DynamicFieldRenderer, {
        props: {
          fieldConfig: mockFieldConfig,
          modelValue: 'test'
        }
      })

      await wrapper.vm.clearValue()
      expect(wrapper.emitted('update:modelValue')![0]).toEqual([''])
    })

    it('应该正确处理空值', () => {
      const wrapper = mount(DynamicFieldRenderer, {
        props: {
          fieldConfig: mockFieldConfig,
          modelValue: null
        }
      })

      const input = wrapper.find('input')
      expect(input.element.value).toBe('')
    })

    it('应该正确处理未定义的值', () => {
      const wrapper = mount(DynamicFieldRenderer, {
        props: {
          fieldConfig: mockFieldConfig,
          modelValue: undefined
        }
      })

      const input = wrapper.find('input')
      expect(input.element.value).toBe('')
    })
  })

  // 验证功能测试 (10+用例)
  describe('验证功能', () => {
    it('应该验证必填字段', async () => {
      const wrapper = mount(DynamicFieldRenderer, {
        props: {
          fieldConfig: mockFieldConfig,
          modelValue: ''
        }
      })

      const isValid = await wrapper.vm.validate()
      expect(isValid).toBe(false)
    })

    it('应该通过必填字段的验证', async () => {
      const wrapper = mount(DynamicFieldRenderer, {
        props: {
          fieldConfig: mockFieldConfig,
          modelValue: 'test value'
        }
      })

      const isValid = await wrapper.vm.validate()
      expect(isValid).toBe(true)
    })

    it('应该验证最小长度', async () => {
      const config = {
        ...mockFieldConfig,
        validation_rules: [
          {
            rule_type: 'length',
            rule_value: { min: 5, max: 100 }
          }
        ]
      }
      const wrapper = mount(DynamicFieldRenderer, {
        props: {
          fieldConfig: config,
          modelValue: 'abc'
        }
      })

      const isValid = await wrapper.vm.validate()
      expect(isValid).toBe(false)
    })

    it('应该验证最大长度', async () => {
      const config = {
        ...mockFieldConfig,
        validation_rules: [
          {
            rule_type: 'length',
            rule_value: { min: 1, max: 10 }
          }
        ]
      }
      const wrapper = mount(DynamicFieldRenderer, {
        props: {
          fieldConfig: config,
          modelValue: 'a'.repeat(20)
        }
      })

      const isValid = await wrapper.vm.validate()
      expect(isValid).toBe(false)
    })

    it('应该验证数字范围', async () => {
      const config = {
        ...mockFieldConfig,
        field_type: FieldType.NUMBER,
        validation_rules: [
          {
            rule_type: 'range',
            rule_value: { min: 1, max: 100 }
          }
        ]
      }
      const wrapper = mount(DynamicFieldRenderer, {
        props: {
          fieldConfig: config,
          modelValue: 150
        }
      })

      const isValid = await wrapper.vm.validate()
      expect(isValid).toBe(false)
    })

    it('应该验证正则表达式', async () => {
      const config = {
        ...mockFieldConfig,
        validation_rules: [
          {
            rule_type: 'regex',
            rule_value: '^[A-Z0-9]+$'
          }
        ]
      }
      const wrapper = mount(DynamicFieldRenderer, {
        props: {
          fieldConfig: config,
          modelValue: 'invalid-value'
        }
      })

      const isValid = await wrapper.vm.validate()
      expect(isValid).toBe(false)
    })

    it('应该显示验证错误信息', async () => {
      const wrapper = mount(DynamicFieldRenderer, {
        props: {
          fieldConfig: mockFieldConfig,
          modelValue: ''
        }
      })

      await wrapper.vm.validate()
      await nextTick()

      expect(wrapper.find('.error-message').exists()).toBe(true)
      expect(wrapper.text()).toContain('必填')
    })

    it('应该支持自定义验证规则', async () => {
      const customValidator = vi.fn().mockResolvedValue(false)
      const wrapper = mount(DynamicFieldRenderer, {
        props: {
          fieldConfig: mockFieldConfig,
          modelValue: 'test',
          customValidator
        }
      })

      const isValid = await wrapper.vm.validate()
      expect(customValidator).toHaveBeenCalled()
      expect(isValid).toBe(false)
    })

    it('应该在值变化时触发验证', async () => {
      const wrapper = mount(DynamicFieldRenderer, {
        props: {
          fieldConfig: mockFieldConfig,
          modelValue: '',
          validateOnBlur: true
        }
      })

      const input = wrapper.find('input')
      await input.trigger('blur')
      await nextTick()

      expect(wrapper.vm.error).toBeTruthy()
    })

    it('应该清除验证错误', async () => {
      const wrapper = mount(DynamicFieldRenderer, {
        props: {
          fieldConfig: mockFieldConfig,
          modelValue: ''
        }
      })

      await wrapper.vm.validate()
      expect(wrapper.vm.error).toBeTruthy()

      await wrapper.vm.clearError()
      expect(wrapper.vm.error).toBeNull()
    })
  })

  // 依赖处理测试 (5+用例)
  describe('依赖处理', () => {
    it('应该根据依赖条件显示/隐藏字段', async () => {
      const config = {
        ...mockFieldConfig,
        dependencies: [
          {
            field_id: 'parent_field',
            condition: 'equals',
            value: 'show'
          }
        ]
      }
      const wrapper = mount(DynamicFieldRenderer, {
        props: {
          fieldConfig: config,
          modelValue: '',
          formData: { parent_field: 'hide' }
        }
      })

      expect(wrapper.vm.isVisible).toBe(false)

      await wrapper.setProps({
        formData: { parent_field: 'show' }
      })
      await nextTick()

      expect(wrapper.vm.isVisible).toBe(true)
    })

    it('应该根据依赖条件启用/禁用字段', async () => {
      const config = {
        ...mockFieldConfig,
        dependencies: [
          {
            field_id: 'parent_field',
            condition: 'equals',
            value: 'enable',
            action: 'disable'
          }
        ]
      }
      const wrapper = mount(DynamicFieldRenderer, {
        props: {
          fieldConfig: config,
          modelValue: '',
          formData: { parent_field: 'disable' }
        }
      })

      const input = wrapper.find('input')
      expect(input.attributes('disabled')).toBeDefined()
    })

    it('应该根据依赖条件更新字段值', async () => {
      const config = {
        ...mockFieldConfig,
        dependencies: [
          {
            field_id: 'parent_field',
            condition: 'equals',
            value: 'auto',
            action: 'set_value',
            target_value: 'automatic value'
          }
        ]
      }
      const wrapper = mount(DynamicFieldRenderer, {
        props: {
          fieldConfig: config,
          modelValue: '',
          formData: { parent_field: 'auto' }
        }
      })

      await wrapper.vm.handleDependencies()
      expect(wrapper.emitted('update:modelValue')![0]).toEqual(['automatic value'])
    })

    it('应该支持多个依赖条件', async () => {
      const config = {
        ...mockFieldConfig,
        dependencies: [
          {
            field_id: 'field1',
            condition: 'equals',
            value: 'value1'
          },
          {
            field_id: 'field2',
            condition: 'equals',
            value: 'value2',
            operator: 'AND'
          }
        ]
      }
      const wrapper = mount(DynamicFieldRenderer, {
        props: {
          fieldConfig: config,
          modelValue: '',
          formData: { field1: 'value1', field2: 'value2' }
        }
      })

      expect(wrapper.vm.isVisible).toBe(true)
    })

    it('应该处理复杂的依赖逻辑', async () => {
      const config = {
        ...mockFieldConfig,
        dependencies: [
          {
            field_id: 'parent_field',
            condition: 'in',
            value: ['option1', 'option2', 'option3']
          }
        ]
      }
      const wrapper = mount(DynamicFieldRenderer, {
        props: {
          fieldConfig: config,
          modelValue: '',
          formData: { parent_field: 'option2' }
        }
      })

      expect(wrapper.vm.isVisible).toBe(true)
    })
  })
})
