export type RangeKey = "7" | "30" | "90" | "custom";

export interface DateRange {
  start: string;
  end: string;
}

export interface ResolvedRange {
  rangeKey: RangeKey;
  current: DateRange;
  previous: DateRange;
}

function toIso(date: Date) {
  return date.toISOString().slice(0, 10);
}

/**
 * Resolves the {7,30,90,custom} segmented selector into a current date range
 * plus the immediately-preceding range of equal length (for the "vs periode
 * lalu" delta on KPI cards). Defaults to the last 30 days.
 */
export function resolveDateRange(params: {
  range?: string;
  start?: string;
  end?: string;
}): ResolvedRange {
  const today = new Date();
  let start: Date;
  let end: Date;
  let rangeKey: RangeKey;

  if (params.range === "custom" && params.start && params.end) {
    rangeKey = "custom";
    start = new Date(params.start);
    end = new Date(params.end);
  } else if (params.range === "7" || params.range === "90") {
    rangeKey = params.range;
    end = today;
    start = new Date(today);
    start.setDate(start.getDate() - (Number(rangeKey) - 1));
  } else {
    rangeKey = "30";
    end = today;
    start = new Date(today);
    start.setDate(start.getDate() - 29);
  }

  const days = Math.max(1, Math.round((end.getTime() - start.getTime()) / 86_400_000) + 1);
  const previousEnd = new Date(start);
  previousEnd.setDate(previousEnd.getDate() - 1);
  const previousStart = new Date(previousEnd);
  previousStart.setDate(previousStart.getDate() - (days - 1));

  return {
    rangeKey,
    current: { start: toIso(start), end: toIso(end) },
    previous: { start: toIso(previousStart), end: toIso(previousEnd) },
  };
}

export type DeltaDirection = "up" | "down" | "flat";

export interface Delta {
  direction: DeltaDirection;
  /** Percent change, absolute value. `null` when not meaningfully computable (e.g. 0 -> 0, or 0 -> N). */
  percent: number | null;
}

/** Percent change of `current` vs `previous`, for the KPI delta badges. */
export function computeDelta(current: number, previous: number): Delta {
  if (previous === 0) {
    if (current === 0) return { direction: "flat", percent: null };
    return { direction: "up", percent: null };
  }
  const change = ((current - previous) / previous) * 100;
  if (Math.abs(change) < 0.5) return { direction: "flat", percent: 0 };
  return { direction: change > 0 ? "up" : "down", percent: Math.abs(change) };
}

/**
 * The revenue-analytics endpoint only returns days that actually had
 * revenue (sparse series) — a single day of data renders as a lone spike
 * with no baseline on a line/area chart. Zero-fills every day in the
 * selected range so the chart always has a proper continuous series; this
 * is a presentation-only transform, it doesn't change what data exists.
 */
export function fillDailySeries(
  daily: { date: string; revenue: string }[],
  range: DateRange,
): { date: string; revenue: string }[] {
  const byDate = new Map(daily.map((d) => [d.date, d.revenue]));
  const filled: { date: string; revenue: string }[] = [];
  const cursor = new Date(range.start);
  const end = new Date(range.end);
  while (cursor <= end) {
    const iso = toIso(cursor);
    filled.push({ date: iso, revenue: byDate.get(iso) ?? "0" });
    cursor.setDate(cursor.getDate() + 1);
  }
  return filled;
}
