import type { ReferralEvent, ReferralStatus } from './events.js';
import type { ReferralEffect } from './effects.js';

export type ReferralCtxId = string & { readonly __brand: 'ReferralCtxId' };

export const asReferralCtxId = (value: string): ReferralCtxId => value as ReferralCtxId;

export interface ReferralState {
  status: ReferralStatus;
  quarantined: boolean;
}

export interface ReferralContext extends ReferralState {
  ctxId: ReferralCtxId;
}

export type DecideResult =
  | { ok: true; nextState: ReferralState; effects: ReferralEffect[] }
  | { ok: false; error: 'INVALID_STATE'; ctxId: ReferralCtxId; message: string };

export function decide(ctx: ReferralContext, event: ReferralEvent): DecideResult {
  switch (event.kind) {
    case 'fraud_blocked':
      if (ctx.quarantined) {
        return {
          ok: false,
          error: 'INVALID_STATE',
          ctxId: ctx.ctxId,
          message: 'Referral already quarantined',
        };
      }
      return {
        ok: true,
        nextState: { status: ctx.status, quarantined: true },
        effects: [
          {
            kind: 'write-zero-commission-audit',
            referralId: event.referralId,
            referrerUserId: event.referrerUserId,
            purchaseId: event.purchaseId,
            sourceType: event.sourceType,
            memo: 'fraud:block',
            at: event.at,
          },
          { kind: 'set-quarantined-at', referralId: event.referralId, at: event.at },
        ],
      };

    case 'fraud_held':
      if (ctx.quarantined) {
        return {
          ok: false,
          error: 'INVALID_STATE',
          ctxId: ctx.ctxId,
          message: 'Referral already quarantined',
        };
      }
      return {
        ok: true,
        nextState: { status: ctx.status, quarantined: true },
        effects: [{ kind: 'set-quarantined-at', referralId: event.referralId, at: event.at }],
      };

    case 'earn_qualified':
      if (ctx.quarantined || ctx.status === 'rejected' || ctx.status === 'quarantined') {
        return {
          ok: false,
          error: 'INVALID_STATE',
          ctxId: ctx.ctxId,
          message: 'Referral cannot earn',
        };
      }
      if (ctx.status === 'qualified') {
        return {
          ok: true,
          nextState: { status: 'qualified', quarantined: false },
          effects: [
            {
              kind: 'accrue-affiliate-commission',
              refereeUserId: event.refereeUserId,
              purchaseId: event.purchaseId,
              amountPaidAgorot: event.amountPaidAgorot,
              orderLineId: event.orderLineId,
            },
          ],
        };
      }
      return {
        ok: true,
        nextState: { status: 'qualified', quarantined: false },
        effects: [
          {
            kind: 'qualify-referee-first-paid',
            refereeUserId: event.refereeUserId,
            purchaseId: event.purchaseId,
            amountPaidAgorot: event.amountPaidAgorot,
          },
          {
            kind: 'accrue-affiliate-commission',
            refereeUserId: event.refereeUserId,
            purchaseId: event.purchaseId,
            amountPaidAgorot: event.amountPaidAgorot,
            orderLineId: event.orderLineId,
          },
        ],
      };

    case 'qualified_notification_requested':
      if (ctx.quarantined || ctx.status !== 'qualified') {
        return {
          ok: false,
          error: 'INVALID_STATE',
          ctxId: ctx.ctxId,
          message: 'Referral cannot notify',
        };
      }
      return {
        ok: true,
        nextState: { status: ctx.status, quarantined: ctx.quarantined },
        effects: [
          {
            kind: 'enqueue-qualified-notification',
            referralId: event.referralId,
            referrerUserId: event.referrerUserId,
            refereeUserId: event.refereeUserId,
            purchaseId: event.purchaseId,
            rewardAgorot: event.rewardAgorot,
          },
        ],
      };

    case 'clawback_executed':
      return {
        ok: true,
        nextState: { status: ctx.status, quarantined: ctx.quarantined },
        effects: [
          {
            kind: 'execute-clawback',
            purchaseId: event.purchaseId,
            refundEventId: event.refundEventId,
            refundFraction: event.refundFraction,
          },
        ],
      };
  }
}
