/**
 * cronForm.ts — 保存済み cron 文字列を、スケジュール編集フォームのフィールドに
 * 復元する純関数。
 *
 * スケジュールは DB 上ではすべて cron 文字列なので、編集時にどの「種別」
 * (daily / weekly / monthly / cron / once) として表示するかをここで判定する。
 *
 * 重要: daily/weekly/monthly のプリセットへ変換するのは、対象フィールドが
 * **単純な整数** (例: `0 9 * * *`) のときだけ。範囲 (`1-5`) / ステップ (`*​/30`) /
 * リスト (`9,17`) / 非 `*` の月を含む式は、プリセットでは表現できない。これらを
 * 無理にプリセット化すると `Number()` が NaN を返してフィールドが壊れ、かつ
 * 元の cron 式が失われる。そうした式は `cron` 種別のまま生の式を保持する。
 */

export type ScheduleType = 'daily' | 'weekly' | 'monthly' | 'cron' | 'once';

export interface ScheduleFields {
  scheduleType: ScheduleType;
  hour: number;
  minute: number;
  dayOfWeek: number;
  dayOfMonth: number;
  cronExpression: string;
}

const isInt = (s: string): boolean => /^\d+$/.test(s);
const inRange = (s: string, lo: number, hi: number): boolean => {
  if (!isInt(s)) return false;
  const n = Number(s);
  return n >= lo && n <= hi;
};

export function cronToFormState(cron: string): ScheduleFields {
  // 任意の cron 文字列をそのまま保持するフォールバック (生の式を捨てない)。
  const asCron: ScheduleFields = {
    scheduleType: 'cron',
    hour: 9,
    minute: 0,
    dayOfWeek: 1,
    dayOfMonth: 1,
    cronExpression: cron,
  };

  if (cron === 'once') {
    return { scheduleType: 'once', hour: 9, minute: 0, dayOfWeek: 1, dayOfMonth: 1, cronExpression: '' };
  }

  const parts = cron.split(' ');
  if (parts.length !== 5) return asCron;

  const [min, hour, dom, mon, dow] = parts;
  // プリセットは「分・時が整数」かつ「月は毎月 (*)」が前提。満たさなければ cron 扱い。
  if (mon !== '*' || !isInt(min) || !isInt(hour)) return asCron;

  const h = Number(hour);
  const m = Number(min);

  if (dom === '*' && dow === '*') {
    return { scheduleType: 'daily', hour: h, minute: m, dayOfWeek: 1, dayOfMonth: 1, cronExpression: '' };
  }
  // weekly/monthly only when the day value is within the editor's select range
  // (dow 0-6, dom 1-31). Out-of-range forms like `* * * * 7` (Sunday-as-7) stay
  // as raw cron so re-saving never rewrites them to a different value.
  if (dom === '*' && inRange(dow, 0, 6)) {
    return { scheduleType: 'weekly', hour: h, minute: m, dayOfWeek: Number(dow), dayOfMonth: 1, cronExpression: '' };
  }
  if (inRange(dom, 1, 31) && dow === '*') {
    return { scheduleType: 'monthly', hour: h, minute: m, dayOfWeek: 1, dayOfMonth: Number(dom), cronExpression: '' };
  }

  // dom と dow が両方指定など、プリセットに当てはまらない組み合わせは cron 扱い。
  return asCron;
}
