<template>
	<div style="width: 100%;">
		<el-input v-model="value">
			<template #suffix>
				<el-icon size="15" @click="showPick">
					<component :is="'pi-icon-choice'"/>
				</el-icon>
			</template>
		</el-input>
	</div>
	<pi-dialog title="Cron 表达式生成器" v-model="visible" :width="800" destroy-on-close @closed="visible=false">
		<el-form :model="form" label-width="120px">
			<el-form-item label="类型" prop="type">
				<el-select v-model="form.type" placeholder="请选择" @change="generateCron">
					<el-option label="每 N 秒" value="every_n_seconds"/>
					<el-option label="每 N 分钟" value="every_n_minutes"/>
					<el-option label="每天在指定时间" value="daily_at"/>
					<el-option label="每周在指定星期和时间" value="weekly_at"/>
					<el-option label="每月在指定日和时间" value="monthly_at"/>
					<el-option label="自定义表达式" value="custom"/>
				</el-select>
			</el-form-item>
			<el-form-item label="间隔 (秒)" v-if="form.type === 'every_n_seconds'" prop="everySeconds">
				<el-input-number v-model="form.everySeconds" :min="0" :max="59" @change="generateCron"/>
			</el-form-item>
			<el-form-item label="间隔 (分钟)" v-if="form.type === 'every_n_minutes'" prop="everyMinutes">
				<el-input-number v-model="form.everyMinutes" :min="1" @change="generateCron"/>
			</el-form-item>
			<el-form-item label="起始秒" v-if="form.type === 'every_n_minutes'" prop="startSecond">
				<el-input-number v-model="form.startSecond" :min="0" :max="59" @change="generateCron"/>
			</el-form-item>
			<el-form-item label="星期" v-if="form.type === 'weekly_at'" prop="weekday">
				<el-select v-model="form.weekday" placeholder="选择星期" @change="generateCron">
					<el-option v-for="(label, idx) in weekOptions" :key="idx" :label="label" :value="idx"/>
				</el-select>
			</el-form-item>
			<el-form-item label="日期 (1-31)" v-if="form.type === 'monthly_at'" prop="dayOfMonth">
				<el-input-number v-model="form.dayOfMonth" :min="1" :max="31" @change="generateCron"/>
			</el-form-item>
			<el-form-item label="选择时间"
						  v-if="form.type === 'daily_at' || form.type === 'weekly_at' || form.type === 'monthly_at'"
						  prop="dailyTime">
				<el-time-picker v-model="form.dailyTime" placeholder="选择时间" @change="generateCron"/>
			</el-form-item>
			<el-form-item label="Cron 表达式" v-if="form.type === 'custom'" prop="customCron">
				<el-input v-model="form.customCron" placeholder="例: 0 0/30 9-17 * * 1-5" @change="generateCron"/>
			</el-form-item>
		</el-form>
		<el-divider/>
		<div>
			<div class="mb-2 font-medium">生成的 Cron 表达式：</div>
			<el-input type="textarea" v-model="value" readonly :rows="2"/>
		</div>
		<el-alert v-if="error" type="error" class="mt-2" :closable="false" :title="error"/>
		<el-divider/>
		<div>
			<div class="mb-2 font-medium">下 5 次执行时间</div>
			<el-table :data="nextRuns.map((t, i) => ({ index: i + 1, time: t }))" stripe>
				<el-table-column prop="index" label="#" width="50"/>
				<el-table-column prop="time" label="执行时间"/>
			</el-table>
		</div>
		<template #footer>
			<el-button @click="visible=false">取 消</el-button>
			<el-button type="primary" @click="confirm()">确 定</el-button>
		</template>
	</pi-dialog>
</template>

<script setup>
import {getCurrentInstance, ref, watch} from "vue";
import parser from 'cron-parser'
import dayjs from 'dayjs'

const {proxy} = getCurrentInstance()

let value = ref("")
let visible = ref(false)

const prop = defineProps({
	modelValue: {type: String, default: ""}
})

let form = ref({
	type: 'every_n_seconds',
	everySeconds: 0,
	everyMinutes: 1,
	startSecond: 0,
	dailyTime: null,
	dayOfMonth: 1,
	customCron: null
})

const error = ref('')
const nextRuns = ref([])
const tzName = Intl.DateTimeFormat().resolvedOptions().timeZone || 'local'
const weekOptions = ['周日', '周一', '周二', '周三', '周四', '周五', '周六']

watch(() => prop.modelValue, (val) => {
	value.value = val
	if (val) {
		computeNextRuns()
	}
}, {immediate: true})

function confirm() {
	proxy.$emit('update:modelValue', value.value)
	visible.value = false
}

function showPick() {
	visible.value = true
}

function generateCron() {
	try {
		error.value = ''
		let expression = ''
		if (form.value.type === 'every_n_seconds') {
			if (form.value.everySeconds === null) return;
			expression = `*/${form.value.everySeconds} * * * * *`
		} else if (form.value.type === 'every_n_minutes') {
			if (form.value.startSecond === null) return;
			if (form.value.everyMinutes === null) return;
			expression = `${form.value.startSecond} */${form.value.everyMinutes} * * * *`
		} else if (form.value.type === 'daily_at' && form.value.dailyTime) {
			const h = dayjs(form.value.dailyTime).hour()
			const m = dayjs(form.value.dailyTime).minute()
			expression = `0 ${m} ${h} * * *`
		} else if (form.value.type === 'weekly_at' && form.value.dailyTime) {
			if (form.value.weekday == null) return;
			const h = dayjs(form.value.dailyTime).hour()
			const m = dayjs(form.value.dailyTime).minute()
			expression = `0 ${m} ${h} * * ${form.value.weekday}`
		} else if (form.value.type === 'monthly_at' && form.value.dailyTime) {
			if (form.value.dayOfMonth == null) return;
			const h = dayjs(form.value.dailyTime).hour()
			const m = dayjs(form.value.dailyTime).minute()
			expression = `0 ${m} ${h} ${form.value.dayOfMonth} * *`
		} else if (form.value.type === 'custom') {
			if (form.value.customCron == null) return;
			expression = form.value.customCron.trim()
		}
		value.value = expression
		computeNextRuns()
	} catch (err) {
		error.value = err.message
	}
}

function computeNextRuns() {
	nextRuns.value = []
	try {
		let expr = value.value.trim()
		if (!expr) return
		const parts = expr.split(/\s+/)
		if (parts.length === 5) expr = '0 ' + expr
		const interval = parser.parseExpression(expr, {iterator: true, tz: tzName})
		const arr = []
		for (let i = 0; i < 5; i++) {
			const obj = interval.next()
			arr.push(dayjs(obj.value.toDate()).format('YYYY-MM-DD HH:mm:ss'))
		}
		nextRuns.value = arr
	} catch (err) {
		error.value = err.message
	}
}

</script>

<style lang="scss" scoped>
:deep(.el-form-item) {
	margin-bottom: 18px;
}
</style>
