import { DurableObject } from 'cloudflare:workers';
import { getFullDb, type DbEnv } from '../lib/db.js';
import { runScheduledPublish } from '../workers/cron/run.js'; // REUSE — do not reimplement
import { timingSafeEqualStr } from '../lib/timing-safe.js';

const FIVE_MIN_MS = 5 * 60 * 1000;

export class ScheduledPublishDO extends DurableObject<Cloudflare.Env> {
  // Control plane ONLY: secret-gated, timing-safe arm. Never runs the sweep directly.
  override async fetch(req: Request): Promise<Response> {
    if (!this.#authorized(req)) return new Response('forbidden', { status: 403 });
    if ((await this.ctx.storage.getAlarm()) === null) {
      await this.ctx.storage.setAlarm(Date.now() + FIVE_MIN_MS);
    }
    return new Response('armed', { status: 200 });
  }

  // Recurring sweep. Catches, logs, ALWAYS reschedules. Never rethrows (no retry storm).
  override async alarm(): Promise<void> {
    try {
      const { db } = getFullDb(this.env as unknown as DbEnv);
      const { promoted } = await runScheduledPublish(db);
      console.log(`[mod-cms scheduled-publish DO] promoted ${promoted}`);
    } catch (error) {
      console.error('[mod-cms scheduled-publish DO] sweep failed:', error);
      // swallow — idempotent sweep self-heals next tick
    } finally {
      await this.ctx.storage.setAlarm(Date.now() + FIVE_MIN_MS);
    }
  }

  #authorized(req: Request): boolean {
    const provided = req.headers.get('x-mod-cron-secret') ?? '';
    const expected = this.env.CRON_DO_SECRET ?? '';
    if (expected.length === 0) return false; // fail-closed: no secret ⇒ deny
    return timingSafeEqualStr(provided, expected);
  }
}
