/**
 * Cron: Group Partial Execution Timeout - runs every 5 minutes.
 *
 * Cancels group deals where the vendor did not respond to a partial execution
 * offer within the 24-hour decision window (partialDecisionDeadline).
 *
 * Calls failGroupDeal which releases all held funds and notifies participants.
 *
 * Batch size capped at 50 per invocation (Workers CPU limit).
 */

import { createDbService } from '@/server/services/db.js';
import { sql } from 'drizzle-orm';
import { withSentry } from '@/server/observability/with-sentry';
import { env as runtimeEnv } from '@/server/env.js';
import { buildServices } from '@/server/services/bundle.js';
import type { CronEnv } from './deal-expiry.js';

const BATCH_SIZE = 50;

const noopPush = {
  sendToUser: async () => {},
  sendToVendor: async () => {},
};

export const runGroupPartialTimeout = withSentry(
  async function runGroupPartialTimeout(env: CronEnv): Promise<void> {
    const db = createDbService({ DATABASE_URL: env.DATABASE_URL });

    try {
      const { failGroupDeal } = await import('@/server/workflows/group-deal.js');

      const services = await buildServices(runtimeEnv);
      const deps = {
        db,
        push: noopPush,
        qrSecret: env.QR_SECRET ?? '',
        doClient: services.doClient,
        payments: services.payments,
        storage: services.storage,
      };

      const timedOutGroups = await db.execute(sql`
      SELECT id
      FROM group_deals
      WHERE group_state = 'PARTIAL_PENDING'
        AND partial_decision_deadline <= NOW()
      LIMIT ${BATCH_SIZE}
    `);

      const rows = timedOutGroups.rows as Array<{ id: string }>;

      for (const row of rows) {
        await failGroupDeal(deps, row.id);
      }
    } catch (err) {
      if (err instanceof Error && err.message.includes('Cannot find module')) {
        return;
      }
      throw err;
    }
  },
  { name: 'cron.group-partial-timeout', kind: 'cron' },
);
