import {
  addDays,
  differenceInCalendarDays,
  format,
  isToday,
  isTomorrow,
  isYesterday,
  isPast,
  startOfDay,
} from "date-fns";

export function formatDue(iso: string | null | undefined): string {
  if (!iso) return "No date";
  const d = new Date(iso);
  if (Number.isNaN(d.getTime())) return "No date";
  if (isToday(d)) return `Today ${format(d, "HH:mm")}`;
  if (isTomorrow(d)) return `Tomorrow ${format(d, "HH:mm")}`;
  if (isYesterday(d)) return `Yesterday ${format(d, "HH:mm")}`;
  return format(d, "d MMM yyyy HH:mm");
}

export function formatDay(iso: string | null | undefined): string {
  if (!iso) return "—";
  const d = new Date(iso);
  if (Number.isNaN(d.getTime())) return "—";
  if (isToday(d)) return "Today";
  if (isTomorrow(d)) return "Tomorrow";
  return format(d, "d MMM");
}

export function dueKind(iso: string | null | undefined): "overdue" | "today" | "soon" | "later" | "none" {
  if (!iso) return "none";
  const d = new Date(iso);
  if (Number.isNaN(d.getTime())) return "none";
  const start = startOfDay(new Date());
  if (isPast(d) && !isToday(d)) return "overdue";
  if (isToday(d)) return "today";
  const diff = (startOfDay(d).getTime() - start.getTime()) / 86400000;
  if (diff <= 3) return "soon";
  return "later";
}

export function toDatetimeLocal(iso: string | null | undefined): string {
  if (!iso) return "";
  const d = new Date(iso);
  if (Number.isNaN(d.getTime())) return "";
  const pad = (n: number) => String(n).padStart(2, "0");
  return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}`;
}

export function fromDatetimeLocal(value: string): string | null {
  if (!value) return null;
  const d = new Date(value);
  if (Number.isNaN(d.getTime())) return null;
  return d.toISOString();
}

/** Follow-ups are days, not moments: they are stored at 09:00 local time. */
export function followUpIn(days: number, from = new Date()): string {
  const d = addDays(startOfDay(from), days);
  d.setHours(9, 0, 0, 0);
  return d.toISOString();
}

export function toDateInput(iso: string | null | undefined): string {
  if (!iso) return "";
  const d = new Date(iso);
  if (Number.isNaN(d.getTime())) return "";
  return format(d, "yyyy-MM-dd");
}

export function fromDateInput(value: string): string | null {
  if (!value) return null;
  const [y, m, day] = value.split("-").map(Number);
  if (!y || !m || !day) return null;
  return new Date(y, m - 1, day, 9, 0, 0, 0).toISOString();
}

/** "today", "1 day", "12 days", "3 weeks" — how long something has been waiting. */
export function waitingFor(since: string): string {
  const d = new Date(since);
  if (Number.isNaN(d.getTime())) return "";
  const days = differenceInCalendarDays(new Date(), d);
  if (days <= 0) return "today";
  if (days === 1) return "1 day";
  if (days < 21) return `${days} days`;
  return `${Math.round(days / 7)} weeks`;
}

/** A follow-up is due once its day has arrived, and never for received items. */
export function followUpDue(item: { done: boolean; followUpAt: string | null }): boolean {
  if (item.done || !item.followUpAt) return false;
  const k = dueKind(item.followUpAt);
  return k === "overdue" || k === "today";
}
