/**
 * applyEffects — interprets ViolationEffect[].
 *
 * PERSISTENCE ORDERING:
 *   1. pause-vendor-deals (idempotent UPDATE — runs before BAN state write
 *      so deals are already paused if a later step crashes)
 *   2. set-account-state  (vendor row UPDATE)
 *   3. insert-admin-action (audit row INSERT)
 *   4. send-policy-email   (best-effort — never rolls back)
 *
 * This is the ONLY place in violation flows that calls:
 *   - vendorQueries.updateAccountState
 *   - deals UPDATE for ban-pause
 *   - adminActions INSERT
 *   - sendPolicyViolation
 */

import { and, eq } from 'drizzle-orm';
import type { DrizzleClient } from '@/server/db/client.js';
import { adminActions, deals } from '@/server/db/schema.js';
import * as vendorQueries from '@/server/db/queries/vendors.js';
import { sendPolicyViolation } from '@/server/services/email';
import { type ResendEnv } from '@/server/services/email';
import type { ViolationEffect } from './effects.js';
import { invalidateCatalog } from '@/server/cache/invalidate.js';

export interface ApplyEffectsContext {
  db: DrizzleClient;
  email: ResendEnv;
  /** Decrypted vendor email (caller provides via the workflow's deps.getVendorEmail). */
  vendorEmail: string | null;
  vendorBusinessName: string;
}

function assertNever(x: never): never {
  throw new Error(`Unhandled ViolationEffect kind: ${JSON.stringify(x)}`);
}

export async function applyEffects(
  ctx: ApplyEffectsContext,
  effects: ViolationEffect[],
): Promise<void> {
  const { db, email, vendorEmail, vendorBusinessName } = ctx;

  for (const effect of effects) {
    if (effect.kind === 'pause-vendor-deals') {
      await db
        .update(deals)
        .set({ dealState: 'PAUSED' })
        .where(and(eq(deals.vendorId, effect.vendorId), eq(deals.dealState, 'ACTIVE')));
      await invalidateCatalog(db, { scope: 'global' });
    }
  }

  for (const effect of effects) {
    if (effect.kind === 'set-account-state') {
      await vendorQueries.updateAccountState(db, effect.vendorId, effect.nextState);
    }
  }

  for (const effect of effects) {
    if (effect.kind === 'insert-admin-action') {
      await db.insert(adminActions).values({
        adminId: effect.adminId,
        targetType: 'VENDOR',
        targetId: effect.vendorId,
        action: effect.action,
        note: effect.note,
      });
    }
  }

  for (const effect of effects) {
    if (effect.kind === 'send-policy-email') {
      if (vendorEmail !== null) {
        await sendPolicyViolation(email, {
          to: vendorEmail,
          vendorName: vendorBusinessName,
          action: effect.action,
          reason: effect.reason,
          nextSteps: effect.nextSteps,
        });
      }
    }
  }

  for (const effect of effects) {
    switch (effect.kind) {
      case 'pause-vendor-deals':
      case 'set-account-state':
      case 'insert-admin-action':
      case 'send-policy-email':
        break;
      default:
        assertNever(effect);
    }
  }
}
