export enum PaymentStatus {
  PENDING = 'pending',
  PARTIAL = 'partial',
  PAID = 'paid',
  OVERDUE = 'overdue',
}

export enum PaymentMethod {
  CASH = 'cash',
  CARD = 'card',
  UPI = 'upi',
  NEFT = 'neft',
  RTGS = 'rtgs',
  IMPS = 'imps',
  CHEQUE = 'cheque',
  OTHER = 'other',
}

/** Whole-currency slack: float noise and "1 rupee left" UX */
const AMOUNT_EPS = 1;

/**
 * True when the stage is fully settled.
 * Supports two stored shapes:
 * - **Remaining balance**: `dueAmount` shrinks as entries are added → done when `dueAmount` ≈ 0.
 * - **Gross installment**: `dueAmount` stays the line total → done when `paid` ≈ `dueAmount`.
 * We must not use plain `paid >= dueAmount` alone (remaining 10k vs paid 40k would wrongly read as paid).
 */
export const isStageBalanceFullyPaid = (
  paid: number,
  dueAmount: number,
): boolean => {
  const d = Number.isFinite(Number(dueAmount)) ? Number(dueAmount) : 0;
  const p = Number.isFinite(Number(paid)) ? Number(paid) : 0;

  if (d <= AMOUNT_EPS) return true;

  if (p >= d - AMOUNT_EPS && p <= d + AMOUNT_EPS) return true;

  return false;
};

/**
 * Calculate stage status.
 * `dueAmount` is usually **remaining** after payments, but may match **gross** due on some timelines.
 */
export const calculateStageStatus = (
  paid: number,
  dueAmount: number,
  dueDate: Date,
): string => {
  const d = Number.isFinite(Number(dueAmount)) ? Number(dueAmount) : 0;
  const p = Number.isFinite(Number(paid)) ? Number(paid) : 0;

  if (isStageBalanceFullyPaid(p, d)) return 'paid';

  if (p > 0) return 'partial';

  return new Date() > dueDate ? 'overdue' : 'pending';
};

/**
 * Calculate overall payment status — all stages must read as fully paid.
 */
export const calculateOverallStatus = (stages): string => {
  if (!stages?.length) return 'pending';

  const totalPaid = stages.reduce(
    (sum, stage) => sum + Number(stage?.paid ?? 0),
    0,
  );

  const allPaid = stages.every((stage) =>
    isStageBalanceFullyPaid(
      Number(stage?.paid ?? 0),
      Number(stage?.dueAmount ?? 0),
    ),
  );

  if (allPaid) return 'paid';

  if (totalPaid === 0) {
    const hasOverdue = stages.some(
      (stage) =>
        Number(stage?.paid ?? 0) === 0 &&
        stage?.dueDate &&
        new Date() > new Date(stage.dueDate),
    );
    return hasOverdue ? 'overdue' : 'pending';
  }

  const hasOverdue = stages.some(
    (stage) =>
      Number(stage?.paid ?? 0) === 0 &&
      stage?.dueDate &&
      new Date() > new Date(stage.dueDate),
  );

  return hasOverdue && totalPaid === 0 ? 'overdue' : 'partial';
};
