import { eq, sql } from 'drizzle-orm';
import * as dealQueries from '@/server/db/queries/deals.js';
import * as groupDealQueries from '@/server/db/queries/group-deals.js';
import { deals, groupDeals } from '@/server/db/schema.js';
import { applyEffects } from './apply-effects.js';
import { transition } from './machine.js';
import {
  buildCtx,
  GroupDealError,
  makeApplyCtx,
  safeArmGroupDealDeadlineAlarm,
  type GroupDealDeps,
  withoutAlarmEffects,
} from './runtime.js';
import { executeGroupDeal } from './execute-handler.js';
import { captureCaught } from '@/server/observability/capture.server.js';

export async function extendGroupDeal(
  deps: GroupDealDeps,
  groupDealId: string,
  newDeadline: Date,
) {
  const groupDeal = await groupDealQueries.findById(deps.db, groupDealId);
  if (!groupDeal) throw new GroupDealError('GROUP_DEAL_NOT_FOUND', 'Group deal not found');

  const extendResult = transition(buildCtx(groupDeal, null), {
    kind: 'vendor_extend',
    newDeadline,
    at: new Date(),
  });
  if (!extendResult.ok) {
    throw new GroupDealError(
      'INVALID_STATE',
      `Can only extend deals in COLLECTING or THRESHOLD_MET state. Current: ${groupDeal.groupState}`,
    );
  }

  if (groupDeal.extensionCount >= 1) {
    throw new GroupDealError('MAX_EXTENSIONS_REACHED', 'Group deal can only be extended once');
  }

  const deal = await dealQueries.findById(deps.db, groupDeal.dealId);
  if (!deal) throw new GroupDealError('DEAL_NOT_FOUND', 'Parent deal not found');

  const currentDeadline = deal.windowEnd ?? new Date();
  const minNewDeadline = new Date(currentDeadline.getTime() + 24 * 60 * 60 * 1000);
  const maxNewDeadline = new Date(currentDeadline.getTime() + 48 * 60 * 60 * 1000);
  if (newDeadline < minNewDeadline || newDeadline > maxNewDeadline) {
    throw new GroupDealError(
      'INVALID_EXTENSION_DEADLINE',
      'New deadline must be 24-48 hours from current deadline',
    );
  }

  await deps.db.update(deals).set({ windowEnd: newDeadline }).where(eq(deals.id, deal.id));
  try {
    await deps.doClient.armDealAlarm(deal.id, newDeadline);
  } catch (err) {
    captureCaught(err, { scope: 'armDealAlarm', extra: { dealId: deal.id } });
  }
  await safeArmGroupDealDeadlineAlarm(deps.doClient, groupDealId, newDeadline);

  await groupDealQueries.updateGroupState(deps.db, groupDealId, extendResult.nextState, {
    extendedDeadline: newDeadline,
    extensionCount: sql`${groupDeals.extensionCount} + 1` as unknown as number,
  });

  await applyEffects(
    makeApplyCtx(deps, (id) => executeGroupDeal(deps, id)),
    withoutAlarmEffects(extendResult.effects),
  );

  return groupDealQueries.findById(deps.db, groupDealId);
}
