<script lang="ts" setup>
import Utils from '@/common/utils'
import SnConfigApi from '@/pages/sys/sn-config/sn-config-api.ts'
import Strings from '@/common/utils/strings.ts'
import SnConfigUtil from '@/pages/sys/sn-config/sn-config-util.ts'
import {
  PadMode,
  RandomMode,
  Rollback,
  SectionName,
  TimeUnit,
} from '@/pages/sys/sn-config/contant.ts'
import Colls from '@/common/utils/colls.ts'
import { elIcons } from '@/common/element/element.ts'
import ADialog from '@/components/a-dialog/ADialog.vue'

defineOptions({name: 'SnConfigForm'})
const emits = defineEmits([ 'close' ])

const visible = ref(false)
const modify = ref(false)

const snConfig = reactive<SnConfigTypes.SnConfigDetail>({
  id: '',
  snname: '',
  sncode: '',
  example: '',
  config: [],
  memo: '',
})

function clearConfig() {
  snConfig.config = []
}

function onCloseHandler() {
  visible.value = false
  Object.assign(snConfig, {
    id: '',
    snname: '',
    sncode: '',
    example: '',
    config: [],
    memo: '',
  })
}

function checkConfig() {
  const {id, snname, sncode, config} = snConfig
  if (modify.value) {
    if (Strings.isBlank(id)) {
      ElMessage.error('未指定要修改的规则')
      return false
    }
  } else {
    if (Strings.isBlank(snname)) {
      ElMessage.error('请输入规则名称')
      return false
    }
    if (Strings.isBlank(sncode)) {
      ElMessage.error('请输入规则编码')
      return false
    }
  }
  if (Colls.isEmpty(config)) {
    ElMessage.error('请配置规则')
    return false
  }
  return true
}

function processConfig(configs: SnConfigTypes.Section[]): SnConfigTypes.Section[] {
  return configs.map(it => {
    switch (it.sectionName) {
      case 'ShiJian': {
        const {sectionName, timestamp, pattern, unit} = it as SnConfigTypes.TimeSectionConfig
        return {
          sectionName,
          timestamp,
          pattern: timestamp ? undefined : pattern,
          unit: !timestamp ? undefined : unit,
        }
      }
      case 'ZiZeng': {
        const {sectionName, code, step, initialVal, padMode, padVal, padLen, rollback, allowOverflow} = it as SnConfigTypes.IncSectionConfig
        return {
          sectionName, code, step, initialVal, padMode,
          padVal: padMode === 'Wu' ? '' : padVal,
          padLen: padMode === 'Wu' ? 0 : padLen,
          rollback, allowOverflow,
        }
      }
      case 'SuiJi': {
        const {sectionName, randomMode, workerId, datacenterId, nanoIdSize} = it as SnConfigTypes.RandomSectionConfig
        return {
          sectionName, randomMode,
          workerId: randomMode !== 'Snowflake' ? undefined : workerId,
          datacenterId: randomMode !== 'Snowflake' ? undefined : datacenterId,
          nanoIdSize: randomMode !== 'NanoId' ? undefined : nanoIdSize,
        }
      }
      case 'GuDing': {
        const {sectionName, code, value} = it as SnConfigTypes.FixedSectionConfig
        return {
          sectionName, code, value,
        }
      }
      default:
        throw new Error(`不支持的配置项: ${it.sectionName}`)
    }
  })
}

const pici = ref<string>('')
const showPici = computed(() => {
  let show = false
  for (let c of snConfig.config) {
    if (c.sectionName === 'ZiZeng') {
      if ((c as SnConfigTypes.IncSectionConfig).rollback === 'Pi') {
        show = true
        break
      }
    }
  }
  return show
})

function testSn() {
  SnConfigApi.next(snConfig.sncode, Strings.isBlank(pici.value) ? undefined : pici.value)
    .then(res => {
      ElMessage.success(`下一个编码: ${res.data}`)
    })
}

function reset() {
  SnConfigApi.reset(snConfig.sncode)
    .then(() => {
      ElMessage.success('重置成功')
    })
}

function onSaveHandler() {
  if (!checkConfig()) {
    return
  }
  let {id, snname, sncode, config, memo} = Utils.clone(snConfig)
  config = processConfig(config)
  if (modify.value) {
    SnConfigApi.modify({id, snname, sncode, config, memo})
      .then(() => {
        ElMessage.success('保存成功')
        emits('close')
        // onCloseHandler()
      })
  } else {
    SnConfigApi.add({
      snname, sncode, config, memo,
    }).then(() => {
      ElMessage.success('保存成功')
      emits('close')
      // onCloseHandler()
    })
  }
}

function addSection(sectionName: SnConfigTypes.SectionType) {
  const section = SnConfigUtil.createSection(sectionName)
  section.sectionDesc = SnConfigUtil.descSection(section)
  snConfig.config.push(section)
}

function delSection(index: number) {
  snConfig.config.splice(index, 1)
}

function moveUp(index: number) {
  if (index > 0) {
    const section = snConfig.config[index]
    snConfig.config[index] = snConfig.config[index - 1]
    snConfig.config[index - 1] = section
  }
}

function moveDown(index: number) {
  if (index < snConfig.config.length - 1) {
    const section = snConfig.config[index]
    snConfig.config[index] = snConfig.config[index + 1]
    snConfig.config[index + 1] = section
  }
}

defineExpose({
  open(data?: SnConfigTypes.SnConfigDetail) {
    if (data == null) {
      modify.value = false
    } else {
      modify.value = true
      const source = Utils.clone(data)
      Object.assign(snConfig, source)
    }
    visible.value = true
  },
})
</script>

<template>
  <ADialog v-model:show="visible"
    :title="Strings.isBlank(snConfig.id) ? '新增编码配置' : '修改编码配置'" class="config-dialog" footer-class="panel-footer" width="950px"
    :closed="onCloseHandler">
    <div class="config-panel">
      <div class="config-title">
        <div>
          <ElInput v-model="snConfig.snname" clearable placeholder="规则名称"/>
        </div>
        <div>
          <ElInput v-model="snConfig.sncode" clearable placeholder="规则编码"/>
        </div>
        <div>
          <ElInput v-model="snConfig.memo" clearable max-count="128" placeholder="备注" resize="none" showCount type="textarea"/>
        </div>
      </div>
      <div class="config-detail">
        <template v-if="!Colls.isEmpty(snConfig.config)">
          <div v-for="(section, i) in snConfig.config" :key="i">
            <div class="config-tool">
              <div> {{ (i + 1) + '、' + SnConfigUtil.descSection(section) }}</div>
              <div>
                <ElButton :icon="elIcons.Delete" text type="danger" @click.stop="delSection(i)"/>
                <ElTooltip v-if="i > 0" content="上移" placement="top">
                  <ElButton :icon="elIcons.ArrowUp" text type="primary" @click.stop="moveUp(i)"/>
                </ElTooltip>
                <ElTooltip v-if="i < snConfig.config.length - 1" content="下移" placement="top">
                  <ElButton :icon="elIcons.ArrowDown" text type="primary" @click.stop="moveDown(i)"/>
                </ElTooltip>
              </div>
            </div>
            <template v-if="section.sectionName === 'GuDing'">
              <div class="config-item">
                <div>
                  <div>固定值</div>
                  <ElInput v-model="(section as SnConfigTypes.FixedSectionConfig).value" clearable placeholder="请输入"/>
                </div>
              </div>
            </template>
            <template v-if="section.sectionName === 'ShiJian'">
              <div class="config-item">
                <div>
                  <div>使用时间戳</div>
                  <ElSwitch v-model="(section as SnConfigTypes.TimeSectionConfig).timestamp" :labels="['是', '否']"/>
                  <div class="config-item-padding"></div>
                </div>
                <div v-if="(section as SnConfigTypes.TimeSectionConfig).timestamp">
                  <div>时间单位</div>
                  <ElSelect v-model="(section as SnConfigTypes.TimeSectionConfig).unit" clearable placeholder="请选择">
                    <ElOption v-for="(val, key) in TimeUnit" :key="'TimeUnit' + key" :label="val" :value="key"/>
                  </ElSelect>
                </div>
                <div v-else>
                  <div>时间格式</div>
                  <ElInput v-model="(section as SnConfigTypes.TimeSectionConfig).pattern" clearable placeholder="请输入"/>
                </div>
              </div>
            </template>
            <template v-if="section.sectionName === 'ZiZeng'">
              <div class="config-item">
                <div>
                  <div>步长</div>
                  <ElInputNumber v-model="(section as SnConfigTypes.IncSectionConfig).step" clearable placeholder="请输入"/>
                </div>
                <div>
                  <div>初始值</div>
                  <ElInputNumber v-model="(section as SnConfigTypes.IncSectionConfig).initialVal" clearable placeholder="请输入"/>
                </div>
                <div>
                  <div>填充模式</div>
                  <ElSelect v-model="(section as SnConfigTypes.IncSectionConfig).padMode" placeholder="请选择">
                    <ElOption v-for="(val, key) in PadMode" :key="'PadMode' + key" :label="val" :value="key"/>
                  </ElSelect>
                </div>
                <div v-if="(section as SnConfigTypes.IncSectionConfig).padMode !== 'Wu'">
                  <div>填充字符</div>
                  <ElInput v-model="(section as SnConfigTypes.IncSectionConfig).padVal" clearable maxlength="1" minlength="1" placeholder="请输入"/>
                </div>
                <div v-if="(section as SnConfigTypes.IncSectionConfig).padMode !== 'Wu'">
                  <div>填充长度</div>
                  <ElInputNumber v-model="(section as SnConfigTypes.IncSectionConfig).padLen" :max="20" :min="1" clearable placeholder="请输入"/>
                </div>
                <div>
                  <div>回卷模式</div>
                  <ElSelect v-model="(section as SnConfigTypes.IncSectionConfig).rollback" clearable placeholder="请选择">
                    <ElOption v-for="(val, key) in Rollback" :key="'rollback-' + key" :label="val" :value="key"/>
                  </ElSelect>
                </div>
                <div>
                  <div>允许溢出</div>
                  <ElSwitch v-model="(section as SnConfigTypes.IncSectionConfig).allowOverflow" :labels="['是', '否']"/>
                  <div class="config-item-padding"></div>
                </div>
              </div>
            </template>
            <template v-if="section.sectionName === 'SuiJi'">
              <div class="config-item">
                <div>
                  <div>随机模式</div>
                  <ElSelect v-model="(section as SnConfigTypes.RandomSectionConfig).randomMode" clearable placeholder="请选择">
                    <ElOption v-for="(val, key) in RandomMode" :key="'RandomMode' + key" :label="val" :value="key"/>
                  </ElSelect>
                </div>
                <div v-if="(section as SnConfigTypes.RandomSectionConfig).randomMode === 'Snowflake'">
                  <div>工作节点</div>
                  <ElInputNumber v-model="(section as SnConfigTypes.RandomSectionConfig).workerId" clearable placeholder="请输入"/>
                </div>
                <div v-if="(section as SnConfigTypes.RandomSectionConfig).randomMode === 'Snowflake'">
                  <div>数据中心</div>
                  <ElInputNumber v-model="(section as SnConfigTypes.RandomSectionConfig).datacenterId" clearable placeholder="请输入"/>
                </div>
                <div v-if="(section as SnConfigTypes.RandomSectionConfig).randomMode === 'NanoId'">
                  <div>长度</div>
                  <ElInputNumber v-model="(section as SnConfigTypes.RandomSectionConfig).nanoIdSize" clearable placeholder="请输入"/>
                </div>
              </div>
            </template>
          </div>
        </template>
        <ElEmpty v-else description="请添加配置项"/>
      </div>
    </div>
    <template #footer>
      <ElButton type="default" @click="onCloseHandler">关闭</ElButton>
      <ElPopconfirm v-if="snConfig.sncode === 'CS' && showPici" placement="top" title="填写批次" @ok="testSn">
        <ElButton type="danger">测试</ElButton>
        <template #content>
          <ElFormItem compact label="批次" required>
            <ElInput v-model="pici"/>
          </ElFormItem>
        </template>
      </ElPopconfirm>
      <ElButton v-if="snConfig.sncode === 'CS' && !showPici" type="danger" @click="testSn">测试</ElButton>
      <ElButton v-if="snConfig.sncode === 'CS'" type="danger" @click="reset">重置</ElButton>
      <ElPopconfirm :title="'是否清空配置？'" placement="top" @ok.stop="clearConfig">
        <ElButton type="danger">清空配置</ElButton>
      </ElPopconfirm>
      <ElButton type="primary" @click="onSaveHandler">保存</ElButton>
      <ElDropdown :hide-on-click="false" @command="addSection">
        <ElButton type="primary">
          添加配置
        </ElButton>
        <template #dropdown>
          <ElDropdownMenu>
            <ElDropdownItem v-for="(val, key) in SectionName" :key="'SectionName' + key" :command="key">{{ val }}</ElDropdownItem>
          </ElDropdownMenu>
        </template>
      </ElDropdown>
    </template>
  </ADialog>
</template>

<style lang="stylus" scoped>
div {
  box-sizing border-box
}

.config-panel {
  width 100%
  height 500px
  display flex
  justify-content space-between
  box-sizing: border-box;
  padding-bottom: 10px;
  gap: 12px;

  .config-title {
    width: 200px;
    height: 100%;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    gap: 1rem;
    padding 6px

    & > div:nth-child(3) {
      flex 1

      :deep(.el-textarea) {
        height 100%

        textarea {
          height 100%
        }
      }
    }
  }

  .config-detail {
    flex: 1;
    height: 100%;
    display: flex;
    overflow: auto;
    align-items: center;
    flex-direction: column;
    gap 20px
    padding: 6px;

    & > div {
      width 100%;
      display: flex;
      flex-direction: column;
      gap: 10px;
      justify-content: center;
      border: 1px solid #E1E5EB;
      border-radius 2px
    }

    & > :deep(.el-empty) {
      height 100%
    }

    .config-tool {
      display flex
      justify-content space-between
      align-content center
      gap 10px
      padding: 10px 16px;
    }

    .config-item {
      display: flex
      flex-direction: column;
      gap: 1rem;
      border-top: 1px solid #E5E7EB;
      background-color: #F7F9FC;
      padding: 16px;

      & > div {
        display flex
        align-items center
        justify-content space-between

        & > div:first-child {
          width 80px
          flex-shrink 0
        }

        .config-item-padding {
          flex: 1
        }
      }
    }

    :deep(.ix-collapse) {
      width 100%
      height 100%
      overflow auto
    }
  }
}


.dropdown-panel {
  display flex
  flex-direction column
  margin .5rem

  .dropdown-item {
    height 2rem

    &:not(:last-child) {
      border-bottom 1px solid #E5E5E5
    }
  }

}

.config-dialog {

}

</style>
<style lang="stylus">
.panel-footer {
  display: flex;
  justify-content: end;
  align-items: center;
  gap: 10px;

  & > button:nth-child(2) {
    margin 0
  }
}
</style>
