<template>
  <div class="variable-bind-wrapper">
    <div v-if="!isBound" class="input-container">
      <slot></slot>
    </div>

    <el-popover v-if="canBindVariable" ref="popoverRef" placement="right" trigger="click">
      <template #reference>
        <div
          class="cursor-pointer"
          :class="[
            isBound ? 'active w-full flex items-center' : '',
            isGlobalBound ? 'global-bound' : ''
          ]"
        >
          <TbVariable :size="14" class="shrink-0" style="margin-top: 0.2em" />
          <span v-if="isBound" class="ml-4px flex-1 truncate">{{ boundVariableName }}</span>
        </div>
      </template>
      <div class="flex-col">
        <el-button
          v-if="!isBound"
          class="w-full mb-12px"
          size="small"
          type="primary"
          @click="addPageVariables"
          ><LuPlus size="12" /> 添加变量</el-button
        >
        <el-button
          v-if="!isBound"
          class="w-full ml-0!"
          size="small"
          type="primary"
          @click="handleOpenVariableSelector"
          ><LuLink size="12" /> 绑定变量</el-button
        >
        <el-button
          v-if="isBound"
          class="w-full ml-0!"
          size="small"
          type="primary"
          @click="handleUnbindVariable"
          ><LuUnlink size="12" /> 解绑变量</el-button
        >
      </div>
    </el-popover>
  </div>

  <!-- 变量选择弹窗 -->
  <VariableSelectorDialog
    v-model="showVariableSelector"
    :all-variables="
      getAllVariables(projectStore.project?.variables || [], projectStore.activePage?.variables)
    "
    :current-var-id="currentBoundVarId"
    :support-type="variableConfig?.type"
    @confirm="handleVariableBindConfirm"
    @cancel="showVariableSelector = false"
  />
</template>

<script setup lang="ts">
import { computed, ref } from 'vue'
import { ElMessageBox, ElMessage } from 'element-plus'
import {
  isVariableBound,
  findVariableById,
  getAllVariables,
  bindVariableToProperty
} from '@/utils/variableBinding'
import { useProjectStore } from '@/store/modules/project'
import { LuPlus, LuLink, LuUnlink } from 'vue-icons-plus/lu'
import { v4 } from 'uuid'
import { TbVariable } from 'vue-icons-plus/tb'
import VariableSelectorDialog from './VariableSelectorDialog.vue'

import type { Variable, VariableType } from '@/types/variables'
import type { PopoverInstance } from 'element-plus'

const props = withDefaults(
  defineProps<{
    /**
     * 是否允许绑定变量
     */
    canBindVariable?: boolean
    /**
     * 变量配置
     */
    variableConfig?: {
      type: VariableType
      enumMap?: Record<number, string>
    }
  }>(),
  {
    canBindVariable: true
  }
)

const modelValue = defineModel<any>()

const projectStore = useProjectStore()

const popoverRef = ref<PopoverInstance>()
const showVariableSelector = ref(false)

const isBound = computed(() => {
  return isVariableBound(modelValue.value)
})

const boundVariableName = computed(() => {
  if (!isBound.value) return ''

  const allVars = getAllVariables(
    projectStore.project?.variables || [],
    projectStore.activePage?.variables
  )

  const variable = findVariableById(modelValue.value?.varId, allVars)
  return variable?.name || ''
})

const isGlobalBound = computed(() => {
  return isBound.value && modelValue.value?.source === 'global'
})

/**
 * 添加页面变量
 */
const addPageVariables = () => {
  // 1、打开弹窗输入变量名称
  // 2、从variableConfig.type获取变量类型，variableConfig.enumMap获取枚举选项（如果是枚举类型），将这些信息传递给弹窗
  // 3、从modelValue获取当前值，作为变量的初始值
  // 4、用户确认后创建变量到页面变量，并自动绑定
  popoverRef.value?.hide()

  ElMessageBox.prompt('请输入变量名称', '提示', {
    confirmButtonText: '确认',
    cancelButtonText: '取消',
    // C语言变量命名规则：只能包含字母、数字和下划线，且必须以字母或下划线开头
    inputPattern: /^[a-zA-Z_][a-zA-Z0-9_]*$/,
    inputErrorMessage: '变量名称只能包含字母、数字和下划线，且必须以字母或下划线开头'
  })
    .then(({ value }) => {
      let val = modelValue.value
      // 如果是枚举
      if (props.variableConfig?.type === 'enum' && props.variableConfig.enumMap) {
        // 尝试将当前值转换为枚举的key
        const enumKey = Object.keys(props.variableConfig.enumMap).find(
          (key) => props.variableConfig?.enumMap?.[key] === modelValue.value
        )
        val = enumKey ?? val
      }

      const newVar: Variable = {
        id: v4(),
        name: value,
        type: props.variableConfig?.type as VariableType,
        value: val
      }
      console.log(newVar)
      projectStore.activePage?.variables?.push(newVar)
      modelValue.value = {
        varId: newVar.id,
        originValue: val,
        source: 'page',
        ...(props.variableConfig?.type === 'enum' && props.variableConfig.enumMap
          ? { enumMap: props.variableConfig.enumMap }
          : {})
      }
    })
    .catch(() => {
      ElMessage({
        message: '取消添加'
      })
    })
}

/**当前变量绑定的变量id */
const currentBoundVarId = computed(() => {
  const currentValue = modelValue.value
  return currentValue && typeof currentValue === 'object' && currentValue.varId
    ? currentValue.varId
    : ''
})

/**
 * 变量选择确认后的处理
 * @param varId
 */
const handleVariableBindConfirm = (varId: string, source: 'page' | 'global') => {
  const boundValue = bindVariableToProperty(
    modelValue.value,
    varId,
    source,
    props.variableConfig?.type === 'enum' ? props.variableConfig.enumMap : undefined
  )
  modelValue.value = boundValue
  showVariableSelector.value = false
}

/**
 * 解绑变量
 */
const handleUnbindVariable = () => {
  const currentValue = modelValue.value
  if (currentValue && typeof currentValue === 'object' && currentValue.varId) {
    modelValue.value = currentValue.originValue
  }
}

/**
 * 打开变量选择器
 */
const handleOpenVariableSelector = () => {
  showVariableSelector.value = true
}
</script>

<style scoped lang="less">
.variable-bind-wrapper {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;

  .input-container {
    flex: 1;
    min-width: 0;
  }

  .active {
    color: var(--accent-blue);
    font-size: 14px;
  }

  .global-bound {
    color: var(--el-color-success);
  }
}
</style>
