export function buildDailyTokenGrid(buckets, days = 30, now = new Date()) {
  const values = new Map((Array.isArray(buckets) ? buckets : []).map((bucket) => [bucket.startDate, bucket.tokens]));
  const peak = Math.max(0, ...values.values().filter(Number.isFinite));
  const end = new Date(now.getFullYear(), now.getMonth(), now.getDate());
  return Array.from({ length: days }, (_, index) => {
    const date = new Date(end);
    date.setDate(end.getDate() - (days - index - 1));
    const key = localDateKey(date);
    const tokens = Number.isFinite(values.get(key)) ? values.get(key) : null;
    return { date: key, tokens, level: tokenLevel(tokens, peak) };
  });
}

export function buildTokenMonthLabels(days) {
  if (!Array.isArray(days) || days.length < 2) return [];
  const columnCount = Math.ceil(days.length / 7);
  return days.flatMap((day, index) => {
    if (!day?.date?.endsWith("-01")) return [];
    return [{
      date: day.date,
      position: Math.floor(index / 7) / Math.max(1, columnCount - 1)
    }];
  });
}

export function buildTokenPeriodGrid(days, period = "daily") {
  if (!Array.isArray(days) || period === "daily") return Array.isArray(days) ? days : [];
  const weeklyGroups = groupByWeek(days);
  const groups = period === "cumulative" ? accumulateGroups(weeklyGroups) : weeklyGroups;
  const peak = Math.max(0, ...groups.map(({ tokens }) => tokens).filter(Number.isFinite));
  return groups.flatMap((group) => buildStackedPeriodBar(group, peak));
}

export function tokenLevel(tokens, peak) {
  if (!Number.isFinite(tokens)) return 0;
  if (!Number.isFinite(peak) || peak <= 0) return 1;
  const ratio = tokens / peak;
  if (ratio <= 0.25) return 1;
  if (ratio <= 0.5) return 2;
  if (ratio <= 0.75) return 3;
  return 4;
}

function localDateKey(date) {
  return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}-${String(date.getDate()).padStart(2, "0")}`;
}

function groupByWeek(days) {
  const groups = [];
  for (let index = 0; index < days.length; index += 7) groups.push(summarizeDays(days.slice(index, index + 7)));
  return groups;
}

function summarizeDays(days) {
  const values = days.map(({ tokens }) => tokens).filter(Number.isFinite);
  return { days, tokens: values.length ? values.reduce((sum, value) => sum + value, 0) : null };
}

function accumulateGroups(groups) {
  let total = 0;
  let hasUsage = false;
  return groups.map((group) => {
    if (Number.isFinite(group.tokens)) {
      total += group.tokens;
      hasUsage = true;
    }
    return { ...group, tokens: hasUsage ? total : null };
  });
}

function buildStackedPeriodBar(group, peak) {
  const ratio = Number.isFinite(group.tokens) && peak > 0 ? group.tokens / peak : 0;
  const filledSlots = group.tokens > 0 ? Math.max(1, Math.min(7, Math.ceil(ratio * 7))) : 0;
  const periodStart = group.days[0]?.date;
  const periodEnd = group.days.at(-1)?.date;
  return Array.from({ length: 7 }, (_, index) => ({
    date: periodStart,
    key: `${periodStart}:${index}`,
    tokens: group.tokens,
    periodStart,
    periodEnd,
    level: index >= 7 - filledSlots ? 4 : 0
  }));
}
