import { executeRows } from '../execute-rows.js';
import { and, eq, isNull, sql } from 'drizzle-orm';
import type { DrizzleClient } from '@/server/db/client.js';
import { stripeWebhookEvents } from '@/server/db/schema.js';

/** Reclaim in-flight claims after isolate eviction; longer than max handler, shorter than Stripe retry horizon. */
export const CLAIM_STALE_MS = 5 * 60 * 1000;

export async function claimWebhookEvent(
  db: DrizzleClient,
  { eventId, eventType }: { eventId: string; eventType: string },
): Promise<{ shouldProcess: boolean }> {
  const result = await db.execute<{ event_id: string }>(sql`
    INSERT INTO stripe_webhook_events (event_id, event_type, claimed_at)
    VALUES (${eventId}, ${eventType}, now())
    ON CONFLICT (event_id) DO UPDATE SET claimed_at = now()
    WHERE stripe_webhook_events.processed_at IS NULL
      AND (stripe_webhook_events.claimed_at IS NULL OR stripe_webhook_events.claimed_at < now() - INTERVAL '5 minutes')
    RETURNING event_id
  `);
  return { shouldProcess: executeRows<{ event_id: string }>(result).length > 0 };
}

export async function markWebhookEventProcessed(db: DrizzleClient, eventId: string): Promise<void> {
  await db
    .update(stripeWebhookEvents)
    .set({ processedAt: new Date() })
    .where(eq(stripeWebhookEvents.eventId, eventId));
}

/** Clear in-flight claim so Stripe retries can re-enter after handler failure. */
export async function releaseWebhookEventClaim(db: DrizzleClient, eventId: string): Promise<void> {
  await db
    .update(stripeWebhookEvents)
    .set({ claimedAt: null })
    .where(and(eq(stripeWebhookEvents.eventId, eventId), isNull(stripeWebhookEvents.processedAt)));
}
