/**
 * Promo usage pure decider.
 *
 * PURITY CONTRACT (mirrors refund): no DB, env, Date.now(), fetch, queues,
 * emails, or payment-provider calls. The decider emits serializable effects;
 * apply-effects.ts owns DB writes and invalidation.
 *
 * Transition table:
 *   { usageReserved:false, redemptionFinalized:false } + promo_applied
 *     -> { usageReserved:true, redemptionFinalized:false }
 *     effects: [record-usage]
 *
 *   { usageReserved:true, redemptionFinalized:false } + promo_usage_recorded
 *     -> { usageReserved:true, redemptionFinalized:true }
 *     effects: [insert-redemption]
 *
 *   { usageReserved:true, redemptionFinalized:false } + promo_exhausted
 *     -> { usageReserved:false, redemptionFinalized:false }
 *     effects: [release-usage]
 *
 * Invalid states reject with INVALID_STATE. Preview remains outside this
 * machine because it has no usage mutation.
 */

import type { PromoEvent } from './events.js';
import type { PromoEffect } from './effects.js';

export interface PromoState {
  usageReserved: boolean;
  redemptionFinalized: boolean;
}

export type DecideResult =
  | { ok: true; nextState: PromoState; effects: PromoEffect[] }
  | { ok: false; error: 'INVALID_STATE'; message: string };

export function decide(ctx: PromoState, event: PromoEvent): DecideResult {
  switch (event.kind) {
    case 'promo_applied':
      if (ctx.usageReserved || ctx.redemptionFinalized) {
        return { ok: false, error: 'INVALID_STATE', message: 'Promo usage already reserved' };
      }
      return {
        ok: true,
        nextState: { usageReserved: true, redemptionFinalized: false },
        effects: [{ kind: 'record-usage', promoCodeId: event.promoCodeId, userId: event.userId }],
      };

    case 'promo_usage_recorded':
      if (!ctx.usageReserved || ctx.redemptionFinalized) {
        return { ok: false, error: 'INVALID_STATE', message: 'Promo usage not reserved' };
      }
      return {
        ok: true,
        nextState: { usageReserved: true, redemptionFinalized: true },
        effects: [
          {
            kind: 'insert-redemption',
            promoCodeId: event.promoCodeId,
            purchaseId: event.purchaseId,
            userId: event.userId,
            vendorId: event.vendorId,
            discountAgorot: event.discountAgorot,
            funder: event.funder,
            appliedToLines: event.appliedToLines,
          },
        ],
      };

    case 'promo_exhausted':
      if (!ctx.usageReserved || ctx.redemptionFinalized) {
        return { ok: false, error: 'INVALID_STATE', message: 'Promo usage cannot be released' };
      }
      return {
        ok: true,
        nextState: { usageReserved: false, redemptionFinalized: false },
        effects: [{ kind: 'release-usage', promoCodeId: event.promoCodeId, userId: event.userId }],
      };
  }
}
