<template>
  <!-- 添加或修改任务抽屉 -->
  <el-drawer v-model="visibleProxy" :title="title" size="70%" append-to-body :close-on-click-modal="false" @closed="resetForm">
    <el-card shadow="always" class="box-card" style="padding-top: 10px">
      <el-form ref="jobFormRef" :model="form" :rules="rules" label-width="120px">
        <!-- 基础配置 -->
        <div class="form-section">
          <div class="section-title">基础配置</div>
          <el-row :gutter="20">
            <el-col :span="12">
              <el-form-item label="执行器" prop="jobGroup">
                <el-select v-model="form.jobGroup" placeholder="示例执行器" style="width: 100%">
                  <el-option v-for="group in jobGroupOptions" :key="group.id" :label="group.title" :value="group.id" />
                </el-select>
              </el-form-item>
            </el-col>
            <el-col :span="12">
              <el-form-item label="任务描述" prop="jobDesc">
                <el-input v-model="form.jobDesc" placeholder="请输入任务描述" />
              </el-form-item>
            </el-col>
          </el-row>
          <el-row :gutter="20">
            <el-col :span="12">
              <el-form-item label="负责人" prop="author">
                <el-input v-model="form.author" placeholder="请输入负责人" />
              </el-form-item>
            </el-col>
            <el-col :span="12">
              <el-form-item label="报警邮件" prop="alarmEmail">
                <el-input v-model="form.alarmEmail" placeholder="请输入报警邮件，多个邮件用逗号分隔" />
              </el-form-item>
            </el-col>
          </el-row>
        </div>

        <!-- 调度配置 -->
        <div class="form-section">
          <div class="section-title">调度配置</div>
          <el-row :gutter="20">
            <el-col :span="12">
              <el-form-item label="调度类型" prop="scheduleType">
                <el-select v-model="form.scheduleType" placeholder="CRON" style="width: 100%" @change="handleScheduleTypeChange">
                  <el-option label="CRON" value="CRON" />
                  <el-option label="固定速度" value="FIX_RATE" />
                </el-select>
              </el-form-item>
            </el-col>
            <el-col :span="12">
              <el-form-item v-if="form.scheduleType === 'CRON'" label="Cron" prop="scheduleConf">
                <el-input v-model="form.scheduleConf" placeholder="cron表达式..." @blur="handleCronChange">
                  <template #append>
                    <el-button icon="Setting" @click="showCronGen = true"></el-button>
                  </template>
                </el-input>
                <div v-if="nextTriggerTimes.length > 0" class="cron-preview">
                  <el-text type="info" size="small"> 未来5次执行时间：{{ nextTriggerTimes.join(', ') }} </el-text>
                </div>
              </el-form-item>
              <el-form-item v-else-if="form.scheduleType === 'FIX_RATE'" label="固定速度" prop="scheduleConf">
                <el-input v-model="form.scheduleConf" placeholder="请输入固定速度，单位秒">
                  <template #append>秒</template>
                </el-input>
              </el-form-item>
            </el-col>
          </el-row>
        </div>

        <!-- 任务配置 -->
        <div class="form-section">
          <div class="section-title">任务配置</div>
          <el-row :gutter="20">
            <el-col :span="12">
              <el-form-item label="JobHandler" prop="executorHandler">
                <el-input v-model="form.executorHandler" placeholder="请输入JobHandler" />
              </el-form-item>
            </el-col>
          </el-row>
          <el-form-item label="任务参数" prop="executorParam">
            <el-input v-model="form.executorParam" type="textarea" :rows="3" placeholder="请输入任务参数，支持JSON格式" />
            <div class="param-tips">
              <el-text type="info" size="small"> 任务参数建议使用JSON格式，例如：{"key1":"value1","key2":"value2"} </el-text>
            </div>
          </el-form-item>
        </div>

        <!-- 高级配置 -->
        <div class="form-section">
          <div class="section-title">高级配置</div>
          <el-row :gutter="20">
            <el-col :span="12">
              <el-form-item label="路由策略" prop="executorRouteStrategy">
                <el-select v-model="form.executorRouteStrategy" placeholder="第一个" style="width: 100%">
                  <el-option label="第一个" value="FIRST" />
                  <el-option label="最后一个" value="LAST" />
                  <el-option label="轮询" value="ROUND" />
                  <el-option label="随机" value="RANDOM" />
                  <el-option label="一致性HASH" value="CONSISTENT_HASH" />
                  <el-option label="最不经常使用" value="LEAST_FREQUENTLY_USED" />
                  <el-option label="最近最久未使用" value="LEAST_RECENTLY_USED" />
                  <el-option label="故障转移" value="FAILOVER" />
                  <el-option label="忙碌转移" value="BUSYOVER" />
                  <el-option label="分片广播" value="SHARDING_BROADCAST" />
                </el-select>
              </el-form-item>
            </el-col>
            <el-col :span="12">
              <el-form-item label="子任务ID">
                <el-input v-model="form.childJobId" placeholder="请输入子任务的任务ID,如存在多个则逗号分隔" />
              </el-form-item>
            </el-col>
          </el-row>
          <el-row :gutter="20">
            <el-col :span="12">
              <el-form-item label="调度过期策略" prop="misfireStrategy">
                <el-select v-model="form.misfireStrategy" placeholder="忽略" style="width: 100%">
                  <el-option label="忽略" value="DO_NOTHING" />
                  <el-option label="立即执行一次" value="FIRE_ONCE_NOW" />
                </el-select>
              </el-form-item>
            </el-col>
            <el-col :span="12">
              <el-form-item label="阻塞处理策略" prop="executorBlockStrategy">
                <el-select v-model="form.executorBlockStrategy" placeholder="单机串行" style="width: 100%">
                  <el-option label="单机串行" value="SERIAL_EXECUTION" />
                  <el-option label="丢弃后续调度" value="DISCARD_LATER" />
                  <el-option label="覆盖之前调度" value="COVER_EARLY" />
                </el-select>
              </el-form-item>
            </el-col>
          </el-row>
          <el-row :gutter="20">
            <el-col :span="12">
              <el-form-item label="任务超时时间">
                <el-input v-model="form.executorTimeout" placeholder="任务超时时间，单位秒，大于零时生效">
                  <template #append>秒</template>
                </el-input>
              </el-form-item>
            </el-col>
            <el-col :span="12">
              <el-form-item label="失败重试次数">
                <el-input v-model="form.executorFailRetryCount" placeholder="失败重试次数，大于零时生效">
                  <template #append>次</template>
                </el-input>
              </el-form-item>
            </el-col>
          </el-row>
        </div>
      </el-form>
    </el-card>

    <template #footer>
      <div class="dialog-footer">
        <el-button :loading="buttonLoading" type="primary" @click="submitForm">保存</el-button>
        <el-button @click="cancel">取消</el-button>
      </div>
    </template>
  </el-drawer>

  <!-- Cron表达式生成器对话框 -->
  <cron-generator v-model:visible="showCronGen" v-model="tempCron" @confirm="applyCron" />
</template>

<script setup lang="ts">
import { getJobInfo, addJobInfo, updateJobInfo, listJobGroup, nextTriggerTime } from '@/api/xxljob/job';
import { JobInfoForm, JobInfoVO, JobGroupVO } from '@/api/xxljob/job/types';
import CronGenerator from './components/CronGenerator.vue';

const props = defineProps({
  visible: {
    type: Boolean,
    default: false
  },
  editType: {
    type: String,
    default: 'add'
  },
  rowData: {
    type: Object as PropType<JobInfoVO | null>,
    default: null
  }
});

const emit = defineEmits(['update:visible', 'save']);

const { proxy } = getCurrentInstance() as ComponentInternalInstance;

// 可见性的双向绑定
const visibleProxy = computed({
  get: () => props.visible,
  set: (val) => emit('update:visible', val)
});

// 根据编辑类型决定标题
const title = computed(() => (props.editType === 'add' ? '新增' : '编辑'));

// 状态变量
const buttonLoading = ref(false);
const showCronGen = ref(false);
const tempCron = ref('');
const nextTriggerTimes = ref<string[]>([]);
const jobGroupOptions = ref<JobGroupVO[]>([]);

// 表单ref
const jobFormRef = ref<ElFormInstance>();

// 初始化表单数据
const initFormData: JobInfoForm = {
  id: undefined,
  jobGroup: '',
  jobDesc: '',
  author: '',
  alarmEmail: '',
  scheduleType: 'CRON',
  scheduleConf: '',
  misfireStrategy: 'DO_NOTHING',
  executorRouteStrategy: 'FIRST',
  executorHandler: '',
  executorParam: '',
  executorBlockStrategy: 'SERIAL_EXECUTION',
  executorTimeout: 0,
  executorFailRetryCount: 0,
  glueType: 'BEAN',
  glueSource: '',
  glueRemark: '',
  childJobId: ''
};

// 表单数据
const form = ref<JobInfoForm>({ ...initFormData });

// 任务参数验证函数
const validateExecutorParam = (rule: any, value: any, callback: any) => {
  if (!value || value.trim() === '') {
    callback();
    return;
  }

  // 检查是否包含危险字符或关键字
  const dangerousPatterns = [
    /eval\s*\(/i,
    /exec\s*\(/i,
    /system\s*\(/i,
    /runtime\s*\./i,
    /processbuilder/i,
    /<script/i,
    /javascript:/i,
    /vbscript:/i,
    /onload\s*=/i,
    /onerror\s*=/i,
    /\$\{.*\}/, // EL表达式
    /#\{.*\}/, // OGNL表达式
    /\{\{.*\}\}/ // 模板表达式
  ];

  for (const pattern of dangerousPatterns) {
    if (pattern.test(value)) {
      callback(new Error('任务参数包含不安全的内容，请检查参数格式'));
      return;
    }
  }

  // 检查是否为有效的JSON格式（可选）
  if (value.trim().startsWith('{') || value.trim().startsWith('[')) {
    try {
      JSON.parse(value);
    } catch (e) {
      callback(new Error('JSON格式不正确，请检查参数格式'));
      return;
    }
  }

  // 检查参数长度
  if (value.length > 2000) {
    callback(new Error('任务参数过长，请控制在2000字符以内'));
    return;
  }

  callback();
};

// 表单校验规则
const rules = ref({
  jobGroup: [{ required: true, message: '执行器不能为空', trigger: 'change' }],
  jobDesc: [{ required: true, message: '任务描述不能为空', trigger: 'blur' }],
  author: [{ required: true, message: '负责人不能为空', trigger: 'blur' }],
  scheduleType: [{ required: true, message: '调度类型不能为空', trigger: 'change' }],
  scheduleConf: [
    {
      required: true,
      message: '调度配置不能为空',
      trigger: 'blur',
      validator: (rule: any, value: any, callback: any) => {
        if (!value) {
          callback(new Error('调度配置不能为空'));
        } else if (form.value.scheduleType === 'CRON') {
          // Cron表达式简单验证
          const cronRegex =
            /^(\*|([0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9])|\*\/([0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9])) (\*|([0-9]|1[0-9]|2[0-3])|\*\/([0-9]|1[0-9]|2[0-3])) (\*|([1-9]|1[0-9]|2[0-9]|3[0-1])|\*\/([1-9]|1[0-9]|2[0-9]|3[0-1])) (\*|([1-9]|1[0-2])|\*\/([1-9]|1[0-2])) (\*|[0-6]|\*\/[0-6]) (\*|([1-9]\d{3})|\*\/([1-9]\d{3}))?$/;
          if (!cronRegex.test(value) && !value.includes('?')) {
            callback(new Error('Cron表达式格式不正确'));
          } else {
            callback();
          }
        } else if (form.value.scheduleType === 'FIX_RATE') {
          const num = parseInt(value);
          if (isNaN(num) || num <= 0) {
            callback(new Error('请输入大于0的整数'));
          } else {
            callback();
          }
        } else {
          callback();
        }
      }
    }
  ],
  executorHandler: [{ required: true, message: 'JobHandler不能为空', trigger: 'blur' }],
  executorParam: [{ validator: validateExecutorParam, trigger: 'blur' }],
  executorRouteStrategy: [{ required: true, message: '路由策略不能为空', trigger: 'change' }],
  executorBlockStrategy: [{ required: true, message: '阻塞处理策略不能为空', trigger: 'change' }],
  misfireStrategy: [{ required: true, message: '调度过期策略不能为空', trigger: 'change' }]
});

/** 获取执行器组列表 */
const getJobGroupList = async () => {
  const res = await listJobGroup();
  jobGroupOptions.value = res.data;
};

/** 处理调度类型变化 */
const handleScheduleTypeChange = (type: string) => {
  form.value.scheduleConf = '';
  nextTriggerTimes.value = [];
};

/** 处理Cron表达式变化 */
const handleCronChange = async () => {
  if (form.value.scheduleConf && form.value.scheduleType === 'CRON') {
    try {
      const res = await nextTriggerTime(form.value.scheduleType, form.value.scheduleConf);
      nextTriggerTimes.value = res.data;
    } catch (error) {
      nextTriggerTimes.value = [];
    }
  } else {
    nextTriggerTimes.value = [];
  }
};

/** 应用Cron表达式 */
const applyCron = (cronExpression: string) => {
  form.value.scheduleConf = cronExpression;
  handleCronChange();
};

/** 取消按钮 */
const cancel = () => {
  visibleProxy.value = false;
};

/** 表单重置 */
const resetForm = () => {
  form.value = { ...initFormData };
  nextTriggerTimes.value = [];
  jobFormRef.value?.resetFields();
};

/** 提交按钮 */
const submitForm = () => {
  jobFormRef.value?.validate(async (valid: boolean) => {
    if (valid) {
      buttonLoading.value = true;
      try {
        if (form.value.id) {
          await updateJobInfo(form.value);
        } else {
          await addJobInfo(form.value);
        }
        proxy?.$modal.msgSuccess('操作成功');
        emit('save');
        visibleProxy.value = false;
      } finally {
        buttonLoading.value = false;
      }
    }
  });
};

// 监听抽屉可见性、编辑类型和行数据变化
watch(
  [() => props.visible, () => props.editType, () => props.rowData],
  async ([visible, type, data]) => {
    if (visible) {
      await getJobGroupList();
      resetForm();

      if (type === 'edit' && data) {
        // 修改操作
        const res = await getJobInfo(data.id);
        Object.assign(form.value, res.data);

        // 如果是CRON类型，加载下次执行时间
        if (form.value.scheduleType === 'CRON' && form.value.scheduleConf) {
          handleCronChange();
        }
      }
    }
  },
  { immediate: true }
);
</script>

<style scoped>
.form-section {
  margin-bottom: 32px;
  border-bottom: 1px solid #f0f0f0;
  padding-bottom: 24px;
}

.form-section:last-child {
  border-bottom: none;
  margin-bottom: 0;
}

.section-title {
  font-size: 16px;
  font-weight: 600;
  color: #303133;
  margin-bottom: 20px;
  padding-left: 12px;
  border-left: 4px solid #409eff;
}

.cron-preview {
  margin-top: 8px;
  padding: 8px 12px;
  background-color: #f4f4f5;
  border-radius: 4px;
  font-size: 12px;
}

.param-tips {
  margin-top: 4px;
}

.dialog-footer {
  text-align: center;
  padding: 20px 0;
}
</style>
