// 極簡 5 欄位 cron 比對：minute hour day-of-month month day-of-week。
// 支援星號、步進(星號斜線n)、列表(a,b,c)、範圍(a-b)、單一數字。
// 給 worker 每分鐘輪詢時判斷規則是否「到點」。

function fieldMatches(field: string, value: number, min: number, max: number): boolean {
  if (field === "*") return true;

  for (const part of field.split(",")) {
    const token = part.trim();
    if (token === "") continue;

    // step: */n 或 a-b/n 或 */n
    const stepMatch = token.match(/^(\*|\d+(?:-\d+)?)\/(\d+)$/);
    if (stepMatch) {
      const step = parseInt(stepMatch[2], 10);
      if (step <= 0) continue;
      let rangeStart = min;
      let rangeEnd = max;
      if (stepMatch[1] !== "*") {
        const rangeParts = stepMatch[1].split("-");
        rangeStart = parseInt(rangeParts[0], 10);
        rangeEnd = rangeParts[1] !== undefined ? parseInt(rangeParts[1], 10) : max;
      }
      if (value < rangeStart || value > rangeEnd) continue;
      if ((value - rangeStart) % step === 0) return true;
      continue;
    }

    // range: a-b
    const rangeMatch = token.match(/^(\d+)-(\d+)$/);
    if (rangeMatch) {
      const start = parseInt(rangeMatch[1], 10);
      const end = parseInt(rangeMatch[2], 10);
      if (value >= start && value <= end) return true;
      continue;
    }

    // single
    if (/^\d+$/.test(token) && parseInt(token, 10) === value) return true;
  }

  return false;
}

export function isValidCron(expr: string): boolean {
  const fields = expr.trim().split(/\s+/);
  return fields.length === 5;
}

export function cronMatches(expr: string, date: Date = new Date()): boolean {
  const fields = expr.trim().split(/\s+/);
  if (fields.length !== 5) return false;

  const [minute, hour, dom, month, dow] = fields;
  const normalizedDow = date.getDay(); // 0-6 (Sun=0)

  return (
    fieldMatches(minute, date.getMinutes(), 0, 59) &&
    fieldMatches(hour, date.getHours(), 0, 23) &&
    fieldMatches(dom, date.getDate(), 1, 31) &&
    fieldMatches(month, date.getMonth() + 1, 1, 12) &&
    fieldMatches(dow, normalizedDow, 0, 6)
  );
}
