import { TraceLabelTranslator } from "./traceLabelUtils";

/** Matches PO receiving UI: only `completed` means 已上架. */
const COMPLETED_PUTAWAY_STATUSES = new Set(["completed", "complete"]);

export const normRefType = (refType: string | null | undefined): string =>
  (refType ?? "").trim().toUpperCase();

const normWhCode = (code: string | null | undefined): string =>
  (code ?? "").trim().toUpperCase();

/** Match exact warehouse codes or floor vs bin (e.g. 4F ↔ 4F-W401). */
export const warehouseCodesMatch = (
  a: string | null | undefined,
  b: string | null | undefined,
): boolean => {
  const x = normWhCode(a);
  const y = normWhCode(b);
  if (!x || !y) return false;
  if (x === y) return true;
  return x.startsWith(`${y}-`) || y.startsWith(`${x}-`);
};

/** Transfer destination stock-in is shown on the TRANSFER node, not as a separate putaway card. */
export const isTransferInboundPutaway = (refType: string | null | undefined): boolean =>
  normRefType(refType) === "TRANSFER";

export type TraceTransferMatchInput = {
  fromWarehouse?: string | null;
  toWarehouse?: string | null;
  qty?: number | null;
  transferCode?: string | null;
  timestamp?: string | null;
};

/**
 * Putaway refCode is often SI-* while transferCode is TR-*; match by code, then to-warehouse + qty/time.
 */
export const matchTransferForInboundPutaway = (
  putaway: {
    warehouseCode?: string | null;
    qty?: number | null;
    refCode?: string | null;
    timestamp?: string | null;
  },
  transfers: TraceTransferMatchInput[],
): TraceTransferMatchInput | undefined => {
  if (!transfers.length) return undefined;
  const ref = (putaway.refCode ?? "").trim();
  if (ref) {
    const byCode = transfers.find((tr) => (tr.transferCode ?? "").trim() === ref);
    if (byCode) return byCode;
  }

  const toMatched = transfers.filter((tr) =>
    warehouseCodesMatch(tr.toWarehouse, putaway.warehouseCode),
  );
  if (!toMatched.length) return undefined;
  if (toMatched.length === 1) return toMatched[0];

  const putawayQty = putaway.qty;
  const qtyMatched =
    putawayQty != null
      ? toMatched.filter((tr) => tr.qty != null && Number(tr.qty) === Number(putawayQty))
      : [];
  const pool = qtyMatched.length > 0 ? qtyMatched : toMatched;

  const putawayTs = Date.parse(putaway.timestamp ?? "");
  if (!Number.isNaN(putawayTs)) {
    const ranked = pool
      .map((tr) => {
        const ts = Date.parse(tr.timestamp ?? "");
        return { tr, dist: Number.isNaN(ts) ? Number.POSITIVE_INFINITY : Math.abs(ts - putawayTs) };
      })
      .sort((a, b) => a.dist - b.dist);
    if (ranked[0] && Number.isFinite(ranked[0].dist)) return ranked[0].tr;
  }
  return pool[0];
};

/**
 * Emit a TRANSFER card for each transfer on the primary lot.
 * Location-block scopes skip transfers to avoid duplicating the same TR-* rows.
 */
export const shouldEmitTransferForScope = (locationBlockKeys?: boolean): boolean =>
  !locationBlockKeys;

/**
 * Transfer inbound putaways are represented by TRANSFER cards (one per TR-*).
 * Keep 轉倉入庫 putaway cards off so multi-transfer lots do not collapse to one inbound.
 */
export const shouldShowTransferInboundPutawayCard = (
  _scopeWarehouse?: string | null,
  _putawayWarehouse?: string | null,
  _transfers?: Array<{ fromWarehouse?: string | null; toWarehouse?: string | null }>,
  _mergedMultiLocation?: boolean,
): boolean => false;

/**
 * In a merged multi-warehouse graph, skip 已用完 when this location was emptied by transfer
 * to another location still shown on the same graph. Remaining DO picks belong to the destination.
 */
export const shouldEmitDepletedForScope = (
  availableQty: number,
  scopeWarehouse: string | null | undefined,
  transfers: Array<{ fromWarehouse?: string | null; toWarehouse?: string | null }>,
  mergedMultiLocation: boolean,
): boolean => {
  if (availableQty > 0) return false;
  if (!mergedMultiLocation) return true;
  const scope = scopeWarehouse?.trim();
  if (!scope) return true;
  const emptiedByTransfer = transfers.some((tr) =>
    warehouseCodesMatch(scope, tr.fromWarehouse),
  );
  return !emptiedByTransfer;
};

export type PutawayPresentationLabels = {
  nodePutaway: string;
  nodePutawayTransfer: string;
  putawayTransferDetail: string;
};

export type PutawayPresentation = {
  /** Chip on flow card (top badge). */
  chipLabel: string;
  /** Status row in node detail panel. */
  statusDetail: string;
  /** Card title (replaces generic「上架」for transfer inbound). */
  title: string;
  /** Type row in node detail panel. */
  detailType: string;
};

export const isPendingPutawayOriginStatus = (status: string | null | undefined): boolean => {
  const normalized = (status ?? "").trim().toLowerCase();
  if (COMPLETED_PUTAWAY_STATUSES.has(normalized)) return false;
  return true;
};

export const resolvePutawayStatusLabel = (
  tr: TraceLabelTranslator,
  status: string | null | undefined,
): string => {
  const normalized = (status ?? "").trim().toLowerCase();
  if (COMPLETED_PUTAWAY_STATUSES.has(normalized)) {
    return tr.putawayShelfStatus("completed");
  }
  return tr.putawayShelfStatus("pending");
};

export const resolvePutawayPresentation = (
  tr: TraceLabelTranslator,
  labels: PutawayPresentationLabels,
  status: string | null | undefined,
  refType: string | null | undefined,
): PutawayPresentation => {
  if (normRefType(refType) === "TRANSFER") {
    return {
      chipLabel: labels.nodePutawayTransfer,
      statusDetail: labels.putawayTransferDetail,
      title: labels.nodePutawayTransfer,
      detailType: labels.nodePutawayTransfer,
    };
  }
  const shelf = resolvePutawayStatusLabel(tr, status);
  return {
    chipLabel: shelf,
    statusDetail: shelf,
    title: labels.nodePutaway,
    detailType: labels.nodePutaway,
  };
};
