<template>
  <div>
    <el-tabs type="border-card">
      <el-tab-pane label="秒" v-if="shouldHide('second')">
        <CrontabSecond
          @update="updateCrontabValue"
          :check="checkNumber"
          ref="cronsecondRef"
        />
      </el-tab-pane>

      <el-tab-pane label="分钟" v-if="shouldHide('min')">
        <CrontabMin
          @update="updateCrontabValue"
          :check="checkNumber"
          ref="cronminRef"
        />
      </el-tab-pane>

      <el-tab-pane label="小时" v-if="shouldHide('hour')">
        <CrontabHour
          @update="updateCrontabValue"
          :check="checkNumber"
          ref="cronhourRef"
        />
      </el-tab-pane>

      <el-tab-pane label="日" v-if="shouldHide('day')">
        <CrontabDay
          @update="updateCrontabValue"
          :check="checkNumber"
          :cron="crontabValueObj"
          ref="crondayRef"
        />
      </el-tab-pane>

      <el-tab-pane label="月" v-if="shouldHide('month')">
        <CrontabMonth
          @update="updateCrontabValue"
          :check="checkNumber"
          ref="cronmonthRef"
        />
      </el-tab-pane>

      <el-tab-pane label="周" v-if="shouldHide('week')">
        <CrontabWeek
          @update="updateCrontabValue"
          :check="checkNumber"
          :cron="crontabValueObj"
          ref="cronweekRef"
        />
      </el-tab-pane>

      <el-tab-pane label="年" v-if="shouldHide('year')">
        <CrontabYear
          @update="updateCrontabValue"
          :check="checkNumber"
          ref="cronyearRef"
        />
      </el-tab-pane>
    </el-tabs>

    <div class="popup-main">
      <div class="popup-result">
        <p class="title">时间表达式</p>
        <table>
          <thead>
            <th v-for="item of tabTitles" :key="item" width="40">{{ item }}</th>
            <th>Cron 表达式</th>
          </thead>
          <tbody>
            <td><span>{{ crontabValueObj.second }}</span></td>
            <td><span>{{ crontabValueObj.min }}</span></td>
            <td><span>{{ crontabValueObj.hour }}</span></td>
            <td><span>{{ crontabValueObj.day }}</span></td>
            <td><span>{{ crontabValueObj.month }}</span></td>
            <td><span>{{ crontabValueObj.week }}</span></td>
            <td><span>{{ crontabValueObj.year }}</span></td>
            <td><span>{{ crontabValueString }}</span></td>
          </tbody>
        </table>
      </div>
      <CrontabResult :ex="crontabValueString" />

      <div class="pop_btn">
        <el-button size="small" type="primary" @click="submitFill">确定</el-button>
        <el-button size="small" type="warning" @click="clearCron">重置</el-button>
        <el-button size="small" @click="hidePopup">取消</el-button>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, computed, watch, onMounted } from 'vue'
import CrontabSecond from './second.vue'
import CrontabMin from './min.vue'
import CrontabHour from './hour.vue'
import CrontabDay from './day.vue'
import CrontabMonth from './month.vue'
import CrontabWeek from './week.vue'
import CrontabYear from './year.vue'
import CrontabResult from './result.vue'
import type { CrontabValueObj } from '@/types'

interface Props {
  expression?: string
  hideComponent?: string[]
}

const props = withDefaults(defineProps<Props>(), {
  expression: '',
  hideComponent: () => []
})

const emit = defineEmits<{
  hide: []
  fill: [value: string]
}>()

const tabTitles = ['秒', '分钟', '小时', '日', '月', '周', '年']

const crontabValueObj = ref<CrontabValueObj>({
  second: '*',
  min: '*',
  hour: '*',
  day: '*',
  month: '*',
  week: '?',
  year: ''
})

const cronsecondRef = ref<any>(null)
const cronminRef = ref<any>(null)
const cronhourRef = ref<any>(null)
const crondayRef = ref<any>(null)
const cronmonthRef = ref<any>(null)
const cronweekRef = ref<any>(null)
const cronyearRef = ref<any>(null)

const crontabValueString = computed(() => {
  const obj = crontabValueObj.value
  return `${obj.second} ${obj.min} ${obj.hour} ${obj.day} ${obj.month} ${obj.week}${obj.year === '' ? '' : ' ' + obj.year}`
})

function shouldHide(key: string): boolean {
  if (props.hideComponent && props.hideComponent.includes(key)) return false
  return true
}

function checkNumber(value: number, minLimit: number, maxLimit: number): number {
  value = Math.floor(value)
  if (value < minLimit) value = minLimit
  else if (value > maxLimit) value = maxLimit
  return value
}

function updateCrontabValue(name: string, value: string, from?: string) {
  crontabValueObj.value[name as keyof CrontabValueObj] = value
  if (from && from !== name) {
    changeRadio(name, value)
  }
}

function changeRadio(name: string, value: string) {
  const arr = ['second', 'min', 'hour', 'month']
  const refName = 'cron' + name

  const refMap: Record<string, any> = {
    cronsecond: cronsecondRef.value,
    cronmin: cronminRef.value,
    cronhour: cronhourRef.value,
    cronday: crondayRef.value,
    cronmonth: cronmonthRef.value,
    cronweek: cronweekRef.value,
    cronyear: cronyearRef.value
  }

  const compRef = refMap[refName]
  if (!compRef) return

  let insValue = 1

  if (arr.includes(name)) {
    if (value === '*') {
      insValue = 1
    } else if (value.includes('-')) {
      const indexArr = value.split('-')
      compRef.cycle01 = isNaN(Number(indexArr[0])) ? 0 : Number(indexArr[0])
      compRef.cycle02 = Number(indexArr[1])
      insValue = 2
    } else if (value.includes('/')) {
      const indexArr = value.split('/')
      compRef.average01 = isNaN(Number(indexArr[0])) ? 0 : Number(indexArr[0])
      compRef.average02 = Number(indexArr[1])
      insValue = 3
    } else {
      insValue = 4
      compRef.checkboxList = value.split(',').map(Number)
    }
  } else if (name === 'day') {
    if (value === '*') {
      insValue = 1
    } else if (value === '?') {
      insValue = 2
    } else if (value.includes('-')) {
      const indexArr = value.split('-')
      compRef.cycle01 = isNaN(Number(indexArr[0])) ? 0 : Number(indexArr[0])
      compRef.cycle02 = Number(indexArr[1])
      insValue = 3
    } else if (value.includes('/')) {
      const indexArr = value.split('/')
      compRef.average01 = isNaN(Number(indexArr[0])) ? 0 : Number(indexArr[0])
      compRef.average02 = Number(indexArr[1])
      insValue = 4
    } else if (value.includes('W')) {
      const indexArr = value.split('W')
      compRef.workday = isNaN(Number(indexArr[0])) ? 0 : Number(indexArr[0])
      insValue = 5
    } else if (value === 'L') {
      insValue = 6
    } else {
      compRef.checkboxList = value.split(',').map(Number)
      insValue = 7
    }
  } else if (name === 'week') {
    if (value === '*') {
      insValue = 1
    } else if (value === '?') {
      insValue = 2
    } else if (value.includes('-')) {
      const indexArr = value.split('-')
      compRef.cycle01 = isNaN(Number(indexArr[0])) ? 0 : Number(indexArr[0])
      compRef.cycle02 = Number(indexArr[1])
      insValue = 3
    } else if (value.includes('#')) {
      const indexArr = value.split('#')
      compRef.average01 = isNaN(Number(indexArr[0])) ? 1 : Number(indexArr[0])
      compRef.average02 = Number(indexArr[1])
      insValue = 4
    } else if (value.includes('L')) {
      const indexArr = value.split('L')
      compRef.weekday = isNaN(Number(indexArr[0])) ? 1 : Number(indexArr[0])
      insValue = 5
    } else {
      compRef.checkboxList = value.split(',')
      insValue = 6
    }
  } else if (name === 'year') {
    if (value === '') {
      insValue = 1
    } else if (value === '*') {
      insValue = 2
    } else if (value.includes('-')) {
      insValue = 3
    } else if (value.includes('/')) {
      insValue = 4
    } else {
      compRef.checkboxList = value.split(',').map(Number)
      insValue = 5
    }
  }

  compRef.setRadioValue(insValue)
}

function resolveExp() {
  if (props.expression) {
    const arr = props.expression.split(' ')
    if (arr.length >= 6) {
      const obj = {
        second: arr[0],
        min: arr[1],
        hour: arr[2],
        day: arr[3],
        month: arr[4],
        week: arr[5],
        year: arr[6] || ''
      }
      crontabValueObj.value = { ...obj }
      for (const key in obj) {
        if (obj[key as keyof typeof obj]) {
          changeRadio(key, obj[key as keyof typeof obj])
        }
      }
    }
  } else {
    clearCron()
  }
}

function submitFill() {
  emit('fill', crontabValueString.value)
  hidePopup()
}

function clearCron() {
  crontabValueObj.value = {
    second: '*',
    min: '*',
    hour: '*',
    day: '*',
    month: '*',
    week: '?',
    year: ''
  }
  for (const key in crontabValueObj.value) {
    changeRadio(key, crontabValueObj.value[key as keyof CrontabValueObj])
  }
}

function hidePopup() {
  emit('hide')
}

watch(() => props.expression, resolveExp)

onMounted(() => {
  resolveExp()
})
</script>

<style scoped>
.pop_btn {
  text-align: center;
  margin-top: 20px;
}

.popup-main {
  position: relative;
  margin: 10px auto;
  background: #fff;
  border-radius: 5px;
  font-size: 12px;
  overflow: hidden;
}

.popup-result {
  box-sizing: border-box;
  line-height: 24px;
  margin: 25px auto;
  padding: 15px 10px 10px;
  border: 1px solid #ccc;
  position: relative;
}

.popup-result .title {
  position: absolute;
  top: -28px;
  left: 50%;
  width: 140px;
  font-size: 14px;
  margin-left: -70px;
  text-align: center;
  line-height: 30px;
  background: #fff;
}

.popup-result table {
  text-align: center;
  width: 100%;
  margin: 0 auto;
}

.popup-result table span {
  display: block;
  width: 100%;
  font-family: arial;
  line-height: 30px;
  height: 30px;
  white-space: nowrap;
  overflow: hidden;
  border: 1px solid #e8e8e8;
}
</style>
