import type { PromoCode, PromoRejectReason, PromoRules, ResolvedCart } from './types.js';

export interface ValidateCtx {
  now: Date;
  user: { id: string; isClubMember: boolean };
  cart: ResolvedCart;
  userPriorPurchaseCount: number;
  userRedemptionCount: number;
  /** Platform fee % for feasibility gate; defaults to 10 when omitted. */
  platformFeePct?: number;
}

export type ValidateResult = { ok: true } | { ok: false; reason: PromoRejectReason };

export function validatePromo(code: PromoCode, ctx: ValidateCtx): ValidateResult {
  if (code.status !== 'active') return { ok: false, reason: 'INACTIVE' };

  if (code.validFrom && ctx.now < code.validFrom) return { ok: false, reason: 'NOT_YET_VALID' };
  if (code.validUntil && ctx.now > code.validUntil) return { ok: false, reason: 'EXPIRED' };

  if (code.totalCap != null && code.redemptionCount >= code.totalCap) {
    return { ok: false, reason: 'OUT_OF_QUOTA' };
  }
  if (code.perUserCap != null && ctx.userRedemptionCount >= code.perUserCap) {
    return { ok: false, reason: 'USER_QUOTA_EXCEEDED' };
  }

  if (code.minSubtotal != null && ctx.cart.totalAgorot < code.minSubtotal) {
    return { ok: false, reason: 'SUBTOTAL_TOO_LOW' };
  }
  if (code.maxSubtotal != null && ctx.cart.totalAgorot > code.maxSubtotal) {
    return { ok: false, reason: 'SUBTOTAL_TOO_HIGH' };
  }

  const rules = code.rulesJson as PromoRules;
  if (!scopeMatchesCart(rules.scope, ctx.cart)) {
    return { ok: false, reason: 'SCOPE_MISMATCH' };
  }

  const elig = rules.eligibility;
  if (elig.firstPurchaseOnly && ctx.userPriorPurchaseCount > 0) {
    return { ok: false, reason: 'NEW_USERS_ONLY' };
  }
  if (elig.clubOnly && !ctx.user.isClubMember) {
    return { ok: false, reason: 'CLUB_ONLY' };
  }
  if (
    elig.userAllowlist &&
    elig.userAllowlist.length > 0 &&
    !elig.userAllowlist.includes(ctx.user.id)
  ) {
    return { ok: false, reason: 'NOT_IN_ALLOWLIST' };
  }

  return { ok: true };
}

function scopeMatchesCart(scope: PromoRules['scope'], cart: ResolvedCart): boolean {
  switch (scope.kind) {
    case 'all':
      return cart.lines.length > 0;
    case 'deals':
      return cart.lines.some((l) => scope.dealIds.includes(l.dealId));
    case 'categories':
      return cart.lines.some((l) => l.categoryIds.some((c) => scope.categoryIds.includes(c)));
    case 'tags':
      return cart.lines.some((l) => l.tagIds.some((t) => scope.tagIds.includes(t)));
    case 'vendor':
      return cart.lines.some((l) => l.vendorId === scope.vendorId);
  }
}
