<template>
  <el-col
    v-if="!schema?.hide && schema.valueType !== 'dependency'"
    :span="componentProps?.span ?? 24"
  >
    <el-form-item
      v-if="isFormItem"
      :prop="schema.field"
      :label="schema?.label"
      :label-width="schema.label ? (schema?.labelWidth ?? '50px') : '0px'"
      :label-position="schema?.labelPosition"
    >
      <!-- 文本 -->
      <el-input
        v-if="schema.valueType === 'text'"
        ref="textInputRef"
        v-model="value"
        spellcheck="false"
        :type="schema?.slots ? 'text' : 'textarea'"
        :rows="1"
        resize="none"
        v-bind="componentProps"
        @focus="syncTextSelection"
        @click="syncTextSelection"
        @keyup="syncTextSelection"
      >
        <template #prefix>
          {{ schema?.slots?.prefix }}
        </template>
        <template #suffix>
          {{ schema?.slots?.suffix }}
        </template>
        <template #append v-if="componentProps?.supportLangues">
          <LuLanguages size="12px" class="cursor-pointer" @click="handleOpenLanguageModal" />
        </template>
      </el-input>
      <!-- 数字 -->
      <input-number
        v-if="schema.valueType === 'number'"
        v-model="value"
        controls-position="right"
        style="width: 100%"
        v-bind="componentProps"
      >
        <template #prefix>
          {{ schema?.slots?.prefix }}
        </template>
        <template #suffix>
          {{ schema?.slots?.suffix }}
        </template>
      </input-number>
      <!-- 选择框 -->
      <el-select-v2
        v-if="schema.valueType === 'select'"
        :options="componentProps?.options || []"
        v-model="value"
        v-bind="componentProps"
      >
        <template #prefix>
          {{ schema?.slots?.prefix }}
        </template>
        <template #suffix>
          {{ schema?.slots?.suffix }}
        </template>
      </el-select-v2>
      <!-- 开关 -->
      <div v-if="schema.valueType === 'switch'" class="w-full flex justify-end">
        <el-switch v-model="value" v-bind="componentProps" />
      </div>

      <!-- 滑动条 -->
      <div v-if="schema.valueType === 'slider'" class="w-full flex gap-20px items-center">
        <el-slider v-model="value" v-bind="componentProps" style="flex: 1"></el-slider>
        <span class="text-text-active inline w-30px cursor-pointer">
          {{ value }}
        </span>
      </div>
      <!-- 文本框 -->
      <CusTextarea v-if="schema.valueType === 'textarea'" v-model="value" v-bind="componentProps" />
      <!-- 图片选择 -->
      <ImageSelect v-if="schema.valueType === 'image'" v-model="value" v-bind="componentProps" />
      <!-- 文件选择 -->
      <FileSelect v-if="schema.valueType === 'file'" v-model="value" v-bind="componentProps" />
      <!-- 图标选择 -->
      <SymbolSelect v-if="schema.valueType === 'symbol'" v-model="value" v-bind="componentProps" />
      <!-- 颜色选择 -->
      <div class="flex" v-if="schema.valueType === 'color'">
        <ColorPicker
          v-model:pureColor="value"
          use-type="pure"
          picker-type="chrome"
          format="hex8"
          v-bind="componentProps"
        />
        <span class="text-text-active">{{ value }}</span>
      </div>

      <!-- 代码 -->
      <div
        v-if="schema.valueType === 'code'"
        class="w-full relative border border-solid border-border rounded-4px overflow-hidden"
      >
        <MonacoEditor v-model="value" v-bind="componentProps" />
      </div>

      <!-- 日期 -->
      <el-date-picker
        v-if="schema.valueType === 'date'"
        v-model="value"
        style="width: 100%"
        v-bind="componentProps"
      />

      <!-- 时间 -->
      <CusTimePicker
        v-if="schema.valueType === 'time'"
        v-model="value"
        style="width: 100%"
        v-bind="componentProps"
      />

      <!-- 字体样式 -->
      <FamilySelect v-if="schema.valueType === 'family'" v-model="value" />
    </el-form-item>

    <!-- 分组 -->
    <el-collapse
      v-if="!isFormItem && !schema?.render && !isStyle && schema.field !== 'part'"
      :model-value="componentProps?.defaultCollapsed ? [] : [key]"
      @change="(val) => emit('changeCollapse', val)"
    >
      <el-collapse-item :title="schema.label" :name="key" style="margin-bottom: 12px">
        <el-card body-class="p-4px! pt-12px!" class="mb-8px!">
          <el-row :gutter="12" class="px-4px">
            <CusFormItem
              v-for="(item, index) in schema.children"
              :key="item.valueType + '_' + index"
              :schema="item"
              :form-data="formData"
            />
            <!-- 平铺多选 -->
            <CusCheckbox
              v-if="schema.valueType === 'checkbox'"
              :options="componentProps?.options"
              v-model="value"
            />
          </el-row>
        </el-card>
      </el-collapse-item>
    </el-collapse>

    <!-- 样式配置 -->
    <el-card
      v-if="isStyle"
      :body-class="value ? 'p-8px!' : 'hidden'"
      :header-class="value ? '' : 'border-b-none!'"
      class="mb-12px"
    >
      <template #header>
        <div class="flex items-center justify-between">
          <span>{{ schema.label }}</span>
          <el-checkbox
            :model-value="!!value"
            @change="(val) => $emit('changeStateStyle', schema?.field!, val ? 'add' : 'delete')"
          />
        </div>
      </template>
      <template v-if="value">
        <!-- 模块 -->
        <!-- <StylePart v-if="schema.valueType === 'part'" v-model="value" /> -->
        <!-- 背景 -->
        <StyleBackground
          v-if="schema.valueType === 'background'"
          v-model="value"
          v-bind="componentProps"
        />
        <!-- 边框 -->
        <StyleBorder v-if="schema.valueType === 'border'" v-model="value" v-bind="componentProps" />
        <!-- 字体 -->
        <StyleFont v-if="schema.valueType === 'font'" v-model="value" v-bind="componentProps" />
        <!-- 外边距 -->
        <StyleMargin v-if="schema.valueType === 'margin'" v-model="value" v-bind="componentProps" />
        <!-- 内边距 -->
        <StylePadding
          v-if="schema.valueType === 'padding'"
          v-model="value"
          v-bind="componentProps"
        />
        <!-- 阴影 -->
        <StyleShadow v-if="schema.valueType === 'shadow'" v-model="value" v-bind="componentProps" />
        <!-- 间距 -->
        <StyleSpace v-if="schema.valueType === 'spacer'" v-model="value" v-bind="componentProps" />
        <!-- 线段  -->
        <StyleLine v-if="schema.valueType === 'line'" v-model="value" v-bind="componentProps" />
        <!-- 外边框 -->
        <StyleOutline
          v-if="schema.valueType === 'outline'"
          v-model="value"
          v-bind="componentProps"
        />
        <!-- 图像样式 -->
        <StyleImage
          v-if="schema.valueType === 'imageStyle'"
          v-model="value"
          v-bind="componentProps"
        />
        <!-- 变换样式 -->
        <StyleTransform
          v-if="schema.valueType === 'transform'"
          v-model="value"
          v-bind="componentProps"
        />
        <!-- 动画样式 -->
        <StyleAnimation
          v-if="schema.valueType === 'animation'"
          v-model="value"
          v-bind="componentProps"
        />
        <!-- 其他 -->
        <StyleOther v-if="schema.valueType === 'other'" v-model="value" v-bind="componentProps" />
      </template>
    </el-card>

    <!-- 自定义渲染 -->
    <component v-if="schema?.render" :is="getComp(schema.render)" />
  </el-col>

  <!-- 依赖项 -->
  <CusFormItem
    v-if="schema.valueType === 'dependency'"
    v-for="(item, index) in dependencyFormItems"
    :key="index"
    :schema="item"
    :form-data="formData"
    @change-state-style="(field, type) => $emit('changeStateStyle', field, type)"
  />
  <LanguageSelectModal ref="languageModalRef" @select="handleSelectLanguage" />
</template>

<script setup lang="tsx">
import type { ComponentSchema } from '@/lvgl-widgets/type'
import type { CollapseModelValue } from 'element-plus'

import { computed, defineComponent, nextTick, ref } from 'vue'
import { get, set } from 'lodash-es'
import { v4 } from 'uuid'

import CusCheckbox from './components/CusCheckbox.vue'
import CusTextarea from './components/CusTextarea.vue'
import CusTimePicker from './components/CusTimePicker.vue'
import ImageSelect from './components/ImageSelect.vue'
import SymbolSelect from './components/SymbolSelect.vue'
import { ColorPicker, MonacoEditor } from '@/components'
import FileSelect from './components/FileSelect.vue'
import FamilySelect from './components/FamilySelect.vue'

import StyleBackground from './components/StyleBackground.vue'
import StyleBorder from './components/StyleBorder.vue'
import StyleFont from './components/StyleFont.vue'
import StyleMargin from './components/StyleMargin.vue'
import StylePadding from './components/StylePadding.vue'
import StyleSpace from './components/StyleSpace.vue'
import StyleShadow from './components/StyleShadow.vue'
// import StylePart from './components/StylePart.vue'
import StyleLine from './components/StyleLine.vue'
import StyleOutline from './components/StyleOutline.vue'
import StyleImage from './components/StyleImage.vue'
import StyleTransform from './components/StyleTransform.vue'
import StyleAnimation from './components/StyleAnimation.vue'
import StyleOther from './components/StyleOther.vue'
import LanguageSelectModal from './components/LanguageSelectModal.vue'
import { LuLanguages } from 'vue-icons-plus/lu'

defineOptions({
  name: 'CusFormItem'
})

const emit = defineEmits<{
  changeStateStyle: [field: string, type: 'add' | 'delete']
  changeCollapse: [value: CollapseModelValue]
}>()

const props = defineProps<{
  schema: ComponentSchema
  formData?: Record<string, any>
  // 控件数据，补充额外数据
  widgetData?: Record<string, any>
}>()
const key = v4()
const textInputRef = ref()
const languageModalRef = ref<InstanceType<typeof LanguageSelectModal>>()
const textSelection = ref({
  start: 0,
  end: 0
})
const componentProps = computed(() => {
  const { onValueChange: _onValueChange, ...rest } = props.schema?.componentProps || {}
  return rest
})

// 绑定数据
const value = computed({
  get() {
    const { schema, formData } = props
    return schema.field ? get(formData, schema.field) : formData
  },
  set(val) {
    const { schema, formData } = props
    if (schema.field && formData) {
      set(formData, schema.field, val)
    }
    // 触发change事件
    if (schema?.componentProps?.onValueChange) {
      schema.componentProps.onValueChange(val, props.formData)
    }
  }
})

const getTextInputElement = () => {
  const inputInstance = textInputRef.value as any
  return inputInstance?.input || inputInstance?.textarea || null
}

const syncTextSelection = () => {
  const inputEl = getTextInputElement()
  if (!inputEl) return

  textSelection.value = {
    start: inputEl.selectionStart ?? 0,
    end: inputEl.selectionEnd ?? inputEl.selectionStart ?? 0
  }
}

const insertLanguageToken = async (languageKey: string) => {
  const token = `#{${languageKey}}`
  const currentValue = String(value.value ?? '')
  const start = textSelection.value.start ?? currentValue.length
  const end = textSelection.value.end ?? start

  value.value = `${currentValue.slice(0, start)}${token}${currentValue.slice(end)}`

  await nextTick()

  const nextPosition = start + token.length
  const inputEl = getTextInputElement()
  inputEl?.focus?.()
  inputEl?.setSelectionRange?.(nextPosition, nextPosition)
  textSelection.value = {
    start: nextPosition,
    end: nextPosition
  }
}

const handleOpenLanguageModal = () => {
  syncTextSelection()
  languageModalRef.value?.open()
}

const handleSelectLanguage = (languageKey: string) => {
  if (!languageKey) return

  insertLanguageToken(languageKey)
}

/**
 * 使用表单组件渲染表单项
 */
const isFormItem = computed(() => {
  // 排除类型
  const exclude: string[] = [
    'group',
    'checkbox',
    'part',
    'background',
    'font',
    'border',
    'shadow',
    'spacer',
    'padding',
    'margin',
    'line',
    'imageStyle',
    'transform',
    'outline',
    'animation',
    'other'
  ]
  // 排除字段
  const excludeFields: string[] = []

  return (
    !exclude.includes(props.schema.valueType) &&
    !excludeFields.includes(props.schema.type) &&
    !props.schema?.render
  )
})

/**
 * 样式配置
 */
const isStyle = computed(() => {
  // 包含类型
  const include: string[] = [
    'background',
    'font',
    'border',
    'shadow',
    'spacer',
    'padding',
    'margin',
    'line',
    'outline',
    'imageStyle',
    'transform',
    'animation',
    'other'
  ]

  return include.includes(props.schema.valueType) && !props.schema?.render
})

/**
 * 自定义渲染
 */
const getComp = (fun: any) => {
  return defineComponent({
    render: () => {
      return <>{fun?.(value)}</>
    }
  })
}

/**
 * 依赖项
 * 1. 根据依赖性的name获取对应值
 * 2. 根据值获取对应的表单项
 */
const dependencyFormItems = computed(() => {
  const { schema, formData, widgetData } = props
  if (schema.valueType === 'dependency') {
    const values: { [key: string]: any } = {}
    schema?.name?.forEach((key) => {
      const val = get(formData, key) ?? get(widgetData, key)
      values[key] = val
    })
    const result = schema.dependency(values) || []
    return Array.isArray(result) ? result : [result]
  }
  return []
})
</script>

<style lang="less" scoped>
::v-deep(.el-collapse-icon-position-right .el-collapse-item__header) {
  padding: 0 !important;
  box-sizing: border-box;
}
::v-deep(.el-card__header) {
  padding: 4px 12px;
}
.el-collapse {
  border-bottom: none !important;
}
.el-form-item {
  margin-bottom: 8px;
}
</style>
