export type TopProductSnapshot = {
  productId: string;
  name: string;
  quantity: number;
  revenue: number;
};

export type DailyReportSnapshot = {
  id: string;
  cafeId: string;
  branchId: string;
  date: string;
  totalRevenue: number;
  cashRevenue: number;
  cardRevenue: number;
  creditRevenue: number;
  totalOrders: number;
  avgOrderValue: number;
  totalVoids: number;
  voidAmount: number;
  totalExpenses: number;
  netIncome: number;
  topProducts: TopProductSnapshot[];
  generatedAt: string;
};

export type DateRangePreset = "7d" | "30d" | "90d" | "custom";

export type ReportRange = {
  from: string;
  to: string;
  preset: DateRangePreset;
};

export function isoTodayTehran(): string {
  return new Date().toLocaleDateString("en-CA", { timeZone: "Asia/Tehran" });
}

export function addDaysIso(iso: string, days: number): string {
  const d = new Date(`${iso}T12:00:00`);
  d.setDate(d.getDate() + days);
  return d.toLocaleDateString("en-CA", { timeZone: "Asia/Tehran" });
}

export function daysBetweenInclusive(from: string, to: string): number {
  const start = new Date(`${from}T12:00:00`).getTime();
  const end = new Date(`${to}T12:00:00`).getTime();
  return Math.max(1, Math.round((end - start) / 86_400_000) + 1);
}

export function buildRangeFromPreset(preset: DateRangePreset): ReportRange {
  const to = isoTodayTehran();
  if (preset === "7d") return { from: addDaysIso(to, -6), to, preset };
  if (preset === "30d") return { from: addDaysIso(to, -29), to, preset };
  if (preset === "90d") return { from: addDaysIso(to, -89), to, preset };
  return { from: addDaysIso(to, -6), to, preset: "7d" };
}

export function previousPeriod(from: string, to: string): { from: string; to: string } {
  const len = daysBetweenInclusive(from, to);
  return {
    from: addDaysIso(from, -len),
    to: addDaysIso(from, -1),
  };
}

export function formatJalaliLabel(isoDate: string, locale: string): string {
  try {
    return new Intl.DateTimeFormat(locale === "fa" ? "fa-IR" : locale === "ar" ? "ar-SA" : "en-GB", {
      calendar: "persian",
      month: "short",
      day: "numeric",
      timeZone: "Asia/Tehran",
    }).format(new Date(`${isoDate}T12:00:00`));
  } catch {
    return isoDate;
  }
}

export function percentChange(current: number, previous: number): number | null {
  if (previous === 0) return current === 0 ? 0 : 100;
  return ((current - previous) / previous) * 100;
}

export type RangeTotals = {
  totalRevenue: number;
  totalOrders: number;
  avgOrderValue: number;
  netIncome: number;
  totalExpenses: number;
  cashRevenue: number;
  cardRevenue: number;
  creditRevenue: number;
};

export function sumSnapshots(rows: DailyReportSnapshot[]): RangeTotals {
  const totalOrders = rows.reduce((s, r) => s + r.totalOrders, 0);
  const totalRevenue = rows.reduce((s, r) => s + r.totalRevenue, 0);
  return {
    totalRevenue,
    totalOrders,
    avgOrderValue: totalOrders > 0 ? totalRevenue / totalOrders : 0,
    netIncome: rows.reduce((s, r) => s + r.netIncome, 0),
    totalExpenses: rows.reduce((s, r) => s + r.totalExpenses, 0),
    cashRevenue: rows.reduce((s, r) => s + r.cashRevenue, 0),
    cardRevenue: rows.reduce((s, r) => s + r.cardRevenue, 0),
    creditRevenue: rows.reduce((s, r) => s + r.creditRevenue, 0),
  };
}

export function aggregateByDate(rows: DailyReportSnapshot[]): DailyReportSnapshot[] {
  const map = new Map<string, DailyReportSnapshot>();
  for (const r of rows) {
    const existing = map.get(r.date);
    if (!existing) {
      map.set(r.date, { ...r, branchId: "", topProducts: [...r.topProducts] });
      continue;
    }
    existing.totalRevenue += r.totalRevenue;
    existing.cashRevenue += r.cashRevenue;
    existing.cardRevenue += r.cardRevenue;
    existing.creditRevenue += r.creditRevenue;
    existing.totalOrders += r.totalOrders;
    existing.totalVoids += r.totalVoids;
    existing.voidAmount += r.voidAmount;
    existing.totalExpenses += r.totalExpenses;
    existing.netIncome += r.netIncome;
    existing.totalExpenses += r.totalExpenses;
    existing.topProducts = mergeTopProducts(existing.topProducts, r.topProducts);
  }
  const merged = Array.from(map.values());
  for (const m of merged) {
    m.avgOrderValue = m.totalOrders > 0 ? m.totalRevenue / m.totalOrders : 0;
  }
  return merged.sort((a, b) => a.date.localeCompare(b.date));
}

export function mergeTopProducts(
  a: TopProductSnapshot[],
  b: TopProductSnapshot[]
): TopProductSnapshot[] {
  const map = new Map<string, TopProductSnapshot>();
  for (const p of [...a, ...b]) {
    const cur = map.get(p.productId);
    if (!cur) {
      map.set(p.productId, { ...p });
      continue;
    }
    cur.quantity += p.quantity;
    cur.revenue += p.revenue;
  }
  return Array.from(map.values()).sort((x, y) => y.revenue - x.revenue);
}

export function topProductsFromRange(rows: DailyReportSnapshot[], take = 10): TopProductSnapshot[] {
  return mergeTopProducts([], rows.flatMap((r) => r.topProducts)).slice(0, take);
}

export function revenueChartPoints(
  rows: DailyReportSnapshot[],
  locale: string,
  rtl: boolean
) {
  const sorted = [...rows].sort((a, b) => a.date.localeCompare(b.date));
  const points = sorted.map((r) => ({
    date: r.date,
    label: formatJalaliLabel(r.date, locale),
    revenue: r.totalRevenue,
  }));
  return rtl ? [...points].reverse() : points;
}

export function branchComparisonPoints(
  rows: DailyReportSnapshot[],
  branches: { id: string; name: string }[],
  locale: string,
  rtl: boolean
) {
  const dates = Array.from(new Set(rows.map((r) => r.date))).sort();
  const points = dates.map((date) => {
    const entry: Record<string, string | number> = {
      date,
      label: formatJalaliLabel(date, locale),
    };
    for (const b of branches) {
      const row = rows.find((r) => r.date === date && r.branchId === b.id);
      entry[b.id] = row?.totalRevenue ?? 0;
    }
    return entry;
  });
  return rtl ? [...points].reverse() : points;
}

const CHART_COLORS = ["#0F6E56", "#0C447C", "#BA7517", "#6366f1", "#ec4899", "#14b8a6"];

export function chartColor(index: number): string {
  return CHART_COLORS[index % CHART_COLORS.length]!;
}

export function downloadReportsCsv(
  rows: DailyReportSnapshot[],
  branchNames: Map<string, string>,
  headers: {
    date: string;
    branch: string;
    totalRevenue: string;
    totalOrders: string;
    avgOrderValue: string;
    cashRevenue: string;
    cardRevenue: string;
    creditRevenue: string;
    netIncome: string;
    totalVoids: string;
    voidAmount: string;
    totalExpenses: string;
  },
  filename: string
) {
  const cols = [
    headers.date,
    headers.branch,
    headers.totalRevenue,
    headers.totalOrders,
    headers.avgOrderValue,
    headers.cashRevenue,
    headers.cardRevenue,
    headers.creditRevenue,
    headers.netIncome,
    headers.totalVoids,
    headers.voidAmount,
    headers.totalExpenses,
  ];
  const lines = rows.map((r) =>
    [
      r.date,
      branchNames.get(r.branchId) ?? r.branchId,
      r.totalRevenue,
      r.totalOrders,
      r.avgOrderValue,
      r.cashRevenue,
      r.cardRevenue,
      r.creditRevenue,
      r.netIncome,
      r.totalVoids,
      r.voidAmount,
      r.totalExpenses,
    ].join(",")
  );
  const bom = "\uFEFF";
  const csv = bom + [cols.join(","), ...lines].join("\n");
  const blob = new Blob([csv], { type: "text/csv;charset=utf-8;" });
  const url = URL.createObjectURL(blob);
  const a = document.createElement("a");
  a.href = url;
  a.download = filename;
  a.click();
  URL.revokeObjectURL(url);
}
