import { prisma } from "./prisma";

export async function buildAnalysis(filters: {
  from?: Date;
  to?: Date;
  accountType?: string;
  region?: string;
  categoryId?: string;
}) {
  const orderWhere = {
    createdAt: {
      gte: filters.from,
      lte: filters.to,
    },
    customer: {
      accountType: filters.accountType || undefined,
      region: filters.region || undefined,
    },
    status: { not: "REJECTED" },
  };

  const orders = await prisma.order.findMany({
    where: orderWhere,
    include: {
      customer: true,
      lines: { include: { product: { include: { category: true } } } },
      payments: true,
    },
  });

  const filteredOrders = orders.filter((order) =>
    filters.categoryId
      ? order.lines.some((line) => line.product.categoryId === filters.categoryId)
      : true,
  );

  const revenue = filteredOrders.reduce((sum, order) => sum + order.total, 0);
  const quantities = filteredOrders.reduce(
    (sum, order) => sum + order.lines.reduce((inner, line) => inner + line.quantity, 0),
    0,
  );
  const collected = filteredOrders.reduce(
    (sum, order) => sum + order.payments.reduce((inner, payment) => inner + payment.amount, 0),
    0,
  );

  const productMap = new Map<string, { name: string; qty: number; revenue: number }>();
  const pairMap = new Map<string, number>();
  const customerMap = new Map<
    string,
    { name: string; revenue: number; orders: number; late: number; lastOrder: Date }
  >();

  for (const order of filteredOrders) {
    const name = `${order.customer.firstName} ${order.customer.lastName}`;
    const existing = customerMap.get(order.customerId) ?? {
      name,
      revenue: 0,
      orders: 0,
      late: 0,
      lastOrder: order.createdAt,
    };
    existing.revenue += order.total;
    existing.orders += 1;
    if (order.createdAt > existing.lastOrder) existing.lastOrder = order.createdAt;
    if (["DELIVERED", "PARTIAL"].includes(order.status) && order.payments.length === 0) existing.late += 1;
    customerMap.set(order.customerId, existing);

    const productIds = order.lines.map((line) => line.product.name);
    for (const line of order.lines) {
      if (filters.categoryId && line.product.categoryId !== filters.categoryId) continue;
      const row = productMap.get(line.productId) ?? { name: line.product.name, qty: 0, revenue: 0 };
      row.qty += line.quantity;
      row.revenue += line.quantity * line.unitPrice;
      productMap.set(line.productId, row);
    }
    for (let i = 0; i < productIds.length; i++) {
      for (let j = i + 1; j < productIds.length; j++) {
        const key = [productIds[i], productIds[j]].sort().join(" + ");
        pairMap.set(key, (pairMap.get(key) ?? 0) + 1);
      }
    }
  }

  const products = [...productMap.values()].sort((a, b) => b.qty - a.qty);
  const customers = [...customerMap.values()].sort((a, b) => b.revenue - a.revenue);
  const now = Date.now();
  const inactiveDays = 21;

  const sumBy = (key: (order: (typeof filteredOrders)[number]) => string) =>
    [...filteredOrders.reduce((map, order) => map.set(key(order), (map.get(key(order)) ?? 0) + order.total), new Map<string, number>())]
      .map(([k, value]) => ({ key: k, value }))
      .sort((a, b) => b.value - a.value);

  return {
    summary: {
      revenue,
      orders: filteredOrders.length,
      quantities,
      collected,
    },
    bestProducts: products.slice(0, 6),
    worstProducts: products.slice(-6).reverse(),
    topCustomers: customers.slice(0, 6),
    declining: customers.filter((c) => now - c.lastOrder.getTime() > 7 * 86400000 && c.orders <= 2),
    inactive: customers.filter((c) => now - c.lastOrder.getTime() > inactiveDays * 86400000),
    byRegion: sumBy((order) => order.region),
    byAccountType: sumBy((order) => order.customer.accountType),
    pairs: [...pairMap.entries()]
      .sort((a, b) => b[1] - a[1])
      .slice(0, 6)
      .map(([pair, count]) => ({ pair, count })),
    segments: {
      top: customers.filter((c) => c.revenue >= (customers[0]?.revenue ?? 0) * 0.6).map((c) => c.name),
      declining: customers.filter((c) => now - c.lastOrder.getTime() > 7 * 86400000).map((c) => c.name),
      inactive: customers.filter((c) => now - c.lastOrder.getTime() > inactiveDays * 86400000).map((c) => c.name),
    },
  };
}
