import { prisma } from "./prisma";
import type { I18n } from "./i18n/core";

export type DriverEvent = {
  id: string;
  at: Date;
  kind: "round" | "stop" | "order" | "payment" | "load" | "return" | "staff";
  title: string;
  detail: string;
  href?: string;
};

export type RoundActivity = {
  roundId: string;
  date: Date;
  kind: string;
  region: string;
  status: string;
  truck: string;
  events: DriverEvent[];
};

function customerName(customer: { firstName: string; lastName: string }) {
  return `${customer.firstName} ${customer.lastName}`;
}

export async function driverRoundActivity(agentId: string, i18n: I18n): Promise<{ recent: DriverEvent[]; rounds: RoundActivity[] }> {
  const { t, label, money } = i18n;
  const [rounds, payments, remittances] = await Promise.all([
    prisma.deliveryRound.findMany({
      where: { agentId },
      include: {
        vehicle: true,
        stops: {
          orderBy: { sequence: "asc" },
          include: {
            order: { include: { customer: true, lines: { include: { product: true } }, payments: true } },
          },
        },
      },
      orderBy: { date: "desc" },
    }),
    prisma.payment.findMany({
      where: { agentId },
      include: { customer: true, order: true },
      orderBy: { createdAt: "desc" },
    }),
    prisma.cashRemittance.findMany({
      where: { agentId },
      orderBy: { date: "desc" },
    }),
  ]);

  const roundIds = rounds.map((round) => round.id);
  type LoadRow = { id: string; roundId: string; loadedQty: number; returnedQty: number; product: { name: string } };
  type FieldRow = {
    id: string;
    sourceRoundId: string | null;
    createdAt: Date;
    reference: string;
    settlement: string;
    total: number;
    paidAmount: number;
    customer: { firstName: string; lastName: string };
    lines: Array<{ quantity: number; product: { name: string } }>;
  };
  let loads: LoadRow[] = [];
  let fieldOrders: FieldRow[] = [];
  if (roundIds.length) {
    try {
      loads = await prisma.roundLoad.findMany({
        where: { roundId: { in: roundIds } },
        include: { product: true },
      });
    } catch {
      loads = [];
    }
    try {
      fieldOrders = await prisma.order.findMany({
        where: { sourceRoundId: { in: roundIds } },
        include: { customer: true, lines: { include: { product: true } } },
      });
    } catch {
      fieldOrders = [];
    }
  }
  const orderIds = [
    ...rounds.flatMap((round) => round.stops.map((stop) => stop.orderId)),
    ...fieldOrders.map((order) => order.id),
  ];
  const relatedIds = [...roundIds, ...orderIds];
  const staffLogs = relatedIds.length
    ? await prisma.activityLog.findMany({
        where: {
          itemId: { in: relatedIds },
          department: { in: ["rounds", "orders", "payments", "fleet"] },
        },
        include: { user: true },
        orderBy: { createdAt: "desc" },
        take: 80,
      })
    : [];

  const roundsOut: RoundActivity[] = rounds.map((round) => {
    const events: DriverEvent[] = [];
    const kind = "kind" in round ? String(round.kind) : "DELIVERY";
    const notes = "notes" in round ? (round.notes as string | null) : null;
    const roundLoads = loads.filter((load) => load.roundId === round.id);
    const roundFields = fieldOrders.filter((order) => order.sourceRoundId === round.id);
    events.push({
      id: `round-open-${round.id}`,
      at: round.createdAt,
      kind: "round",
      title: kind === "PROSPECTING" ? t("Van-sale outing started") : t("Delivery round opened"),
      detail: `${t(round.region)} · ${round.vehicle.registration}${notes ? ` · ${notes}` : ""}`,
      href: `/rounds/${round.id}`,
    });

    for (const load of roundLoads) {
      events.push({
        id: `load-${load.id}`,
        at: round.createdAt,
        kind: "load",
        title: t("Loaded {qty} of {product}", { qty: load.loadedQty, product: load.product.name }),
        detail: t("Taken from warehouse onto the truck"),
        href: `/rounds/${round.id}`,
      });
      if (load.returnedQty > 0) {
        events.push({
          id: `return-${load.id}`,
          at: new Date(round.date.getTime() + 12 * 3600000),
          kind: "return",
          title: t("Returned {qty} {product} to warehouse", { qty: load.returnedQty, product: load.product.name }),
          detail: t("Sold from truck: {qty}", { qty: Math.max(0, load.loadedQty - load.returnedQty) }),
          href: `/rounds/${round.id}`,
        });
      }
    }

    for (const stop of round.stops) {
      const products = stop.order.lines.map((line) => `${line.product.name} × ${line.deliveredQty || line.quantity}`).join(", ");
      events.push({
        id: `stop-${stop.id}`,
        at: stop.order.updatedAt ?? stop.order.createdAt,
        kind: "stop",
        title: t("Stop {n}: {ref} · {status}", { n: stop.sequence, ref: stop.order.reference, status: label(stop.status) }),
        detail: `${customerName(stop.order.customer)} · ${money(stop.order.total)}${products ? ` · ${products}` : ""}`,
        href: `/orders/${stop.order.id}`,
      });
    }

    for (const order of roundFields) {
      const products = order.lines.map((line) => `${line.product.name} × ${line.quantity}`).join(", ");
      events.push({
        id: `field-${order.id}`,
        at: order.createdAt,
        kind: "order",
        title: t("Field result {kind}: {ref}", { kind: label(order.settlement), ref: order.reference }),
        detail: `${customerName(order.customer)} · ${money(order.total)} · ${t("collected {amount}", { amount: money(order.paidAmount) })}${products ? ` · ${products}` : ""}`,
        href: `/orders/${order.id}`,
      });
    }

    for (const payment of payments.filter((payment) =>
      payment.orderId
        ? orderIds.includes(payment.orderId) &&
          (round.stops.some((stop) => stop.orderId === payment.orderId) ||
            roundFields.some((order) => order.id === payment.orderId))
        : false,
    )) {
      events.push({
        id: `pay-${payment.id}`,
        at: payment.createdAt,
        kind: "payment",
        title: t("Collected {amount} ({method})", { amount: money(payment.amount), method: label(payment.method) }),
        detail: `${customerName(payment.customer)}${payment.order ? ` · ${payment.order.reference}` : ""}`,
      });
    }

    const thisRoundOrderIds = new Set([
      ...round.stops.map((stop) => stop.orderId),
      ...roundFields.map((order) => order.id),
    ]);
    for (const log of staffLogs.filter((log) => log.itemId === round.id || thisRoundOrderIds.has(log.itemId ?? ""))) {
      events.push({
        id: `staff-${log.id}`,
        at: log.createdAt,
        kind: "staff",
        title: `${label(log.operation)} · ${i18n.tr(log.item)}`,
        detail: `${log.user.firstName} ${log.user.lastName}${log.previousValue || log.newValue ? ` · ${i18n.tr(log.previousValue)} ${i18n.arrow} ${i18n.tr(log.newValue)}` : ""}${log.motif ? ` · ${t("Reason")}: ${log.motif}` : ""}`,
      });
    }

    if (round.status === "CLOSED" || round.status === "CANCELLED") {
      events.push({
        id: `round-end-${round.id}`,
        at: new Date(Math.max(round.date.getTime(), ...events.map((event) => event.at.getTime()))),
        kind: "round",
        title: round.status === "CLOSED" ? t("Round closed") : t("Round cancelled"),
        detail: t(round.region),
        href: `/rounds/${round.id}`,
      });
    }

    events.sort((a, b) => b.at.getTime() - a.at.getTime());
    return {
      roundId: round.id,
      date: round.date,
      kind,
      region: round.region,
      status: round.status,
      truck: round.vehicle.registration,
      events,
    };
  });

  const remittanceEvents: DriverEvent[] = remittances.map((row) => ({
    id: `remit-${row.id}`,
    at: row.date,
    kind: "payment" as const,
    title: t("Cash remittance {amount}", { amount: money(row.amount) }),
    detail: row.documentRef ?? t("Handed in to the company"),
  }));

  const recent = [...roundsOut.flatMap((round) => round.events), ...remittanceEvents]
    .sort((a, b) => b.at.getTime() - a.at.getTime())
    .slice(0, 12);

  return { recent, rounds: roundsOut };
}

