import type { MultidealEnv } from '@/server/env';
import { respondError, respondOk } from '@/server/api/error-envelope.js';

const ALARM_INTERVAL_MS = 15 * 60 * 1000; // 15 minutes

export class StripeReconcileDO {
  private ctx: DurableObjectState;
  private env: MultidealEnv;

  constructor(ctx: DurableObjectState, env: MultidealEnv) {
    this.ctx = ctx;
    this.env = env;
  }

  async fetch(request: Request): Promise<Response> {
    const url = new URL(request.url);

    if (request.method === 'POST' && url.pathname === '/arm') {
      const nextAt = Date.now() + ALARM_INTERVAL_MS;
      await this.ctx.storage.setAlarm(nextAt);
      return new Response(
        JSON.stringify({ ok: true, nextAlarmAt: new Date(nextAt).toISOString() }),
        {
          status: 200,
          headers: { 'Content-Type': 'application/json' },
        },
      );
    }

    if (request.method === 'GET' && url.pathname === '/status') {
      const alarm = await this.ctx.storage.getAlarm();
      return new Response(
        JSON.stringify({ nextAlarmAt: alarm ? new Date(alarm).toISOString() : null }),
        {
          status: 200,
          headers: { 'Content-Type': 'application/json' },
        },
      );
    }

    if (request.method === 'POST' && url.pathname === '/reconcile-now') {
      const result = await this.runSweep();
      return respondOk(result);
    }

    return respondError('NOT_FOUND', 'Not found');
  }

  async alarm(): Promise<void> {
    try {
      await this.runSweep();
    } catch (err) {
      console.error(
        JSON.stringify({
          event: 'do_alarm_error',
          class: 'StripeReconcileDO',
          error: err instanceof Error ? err.message : String(err),
        }),
      );
      throw err;
    } finally {
      const nextAt = Date.now() + ALARM_INTERVAL_MS;
      await this.ctx.storage.setAlarm(nextAt);
    }
  }

  private async runSweep(): Promise<{ checked: number; resolved: number; failed: number }> {
    const { reconcilePendingPurchases } = await import('@/server/payments/stripe/reconcile');
    return reconcilePendingPurchases(this.env as unknown as MultidealEnv);
  }
}
