import type {
  ItemLotTraceLocationBlock,
  ItemLotTraceResponse,
} from "@/app/api/itemTracing";
import { blockWarehouseCode } from "./buildLocationBlockGraphNodes";

export type ScopedRow<T> = T & {
  scopeWarehouseCode: string;
  inventoryLotId: number;
};

export const primaryWarehouseLabel = (data: ItemLotTraceResponse): string =>
  data.warehouseLines
    .map((w) => w.warehouseCode)
    .filter(Boolean)
    .join(" / ") || "—";

const sortByTimestampDesc = <T extends { timestamp?: string | null }>(
  rows: T[],
): T[] =>
  [...rows].sort((a, b) =>
    (b.timestamp ?? "").localeCompare(a.timestamp ?? ""),
  );

const sortByReceiptDateDesc = <T extends { receiptDate?: string | null }>(
  rows: T[],
): T[] =>
  [...rows].sort((a, b) =>
    (b.receiptDate ?? "").localeCompare(a.receiptDate ?? ""),
  );

export const mergeScopedOrigins = (data: ItemLotTraceResponse) => {
  const primaryWh = primaryWarehouseLabel(data);
  const primary = data.origins.map((o) => ({
    ...o,
    scopeWarehouseCode: primaryWh,
    inventoryLotId: data.lot.inventoryLotId,
  }));
  const fromBlocks = (data.locationBlocks ?? []).flatMap((block) => {
    const wh = blockWarehouseCode(block);
    return block.origins.map((o) => ({
      ...o,
      scopeWarehouseCode: wh,
      inventoryLotId: block.inventoryLotId,
    }));
  });
  return sortByReceiptDateDesc([...primary, ...fromBlocks]);
};

export const mergeScopedQcResults = (data: ItemLotTraceResponse) => {
  const primaryWh = primaryWarehouseLabel(data);
  const primary = data.qcResults.map((q, i) => ({
    ...q,
    scopeWarehouseCode: primaryWh,
    inventoryLotId: data.lot.inventoryLotId,
    rowKey: `primary-${q.stockInLineId}-${i}`,
  }));
  const fromBlocks = (data.locationBlocks ?? []).flatMap((block) => {
    const wh = blockWarehouseCode(block);
    return block.qcResults.map((q, i) => ({
      ...q,
      scopeWarehouseCode: wh,
      inventoryLotId: block.inventoryLotId,
      rowKey: `loc-${block.inventoryLotId}-${q.stockInLineId}-${i}`,
    }));
  });
  return [...primary, ...fromBlocks].sort((a, b) =>
    (b.created ?? "").localeCompare(a.created ?? ""),
  );
};

export const mergeScopedOutboundUsage = (data: ItemLotTraceResponse) => {
  const primaryWh = primaryWarehouseLabel(data);
  const primary = data.outboundUsage.map((u) => ({
    ...u,
    scopeWarehouseCode: primaryWh,
    inventoryLotId: data.lot.inventoryLotId,
  }));
  const fromBlocks = (data.locationBlocks ?? []).flatMap((block) => {
    const wh = blockWarehouseCode(block);
    return block.outboundUsage.map((u) => ({
      ...u,
      scopeWarehouseCode: wh,
      inventoryLotId: block.inventoryLotId,
    }));
  });
  return sortByTimestampDesc([...primary, ...fromBlocks]);
};

export const mergeScopedStockTakeEvents = (data: ItemLotTraceResponse) => {
  const primaryWh = primaryWarehouseLabel(data);
  const primary = data.stockTakeEvents.map((e, i) => ({
    ...e,
    scopeWarehouseCode: e.warehouseCode?.trim() || primaryWh,
    inventoryLotId: data.lot.inventoryLotId,
    rowKey: `primary-${e.stockTakeCode}-${i}`,
  }));
  const fromBlocks = (data.locationBlocks ?? []).flatMap((block) => {
    const wh = blockWarehouseCode(block);
    return block.stockTakeEvents.map((e, i) => ({
      ...e,
      scopeWarehouseCode: e.warehouseCode?.trim() || wh,
      inventoryLotId: block.inventoryLotId,
      rowKey: `loc-${block.inventoryLotId}-${e.stockTakeCode}-${i}`,
    }));
  });
  return sortByTimestampDesc([...primary, ...fromBlocks]);
};

export const mergeScopedAdjustments = (data: ItemLotTraceResponse) => {
  const primaryWh = primaryWarehouseLabel(data);
  const primary = data.adjustments.map((a, i) => ({
    ...a,
    scopeWarehouseCode: primaryWh,
    inventoryLotId: data.lot.inventoryLotId,
    rowKey: `primary-${a.refCode}-${i}`,
  }));
  const fromBlocks = (data.locationBlocks ?? []).flatMap((block) => {
    const wh = blockWarehouseCode(block);
    return block.adjustments.map((a, i) => ({
      ...a,
      scopeWarehouseCode: wh,
      inventoryLotId: block.inventoryLotId,
      rowKey: `loc-${block.inventoryLotId}-${a.refCode}-${i}`,
    }));
  });
  return sortByTimestampDesc([...primary, ...fromBlocks]);
};

export const mergeScopedTransfers = (data: ItemLotTraceResponse) => {
  const primaryWh = primaryWarehouseLabel(data);
  const primary = data.transfers.map((tr, i) => ({
    ...tr,
    scopeWarehouseCode: primaryWh,
    inventoryLotId: data.lot.inventoryLotId,
    rowKey: `primary-${tr.transferCode}-${i}`,
  }));
  const fromBlocks = (data.locationBlocks ?? []).flatMap((block) => {
    const wh = blockWarehouseCode(block);
    return block.transfers.map((tr, i) => ({
      ...tr,
      scopeWarehouseCode: wh,
      inventoryLotId: block.inventoryLotId,
      rowKey: `loc-${block.inventoryLotId}-${tr.transferCode}-${i}`,
    }));
  });
  return sortByTimestampDesc([...primary, ...fromBlocks]);
};

export const mergeScopedMovements = (data: ItemLotTraceResponse) => {
  const primaryWh = primaryWarehouseLabel(data);
  const primary = data.movements.map((m, i) => ({
    ...m,
    scopeWarehouseCode: m.warehouseCode?.trim() || primaryWh,
    inventoryLotId: data.lot.inventoryLotId,
    rowKey: `primary-mov-${i}-${m.refCode}`,
  }));
  const fromBlocks = (data.locationBlocks ?? []).flatMap((block) => {
    const wh = blockWarehouseCode(block);
    return block.movements.map((m, i) => ({
      ...m,
      scopeWarehouseCode: m.warehouseCode?.trim() || wh,
      inventoryLotId: block.inventoryLotId,
      rowKey: `loc-${block.inventoryLotId}-mov-${i}-${m.refCode}`,
    }));
  });
  return sortByTimestampDesc([...primary, ...fromBlocks]);
};

export const mergeScopedPutawayEvents = (data: ItemLotTraceResponse) => {
  const primaryWh = primaryWarehouseLabel(data);
  const primary = data.putawayEvents.map((p, i) => ({
    ...p,
    scopeWarehouseCode: p.warehouseCode?.trim() || primaryWh,
    inventoryLotId: data.lot.inventoryLotId,
    rowKey: `primary-putaway-${i}-${p.refCode}`,
  }));
  const fromBlocks = (data.locationBlocks ?? []).flatMap((block) => {
    const wh = blockWarehouseCode(block);
    return block.putawayEvents.map((p, i) => ({
      ...p,
      scopeWarehouseCode: p.warehouseCode?.trim() || wh,
      inventoryLotId: block.inventoryLotId,
      rowKey: `loc-${block.inventoryLotId}-putaway-${i}-${p.refCode}`,
    }));
  });
  return sortByTimestampDesc([...primary, ...fromBlocks]);
};

export const mergeScopedPurchaseEvents = (data: ItemLotTraceResponse) => {
  const primaryWh = primaryWarehouseLabel(data);
  const primary = (data.purchaseEvents ?? []).map((p, i) => ({
    ...p,
    scopeWarehouseCode: primaryWh,
    inventoryLotId: data.lot.inventoryLotId,
    rowKey: `primary-po-${i}-${p.purchaseOrderLineId}`,
  }));
  const fromBlocks = (data.locationBlocks ?? []).flatMap((block) => {
    const wh = blockWarehouseCode(block);
    return (block.purchaseEvents ?? []).map((p, i) => ({
      ...p,
      scopeWarehouseCode: wh,
      inventoryLotId: block.inventoryLotId,
      rowKey: `loc-${block.inventoryLotId}-po-${i}-${p.purchaseOrderLineId}`,
    }));
  });
  return [...primary, ...fromBlocks].sort((a, b) =>
    (b.orderDate ?? "").localeCompare(a.orderDate ?? ""),
  );
};

export const mergeScopedDoDeliveries = (data: ItemLotTraceResponse) => {
  const primaryWh = primaryWarehouseLabel(data);
  const primary = data.doDeliveries.map((d, i) => ({
    ...d,
    scopeWarehouseCode: primaryWh,
    inventoryLotId: data.lot.inventoryLotId,
    rowKey: `primary-do-${i}-${d.stockOutLineId}`,
  }));
  const fromBlocks = (data.locationBlocks ?? []).flatMap((block) => {
    const wh = blockWarehouseCode(block);
    return block.doDeliveries.map((d, i) => ({
      ...d,
      scopeWarehouseCode: wh,
      inventoryLotId: block.inventoryLotId,
      rowKey: `loc-${block.inventoryLotId}-do-${i}-${d.stockOutLineId}`,
    }));
  });
  return sortByTimestampDesc([...primary, ...fromBlocks]);
};

export const mergeScopedFailEvents = (data: ItemLotTraceResponse) => {
  const primaryWh = primaryWarehouseLabel(data);
  const primary = data.failEvents.map((f, i) => ({
    ...f,
    scopeWarehouseCode: primaryWh,
    inventoryLotId: data.lot.inventoryLotId,
    rowKey: `primary-fail-${i}-${f.failId}`,
    timestamp: f.recordDate,
  }));
  const fromBlocks = (data.locationBlocks ?? []).flatMap((block) => {
    const wh = blockWarehouseCode(block);
    return block.failEvents.map((f, i) => ({
      ...f,
      scopeWarehouseCode: wh,
      inventoryLotId: block.inventoryLotId,
      rowKey: `loc-${block.inventoryLotId}-fail-${i}-${f.failId}`,
      timestamp: f.recordDate,
    }));
  });
  return sortByTimestampDesc([...primary, ...fromBlocks]);
};

export const mergeScopedReturnEvents = (data: ItemLotTraceResponse) => {
  const primaryWh = primaryWarehouseLabel(data);
  const primary = data.returnEvents.map((r, i) => ({
    ...r,
    scopeWarehouseCode: r.warehouseCode?.trim() || primaryWh,
    inventoryLotId: data.lot.inventoryLotId,
    rowKey: `primary-return-${i}-${r.stockOutLineId}`,
  }));
  const fromBlocks = (data.locationBlocks ?? []).flatMap((block) => {
    const wh = blockWarehouseCode(block);
    return block.returnEvents.map((r, i) => ({
      ...r,
      scopeWarehouseCode: r.warehouseCode?.trim() || wh,
      inventoryLotId: block.inventoryLotId,
      rowKey: `loc-${block.inventoryLotId}-return-${i}-${r.stockOutLineId}`,
    }));
  });
  return sortByTimestampDesc([...primary, ...fromBlocks]);
};

export const mergeScopedOpenMovements = (data: ItemLotTraceResponse) => {
  const primaryWh = primaryWarehouseLabel(data);
  const primary = data.openMovements.map((o, i) => ({
    ...o,
    scopeWarehouseCode: o.warehouseCode?.trim() || primaryWh,
    inventoryLotId: data.lot.inventoryLotId,
    rowKey: `primary-open-${i}-${o.stockInLineId}`,
  }));
  const fromBlocks = (data.locationBlocks ?? []).flatMap((block) => {
    const wh = blockWarehouseCode(block);
    return block.openMovements.map((o, i) => ({
      ...o,
      scopeWarehouseCode: o.warehouseCode?.trim() || wh,
      inventoryLotId: block.inventoryLotId,
      rowKey: `loc-${block.inventoryLotId}-open-${i}-${o.stockInLineId}`,
    }));
  });
  return sortByTimestampDesc([...primary, ...fromBlocks]);
};

export const mergeScopedReplenishmentEvents = (data: ItemLotTraceResponse) => {
  const primaryWh = primaryWarehouseLabel(data);
  const primary = (data.replenishmentEvents ?? []).map((r, i) => ({
    ...r,
    scopeWarehouseCode: primaryWh,
    inventoryLotId: data.lot.inventoryLotId,
    rowKey: `primary-replenish-${i}-${r.replenishmentId}`,
  }));
  const fromBlocks = (data.locationBlocks ?? []).flatMap((block) => {
    const wh = blockWarehouseCode(block);
    return (block.replenishmentEvents ?? []).map((r, i) => ({
      ...r,
      scopeWarehouseCode: wh,
      inventoryLotId: block.inventoryLotId,
      rowKey: `loc-${block.inventoryLotId}-replenish-${i}-${r.replenishmentId}`,
    }));
  });
  return sortByTimestampDesc([...primary, ...fromBlocks]);
};

export const hasMultipleLocations = (data: ItemLotTraceResponse): boolean =>
  (data.locationBlocks?.length ?? 0) > 0 ||
  (data.alternateLocations?.length ?? 0) > 0;
