import { prisma } from "@/lib/prisma";

type OrderRecord = Awaited<ReturnType<typeof prisma.order.findMany>>[number];

type StatusCount = {
  label: string;
  count: number;
  value: number;
};

type PeriodSummary = {
  key: "today" | "last7Days" | "last30Days" | "allTime";
  label: string;
  orderCount: number;
  grossSubmittedSales: number;
  paidSales: number;
  pendingSales: number;
  failedSales: number;
  refundedSales: number;
  supplierSharePaid: number;
  markupSharePaid: number;
  paidOrderCount: number;
  pendingOrderCount: number;
  failedOrderCount: number;
  refundedOrderCount: number;
  averagePaidOrderValue: number;
};

type RecentOrder = {
  id: string;
  orderNumber: string;
  customerName: string;
  grandTotal: number;
  supplierTotal: number;
  markupTotal: number;
  paymentStatus: string;
  fulfillmentStatus: string;
  createdAt: Date;
};

export type AdminReportingData = {
  periods: Record<PeriodSummary["key"], PeriodSummary>;
  paymentStatusCounts: StatusCount[];
  fulfillmentStatusCounts: StatusCount[];
  recentOrders: RecentOrder[];
};

const PAYMENT_STATUSES = ["PENDING", "PAID", "FAILED", "REFUNDED"] as const;

function startOfToday() {
  const now = new Date();
  return new Date(now.getFullYear(), now.getMonth(), now.getDate());
}

function startOfDaysAgo(daysAgo: number) {
  const start = startOfToday();
  start.setDate(start.getDate() - daysAgo);
  return start;
}

function sumByStatus(orders: OrderRecord[], status: string, value: (order: OrderRecord) => number) {
  return orders.reduce((sum, order) => sum + (order.paymentStatus === status ? value(order) : 0), 0);
}

function countByStatus(orders: OrderRecord[], status: string) {
  return orders.reduce((sum, order) => sum + (order.paymentStatus === status ? 1 : 0), 0);
}

function aggregatePeriod(key: PeriodSummary["key"], label: string, orders: OrderRecord[]): PeriodSummary {
  const grossSubmittedSales = orders.reduce((sum, order) => sum + Number(order.grandTotal), 0);
  const paidSales = sumByStatus(orders, "PAID", (order) => Number(order.grandTotal));
  const pendingSales = sumByStatus(orders, "PENDING", (order) => Number(order.grandTotal));
  const failedSales = sumByStatus(orders, "FAILED", (order) => Number(order.grandTotal));
  const refundedSales = sumByStatus(orders, "REFUNDED", (order) => Number(order.grandTotal));
  const supplierSharePaid = sumByStatus(orders, "PAID", (order) => Number(order.supplierTotal));
  const markupSharePaid = sumByStatus(orders, "PAID", (order) => Number(order.markupTotal));
  const paidOrderCount = countByStatus(orders, "PAID");
  const pendingOrderCount = countByStatus(orders, "PENDING");
  const failedOrderCount = countByStatus(orders, "FAILED");
  const refundedOrderCount = countByStatus(orders, "REFUNDED");

  return {
    key,
    label,
    orderCount: orders.length,
    grossSubmittedSales,
    paidSales,
    pendingSales,
    failedSales,
    refundedSales,
    supplierSharePaid,
    markupSharePaid,
    paidOrderCount,
    pendingOrderCount,
    failedOrderCount,
    refundedOrderCount,
    averagePaidOrderValue: paidOrderCount ? paidSales / paidOrderCount : 0
  };
}

function buildStatusCounts(
  orders: OrderRecord[],
  field: "paymentStatus" | "fulfillmentStatus",
  knownStatuses: readonly string[] = []
) {
  const counts = new Map<string, StatusCount>();

  for (const order of orders) {
    const rawLabel = order[field] || "OTHER";
    const label = rawLabel.trim() || "OTHER";
    const current = counts.get(label) || { label, count: 0, value: 0 };
    current.count += 1;
    current.value += Number(order.grandTotal);
    counts.set(label, current);
  }

  for (const status of knownStatuses) {
    if (!counts.has(status)) counts.set(status, { label: status, count: 0, value: 0 });
  }

  return Array.from(counts.values()).sort((a, b) => {
    const aKnown = knownStatuses.indexOf(a.label);
    const bKnown = knownStatuses.indexOf(b.label);
    if (aKnown !== -1 || bKnown !== -1) {
      if (aKnown === -1) return 1;
      if (bKnown === -1) return -1;
      return aKnown - bKnown;
    }
    return a.label.localeCompare(b.label);
  });
}

export async function getAdminReportingData(): Promise<AdminReportingData> {
  const orders = await prisma.order.findMany({
    orderBy: { createdAt: "desc" }
  });

  const todayStart = startOfToday();
  const last7Start = startOfDaysAgo(6);
  const last30Start = startOfDaysAgo(29);

  return {
    periods: {
      today: aggregatePeriod("today", "Today", orders.filter((order) => order.createdAt >= todayStart)),
      last7Days: aggregatePeriod("last7Days", "Last 7 Days", orders.filter((order) => order.createdAt >= last7Start)),
      last30Days: aggregatePeriod("last30Days", "Last 30 Days", orders.filter((order) => order.createdAt >= last30Start)),
      allTime: aggregatePeriod("allTime", "All Time", orders)
    },
    paymentStatusCounts: buildStatusCounts(orders, "paymentStatus", PAYMENT_STATUSES),
    fulfillmentStatusCounts: buildStatusCounts(orders, "fulfillmentStatus"),
    recentOrders: orders.slice(0, 8).map((order) => ({
      id: order.id,
      orderNumber: order.orderNumber,
      customerName: order.customerName,
      grandTotal: Number(order.grandTotal),
      supplierTotal: Number(order.supplierTotal),
      markupTotal: Number(order.markupTotal),
      paymentStatus: order.paymentStatus,
      fulfillmentStatus: order.fulfillmentStatus,
      createdAt: order.createdAt
    }))
  };
}
