/**
 * computeCacheTTL
 *
 * Computes the Redis TTL (in milliseconds) for an opportunity record based on
 * its activity dates and closed state.
 *
 * Rules (highest priority first):
 *  1a. Closed > 30 days ago  → null (do not cache)
 *  1b. Closed ≤ 30 days ago  → TTL_LOW_ACTIVITY (15 min)
 *  2.  High activity (≤ 5 days) → TTL_HIGH_ACTIVITY (30 s)
 *  3.  Moderate activity (6–14 days) → TTL_MODERATE_ACTIVITY (60 s)
 *  4.  Everything else → TTL_LOW_ACTIVITY (15 min)
 */

export const TTL_HIGH_ACTIVITY = 30_000;     // 30 seconds
export const TTL_MODERATE_ACTIVITY = 60_000; // 60 seconds
export const TTL_LOW_ACTIVITY = 900_000;     // 15 minutes

export interface ComputeCacheTTLInput {
  closedFlag: boolean;
  closedDate: Date | null;
  expectedCloseDate: Date | null;
  lastUpdated: Date | null;
  /** Override "now" for deterministic tests. Defaults to `new Date()`. */
  now?: Date;
}

const DAY_MS = 24 * 60 * 60 * 1000;

/** Returns the absolute age in milliseconds between `date` and `now`. */
function ageMs(date: Date, now: Date): number {
  return Math.abs(now.getTime() - date.getTime());
}

export function computeCacheTTL(input: ComputeCacheTTLInput): number | null {
  const now = input.now ?? new Date();

  // Rule 1 — closed opportunities
  if (input.closedFlag) {
    if (!input.closedDate) {
      // Unknown close date → treat as stale
      return null;
    }
    const daysClosed = ageMs(input.closedDate, now) / DAY_MS;
    if (daysClosed > 30) {
      return null;
    }
    return TTL_LOW_ACTIVITY;
  }

  // Helper: minimum absolute distance (in ms) of a date from now
  const dates = [input.lastUpdated, input.expectedCloseDate].filter(
    (d): d is Date => d !== null
  );

  if (dates.length === 0) {
    return TTL_LOW_ACTIVITY;
  }

  const minDeltaMs = Math.min(...dates.map((d) => ageMs(d, now)));
  const minDeltaDays = minDeltaMs / DAY_MS;

  if (minDeltaDays <= 5) {
    return TTL_HIGH_ACTIVITY;
  }
  if (minDeltaDays <= 14) {
    return TTL_MODERATE_ACTIVITY;
  }
  return TTL_LOW_ACTIVITY;
}
