/**
 * Cron index — 單一固定 key 模型（kbdb-base 8.P0 止血）。
 *
 * 背景：原本每個 cron workflow 寫一筆 `cron-idx:{apiKey}:{name}`，scheduled() 每分鐘
 * `WEBHOOKS.list({prefix:'cron-idx:'})` 一次 = 1440 list/日，單獨就爆 CF KV 免費 list 上限（1000/日）。
 *
 * 解法（SDD §8.2）：所有 cron workflow 的 cron_expr 集中存進**單一固定 key** `cron-idx:_all`。
 * scheduled() 每分鐘只 `get` 一次（KV get 免費額度 100K/日，遠夠）→ list 次數歸零。
 * acr push（webhooks-named POST）/ delete 時對這個 key 做 read-modify-write 維護。
 *
 * 結構：{ [ "{apiKey}:{name}" ]: cron_expr }
 *   key 用 `{apiKey}:{name}` 維持多租戶隔離（scheduled 觸發時拆回 apiKey/name 去讀完整 record）。
 */

// KVNamespace 用全域 ambient 型別（與 types.ts 一致，不從 @cloudflare/workers-types import
// 以免產生第二個不相容的 KVNamespace 型別）。

/** 單一固定索引 key — 全租戶共用一筆，scheduled() 只 get 這個 */
export const CRON_INDEX_KEY = 'cron-idx:_all';

/** 索引內容：entryKey（"{apiKey}:{name}"）→ cron_expr */
export type CronIndex = Record<string, string>;

/** 組出索引 entry 的 key（apiKey + name），含 ':' 也安全：split 時 name 用 slice 還原 */
export function cronEntryKey(apiKey: string, name: string): string {
  return `${apiKey}:${name}`;
}

/** 從 entryKey 拆回 { apiKey, name }（name 可能含 ':'，取第一個 ':' 後全部為 name） */
export function parseCronEntryKey(entryKey: string): { apiKey: string; name: string } | null {
  const idx = entryKey.indexOf(':');
  if (idx <= 0) return null;
  return { apiKey: entryKey.slice(0, idx), name: entryKey.slice(idx + 1) };
}

/** 讀整個 cron index（單次 get，不 list） */
export async function readCronIndex(kv: KVNamespace): Promise<CronIndex> {
  const raw = await kv.get(CRON_INDEX_KEY, 'text');
  if (!raw) return {};
  try {
    const parsed = JSON.parse(raw);
    return parsed && typeof parsed === 'object' ? (parsed as CronIndex) : {};
  } catch {
    return {};
  }
}

/**
 * upsert / 移除單筆 cron entry（read-modify-write 單一 key）。
 * @param cronExpr - 有值=upsert；null/undefined=移除（push 改掉 cron 後清乾淨）
 */
export async function updateCronIndexEntry(
  kv: KVNamespace,
  apiKey: string,
  name: string,
  cronExpr: string | null | undefined,
): Promise<void> {
  const index = await readCronIndex(kv);
  const entryKey = cronEntryKey(apiKey, name);

  if (cronExpr) {
    if (index[entryKey] === cronExpr) return; // 無變化，不浪費一次 put
    index[entryKey] = cronExpr;
  } else {
    if (!(entryKey in index)) return; // 本來就沒有，不浪費一次 put
    delete index[entryKey];
  }

  await kv.put(CRON_INDEX_KEY, JSON.stringify(index));
}
