// Goods Receipt Note types (docs/11-BACKEND-PHASE1.md §4; FR-GRN-01..08).
// Mirrors the live backend DTOs. GET /grns and GET /grns/{id} both exist as of 2026-07-16.
//
// KNOWN GAP — serial numbers: FR-GRN-04 requires capturing serial numbers on receipt for
// Serial-tracked items, but the backend's CreateGrnLineInput has no such field (only
// `batch`). There is therefore deliberately no `serialNumbers` here: typing it would
// invite the UI to send data the server silently drops. Tracked in Frontend/PROGRESS.md.

export type GrnStatus = "Draft" | "Confirmed" | "Closed"
export type HoldStatus = "OnHold" | "Available" | "Rejected"
export type PurchaseOrderStatus =
  | "Draft"
  | "PendingApproval"
  | "Approved"
  | "PartiallyReceived"
  | "FullyReceived"
  | "Closed"
  | "Cancelled"

export interface BatchInput {
  batchNo: string
  expiryDate?: string | null
}

/**
 * A captured warranty number as returned by the server. The coverage period is not chosen at
 * receipt — it is snapshotted from the item's own `warrantyPeriodMonths` (set at item create).
 */
export interface GrnLineWarrantyNumber {
  warrantyNo: string
  warrantyPeriodMonths: number
}

/** One received line on create (docs/11 §4.1). */
export interface CreateGrnLineInput {
  poLineId?: number | null
  itemId: number
  binId?: number | null
  qty: number
  /**
   * Gross unit cost. For a PO line it is an optional per-receipt override — 0/omitted uses
   * the PO price; a value wins and the server records a variance (docs/02-SECURITY C.3,
   * revised). Required (> 0) for a direct receipt.
   */
  unitCost: number
  /** Trade discount % (0–100). Reduces inventory cost. */
  discountPct?: number
  /** VAT % (0–100). Recoverable — does not affect stock value. */
  vatPct?: number
  holdStatus: HoldStatus
  batch?: BatchInput | null
  /**
   * Required, one per received unit (count must equal `qty`), when the item is
   * warranty-tracked (`Item.warranty === "Warranty"`). Ignored otherwise.
   */
  warrantyNumbers?: string[] | null
}

export interface CreateGrnRequest {
  poId?: number | null
  /** Required when poId is null (direct/emergency receipt, FR-GRN-02). */
  vendorId?: number | null
  warehouseId: number
  lines: CreateGrnLineInput[]
}

export interface GrnLine {
  grnLineId: number
  poLineId: number | null
  itemId: number
  binId: number | null
  qty: number
  /** Gross unit cost received at. */
  unitCost: number
  /** PO price snapshot at receipt; null for direct receipts. */
  poUnitPrice: number | null
  discountPct: number
  /** After-discount cost — what the FIFO layer is valued at. */
  netUnitCost: number
  vatPct: number
  vatAmount: number
  /** qty × netUnitCost (after discount, before VAT). */
  receivedValue: number
  /** qty × netUnitCost + vatAmount — payable to vendor. */
  lineTotal: number
  /** (unitCost − poUnitPrice) × qty; 0 for direct receipts. */
  priceVariance: number
  holdStatus: HoldStatus
  batchId: number | null
  warrantyNumbers: GrnLineWarrantyNumber[]
}

export interface Grn {
  grnId: number
  docNo: string
  poId: number | null
  vendorId: number
  warehouseId: number
  status: GrnStatus
  createdBy: number
  createdAt: string
  postedAt: string | null
  /** Journal number of the real GL journal entry posted for this GRN's receipt (set on confirm). */
  glJournalNo: string | null
  paidAmount: number
  balanceAmount: number
  lines: GrnLine[]
}

export interface GrnSummary {
  grnId: number
  docNo: string
  poId: number | null
  vendorId: number
  warehouseId: number
  status: GrnStatus
  createdBy: number
  createdAt: string
  postedAt: string | null
  lineCount: number
  paidAmount: number
  balanceAmount: number
}

/** docs/11 §4.2 confirm response. */
export interface CreatedLayer {
  layerId: number
  itemId: number
  warehouseId: number
  batchId: number | null
  qtyReceived: number
  qtyRemaining: number
  unitCost: number
  receiptDate: string
}

export interface ConfirmGrnResponse {
  grnId: number
  status: GrnStatus
  postedAt: string
  glJournalNo: string
  balanceAmount: number
  createdLayers: CreatedLayer[]
  ledgerRefs: number[]
  poStatus: PurchaseOrderStatus | null
}

export type ReleaseAction = "Release" | "Reject"

export interface ReleaseGrnLineRequest {
  action: ReleaseAction
}

export interface ReleaseGrnLineResponse {
  grnLineId: number
  holdStatus: HoldStatus
}

/** A vendor payment against a confirmed GRN's balance (installments allowed). */
export interface GrnPayment {
  grnPaymentId: number
  grnId: number
  amount: number
  paymentDate: string
  glBankAccountId: number
  bankAccountName: string
  reference: string | null
  /** Journal number of the real GL journal entry this payment posted. */
  glJournalNo: string | null
  createdAt: string
}

export interface CreateGrnPaymentRequest {
  amount: number
  glBankAccountId: number
  reference?: string | null
}
