import { NOTIONS_SUPPLIER_ID } from "./constants";

/**
 * Computes the "cost each" that the PO line item will carry, mirroring the
 * fallback chain in the legacy PHP `clsPO::_product_add()` (po.class.php:189):
 *
 *   if supplierId == 92 (Notions):
 *     notions_cost_each → supplier_cost_each → last_received_cost
 *   else:
 *     supplier_cost_each → last_received_cost
 *
 * Returns null if none of the candidate fields has a positive value, so
 * callers can distinguish "no quote" from "$0".
 *
 * Computed client-side so changing the supplier mid-flow doesn't require a
 * round-trip; the three raw fields come from /api/products/batch once.
 */
export function computeCostEach(
  item: Pick<PoLineItem, "notions_cost_each" | "supplier_cost_each" | "last_received_cost">,
  supplierId: number | undefined
): number | null {
  const notions = Number(item.notions_cost_each) || 0;
  const supplier = Number(item.supplier_cost_each) || 0;
  const lastReceived = Number(item.last_received_cost) || 0;
  if (Number(supplierId) === NOTIONS_SUPPLIER_ID && notions > 0) return notions;
  if (supplier > 0) return supplier;
  if (lastReceived > 0) return lastReceived;
  return null;
}

/**
 * Display shape for a single line item on the Create PO page. This is the
 * exact response shape returned by GET /api/products/batch (snake_case).
 *
 * `qty` and `moqOverride` are local-only client state appended to the API
 * shape; they are NOT returned by the backend.
 */
export interface PoLineItem {
  pid: number;
  title: string;
  image_url: string | null;
  barcode: string | null;
  vendor_reference: string | null;
  notions_reference: string | null;
  notions_inv_count: number | null;
  current_stock: number | null;
  baskets: number | null;
  on_order_qty: number | null;
  total_sold: number | null;
  /**
   * Backend-computed cost using the same fallback chain the legacy PHP
   * `_product_add()` writes onto the PO line item:
   *   supplier=92 → notions_cost_each → supplier_cost_each → last received cost
   *   else        → supplier_cost_each → last received cost
   * Sent by the server when a supplierId is passed to /api/products/batch.
   * For supplier-aware display the UI should re-compute from the three raw
   * fields below using `computeCostEach()`, since the working supplier can
   * change after the row was fetched.
   */
  current_cost_price: number | null;
  /** Raw cost from supplier_item_data.notions_cost_each (0/null when unset). */
  notions_cost_each: number | null;
  /** Raw cost from supplier_item_data.supplier_cost_each (0/null when unset). */
  supplier_cost_each: number | null;
  /** Most recent receivings.cost_each (>0, non-canceled). */
  last_received_cost: number | null;
  date_last_sold: string | null;
  date_first_received: string | null;
  /** From the products table; may be null/0/inconsistent. The user can override locally. */
  moq: number | null;

  // --- Local-only client state ---
  /** User-entered order quantity. */
  qty: number;
  /**
   * Local override of MOQ for this row. Undefined means "use the canonical
   * `moq` value above". This is never sent to the backend; it only affects
   * the qty-validation highlight on the row.
   */
  moqOverride?: number;
}

/** Wire shape sent to the legacy PHP endpoint. */
export interface PoSubmitItem {
  pid: number;
  qty: number;
}

/**
 * Intermediate shape produced by paste/upload parsing — before identifier
 * resolution against the products table.
 */
export interface RawIdentifierRow {
  identifier: string;
  qty: number;
}

/** A single search result candidate from /api/products/search. */
export interface SearchCandidate {
  pid: number;
  title: string;
  sku: string | null;
  barcode: string | null;
  brand: string | null;
}

/**
 * The result of attempting to resolve a single raw row to a product:
 *  - matched   → exactly one product found
 *  - ambiguous → multiple candidates; user must pick one
 *  - unmatched → zero candidates; user can manually fix or drop
 */
export type ResolveOutcome =
  | { kind: "matched"; pid: number; qty: number; identifier: string }
  | { kind: "ambiguous"; identifier: string; qty: number; candidates: SearchCandidate[] }
  | { kind: "unmatched"; identifier: string; qty: number };

export interface ResolveResult {
  matched: Array<{ pid: number; qty: number; identifier: string }>;
  ambiguous: Array<{ identifier: string; qty: number; candidates: SearchCandidate[] }>;
  unmatched: Array<{ identifier: string; qty: number }>;
}
