/**
 * Sweep stuck refund intents: a 'pending' refund_intent row older than
 * STUCK_AFTER_MS means a worker died between claiming the intent and the
 * provider call settling/releasing it. Retry the provider refund under the
 * intent's original refundKey (Stripe dedupes on the idempotency key, so a
 * refund that DID land is returned, not re-issued); the provider settles the
 * intent via setPurchaseRefund on success. Hard provider failures release the
 * claim (pending → failed) so the money stops being reserved.
 */

import { createDbService } from '@/server/services/db.js';
import { and, eq, lt } from 'drizzle-orm';
import type { MultidealEnv } from '../env.js';
import { orderLine, refundIntent, refundIntentLineExt } from '../db/schema.js';
import { getPaymentProvider } from '../payments/get-provider.js';
import { captureCaught } from '../observability/capture.server.js';
import { failPendingRefundIntent } from '../db/queries/cron-boundary.js';

const STUCK_AFTER_MS = 30 * 60 * 1000;
const BATCH_LIMIT = 20;

export async function runRefundIntentsSweep(env: MultidealEnv): Promise<void> {
  const db = createDbService({ DATABASE_URL: env.DATABASE_URL });
  const cutoff = new Date(Date.now() - STUCK_AFTER_MS);

  const stuck = await db
    .select({
      id: refundIntent.id,
      orderId: refundIntent.orderId,
      amount: refundIntent.amount,
      refundKey: refundIntent.refundKey,
      orderLineId: refundIntentLineExt.orderLineId,
    })
    .from(refundIntent)
    .leftJoin(refundIntentLineExt, eq(refundIntentLineExt.refundIntentId, refundIntent.id))
    .where(and(eq(refundIntent.status, 'pending'), lt(refundIntent.createdAt, cutoff)))
    .limit(BATCH_LIMIT);
  if (stuck.length === 0) return;

  const provider = await getPaymentProvider(env);

  for (const intent of stuck) {
    try {
      const [line] = intent.orderLineId
        ? [{ id: intent.orderLineId }]
        : await db
            .select({ id: orderLine.id })
            .from(orderLine)
            .where(eq(orderLine.orderId, intent.orderId))
            .limit(1);
      if (!line) {
        captureCaught(
          new Error(`refund intent ${intent.id}: order ${intent.orderId} has no lines`),
          {
            scope: 'cron.refundIntentsSweep',
            severity: 'error',
          },
        );
        continue;
      }

      const result = await provider.refund({
        purchaseId: line.id,
        amountAgorot: Number(intent.amount),
        idempotencyKey: intent.refundKey ?? undefined,
      });

      if (!result.ok) {
        // Provider says no — stop reserving the money and surface it.
        await failPendingRefundIntent(db, intent.id);
        captureCaught(
          new Error(
            `refund intent ${intent.id} retry failed: ${result.code} ${result.message ?? ''}`,
          ),
          { scope: 'cron.refundIntentsSweep', severity: 'error' },
        );
      }
      // Success: provider.refund settles the intent (setPurchaseRefund) itself.
    } catch (err) {
      captureCaught(err as Error, {
        scope: 'cron.refundIntentsSweep',
        severity: 'error',
        extra: { intentId: intent.id },
      });
    }
  }
}
