// Vendor Settlement — Purchase-Order-Centric Architecture
// Mirrors the Transporter Settlement module's structure (settlements.jsx) but pays MATERIAL VENDORS,
// never transporters. Two business scenarios are handled distinctly:
//   Scenario 1 — Vendor supplies material with own transport → included here.
//   Scenario 2 — Vendor supplies material only, third party transports → excluded here entirely
//                (that trip is settled instead via Transporter Settlement).
const { useState: vsSt, useEffect: vsEf, useContext: vsCtx, useMemo: vsMemo } = React;

const VS_STATUSES  = ['Pending', 'Partially Settled', 'Settled', 'Cancelled'];
const VS_DED_TYPES = ['Adjustment', 'Advance', 'RTO', 'Royalty Recovery', 'Penalty', 'Quality Deduction', 'Short Supply', 'Damage Recovery', 'Miscellaneous', 'Others'];
const VS_PAY_MODES = ['Cheque', 'Bank Transfer', 'RTGS', 'NEFT', 'UPI', 'Cash'];
// Centralized payment-mode → instrument/reference-field behavior. Every consumer (the Add Payment
// field, save-time validation, read-only displays, reports, future modules) reads through
// vsPayModeConfig, so introducing a new mode later (IMPS, DD, Wire, Swift…) means adding one line
// here — never touching per-mode conditionals scattered through the module. The column/field
// heading itself is always the generic "Payment Reference" (see vsPayRefColumnLabel below) so it
// never drifts out of sync with whichever mode is selected — only refLabel (used in validation
// messages and read-only "<Label>: value" displays) and refPlaceholder change per mode.
const VS_PAY_MODE_CONFIG = {
  'Cheque':        { refRequired: true,  refDisabled: false, refLabel: 'Cheque Number',      refPlaceholder: 'Enter Cheque Number' },
  'Bank Transfer': { refRequired: true,  refDisabled: false, refLabel: 'Transaction Number', refPlaceholder: 'Enter Transaction Number' },
  'RTGS':          { refRequired: true,  refDisabled: false, refLabel: 'RTGS UTR Number',    refPlaceholder: 'Enter RTGS UTR Number' },
  'NEFT':          { refRequired: true,  refDisabled: false, refLabel: 'NEFT UTR Number',     refPlaceholder: 'Enter NEFT UTR Number' },
  'UPI':           { refRequired: true,  refDisabled: false, refLabel: 'UPI Transaction ID',  refPlaceholder: 'Enter UPI Transaction ID' },
  'Cash':          { refRequired: false, refDisabled: true,  refLabel: 'Payment Reference',   refPlaceholder: 'Not Required' },
};
// Safe default for any not-yet-configured mode — requires a reference rather than silently
// skipping validation.
const VS_PAY_MODE_DEFAULT = { refRequired: true, refDisabled: false, refLabel: 'Payment Reference', refPlaceholder: 'Enter Payment Reference' };
function vsPayModeConfig(mode) { return VS_PAY_MODE_CONFIG[mode] || VS_PAY_MODE_DEFAULT; }
// The column/field heading is always this one generic label, regardless of mode.
const VS_PAY_REF_COLUMN_LABEL = 'Payment Reference';
// Centralized read-only display helper — "<mode-specific label>: value", or "Payment Reference: Not
// Applicable" for Cash. Every settlement/ledger/report view should render payment references through
// this so no screen ever hardcodes "Cheque No." for a non-cheque transaction.
function vsPayRefDisplay(mode, value) {
  var cfg = vsPayModeConfig(mode);
  if (cfg.refDisabled) return VS_PAY_REF_COLUMN_LABEL + ': Not Applicable';
  return cfg.refLabel + ': ' + (value || '—');
}
const VS_EXCLUDE_KEYWORDS = ['water']; // extensible exclusion list — never fetch water purchases/vendors

function vsIsExcluded(purchaseItem, vendor) {
  const mat = Store.byId('materials', purchaseItem.materialId);
  const matName = ((mat && mat.name) || '').toLowerCase();
  const vendorName = ((vendor && vendor.name) || '').toLowerCase();
  return VS_EXCLUDE_KEYWORDS.some(function (kw) { return matName.indexOf(kw) !== -1 || vendorName.indexOf(kw) !== -1; });
}

// ══════════════════════════════════════════════════════════════════════════════════════════════
// IDENTITY / VALUE RESOLUTION LAYER
// Every match in the settlement pipeline (vendor, company, date, flags) goes through these
// helpers so that BOTH sides of every comparison are normalised the same way. Purely
// data-driven — field names come from the alias lists below, values from the masters.
// ══════════════════════════════════════════════════════════════════════════════════════════════
// Field aliases a Purchase Order may carry for its owning company / vendor / settlement date.
// Extend these lists (never add per-record special cases) if a new field is ever introduced.
const VS_CO_FIELDS     = ['companyId', 'company', 'companyName', 'businessUnit', 'masterCompany', 'subsidiary'];
const VS_VENDOR_FIELDS = ['vendorId', 'vendor', 'vendorName', 'supplierId', 'supplierName'];
const VS_DATE_FIELDS   = ['date', 'deliveryDate', 'deliveredDate', 'completedDate', 'challanDate', 'purchaseDate', 'settlementDate'];
const VS_OK_STATUSES   = ['delivered', 'completed'];
const VS_BAD_STATUSES  = ['cancelled', 'deleted', 'archived', 'rejected', 'void'];

// Normalise any text for comparison: strip zero-width/invisible chars, collapse whitespace, lowercase.
function vsNorm(v) {
  if (v == null) return '';
  return String(v).replace(/[\u200B-\u200D\uFEFF\u00A0]/g, ' ').replace(/\s+/g, ' ').trim().toLowerCase();
}
// Normalise any date value to ISO yyyy-mm-dd — handles Date objects, ISO datetimes,
// dd-mm-yyyy, dd/mm/yyyy and yyyy/mm/dd. Never uses locale parsing (timezone-safe).
function vsIsoDate(v) {
  if (!v) return '';
  if (v instanceof Date) return isNaN(v) ? '' : new Date(v.getTime() - v.getTimezoneOffset() * 60000).toISOString().slice(0, 10);
  const s = String(v).trim();
  if (!s) return '';
  let m = s.match(/^(\d{4})[-/](\d{1,2})[-/](\d{1,2})/);
  if (m) return m[1] + '-' + ('0' + m[2]).slice(-2) + '-' + ('0' + m[3]).slice(-2);
  m = s.match(/^(\d{1,2})[-/.](\d{1,2})[-/.](\d{4})/);
  if (m) return m[3] + '-' + ('0' + m[2]).slice(-2) + '-' + ('0' + m[1]).slice(-2);
  return s;
}
// Resolve any company reference (id, name, legacy label) to a canonical company id.
function vsResolveCompanyId(ref) {
  if (ref == null || ref === '') return '';
  const s = String(ref).trim();
  if (s === 'group') return 'group';
  const cos = Store.all('companies', 'group') || [];
  if (cos.some(function (c) { return c.id === s; })) return s;
  const k = vsNorm(s);
  const byName = cos.find(function (c) { return vsNorm(c.name) === k; });
  return byName ? byName.id : s;
}
// The company a Purchase Order belongs to — first populated alias field, canonicalised.
function vsPoCompanyId(p) {
  for (let i = 0; i < VS_CO_FIELDS.length; i++) {
    const v = p[VS_CO_FIELDS[i]];
    if (v != null && v !== '') return vsResolveCompanyId(v);
  }
  return '';
}
// ── Vendor identity resolution ───────────────────────────────────────────────────────────────
// A vendor that supplies several companies is often entered once per company, producing
// multiple vendor master rows for the SAME party. Settling by a single row id then finds
// nothing for the other company. This resolves the selected vendor to the full set of master
// rows that are provably the same party: identical normalised name AND no conflicting GST.
// Different GST numbers ⇒ genuinely different parties ⇒ never linked.
function vsResolveVendorIds(vendorId) {
  const all = Store.all('vendors', 'group') || [];
  const base = all.find(function (v) { return v.id === vendorId; });
  if (!base) return { ids: [vendorId], names: [], linked: [] };
  const key = vsNorm(base.name), baseGst = vsNorm(base.gst);
  const ids = [base.id], linked = [];
  if (key) all.forEach(function (v) {
    if (v.id === base.id || vsNorm(v.name) !== key) return;
    // GST must agree exactly (both blank counts as agreeing). A record carrying a different
    // GST — or a GST where the other has none — is treated as a DIFFERENT party and never
    // merged, so no other party's Purchase Orders can enter this settlement.
    if (vsNorm(v.gst) !== baseGst) return;
    ids.push(v.id); linked.push(v);
  });
  return { ids: ids, names: key ? [key] : [], linked: linked };
}
// Does a Purchase Order belong to this vendor identity? id match first, then name match for
// legacy rows that carry only a vendor name / a since-deleted vendor id.
function vsPoMatchesVendor(p, identity) {
  for (let i = 0; i < VS_VENDOR_FIELDS.length; i++) {
    const v = p[VS_VENDOR_FIELDS[i]];
    if (v == null || v === '') continue;
    const s = String(v).trim();
    if (identity.ids.indexOf(s) !== -1) return true;
    if (identity.names.length && identity.names.indexOf(vsNorm(s)) !== -1) return true;
  }
  return false;
}
// Every date a PO carries, ISO-normalised — a PO is in-period if ANY of them falls in range
// (order date, delivery date, completion date…), so a legitimate PO can never be hidden by
// which date field the operator happened to fill in. Returns [{field, iso}].
function vsPoDates(p) {
  const out = [];
  VS_DATE_FIELDS.forEach(function (f) {
    const iso = vsIsoDate(p[f]);
    if (iso && !out.some(function (o) { return o.iso === iso; })) out.push({ field: f, iso: iso });
  });
  return out;
}
function vsFlagYes(v) { const n = vsNorm(v); return v === true || n === 'yes' || n === 'y' || n === 'true' || n === '1'; }

// ── Eligibility audit — the single source of truth for settlement PO matching ────────────────
// ALL conditions must hold:
//   Create Vendor Settlement = Yes · Status Delivered/Completed ·
//   Not already fully settled (unless part of the settlement being edited) · not a water purchase.
// NOTE: transportThirdParty is NOT a disqualifier — the user's explicit
//   "Create Vendor Settlement = Yes" flag is the authoritative gate.
//   Transport arrangement (own vs third-party) affects Transporter Settlement
//   separately; it does not prevent a PO from also being vendor-settled.
// Returns { eligible, vendorLinked, scanned, matchedVendor, rejects } where rejects records the
// exact stage every excluded PO failed at, so the UI can explain an empty result instead of
// silently showing zero.
function vsAuditEligiblePurchases(vendorId, periodFrom, periodTo, coId, currentSettlementId) {
  const empty = { eligible: [], vendorLinked: [], scanned: 0, matchedVendor: 0, rejects: {} };
  if (!vendorId || !periodFrom || !periodTo) return empty;
  const vendor = Store.byId('vendors', vendorId);
  const identity = vsResolveVendorIds(vendorId);
  const wantCo = vsResolveCompanyId(coId);
  const scoped = wantCo && wantCo !== 'group';
  const from = vsIsoDate(periodFrom), to = vsIsoDate(periodTo);
  const all = Store.all('purchases', 'group') || [];
  const rejects = {};
  const eligible = [];
  function reject(stage, p, detail) {
    (rejects[stage] = rejects[stage] || []).push({ id: p.id, poNo: p.challanNumber || ('#' + String(p.id).slice(0, 6).toUpperCase()), date: vsIsoDate(p.date), detail: detail });
  }
  let matchedVendor = 0;
  all.forEach(function (p) {
    if (!vsPoMatchesVendor(p, identity)) return; // different vendor — not reported, not relevant
    matchedVendor++;
    const poCo = vsPoCompanyId(p);
    if (scoped) {
      if (!poCo) return reject('noCompany', p, 'no company assigned on this Purchase Order');
      if (poCo !== wantCo) return reject('company', p, Store.name('companies', poCo) || poCo);
    }
    const st = vsNorm(p.status);
    if (VS_BAD_STATUSES.indexOf(st) !== -1) return reject('cancelled', p, p.status);
    if (!vsFlagYes(p.createVendorSettlement)) return reject('flag', p, 'Create Vendor Settlement = ' + (p.createVendorSettlement || 'No'));
    if (VS_OK_STATUSES.indexOf(st) === -1) return reject('status', p, p.status || '—');
    const dates = vsPoDates(p);
    if (!dates.length) return reject('noDate', p, 'no date on this Purchase Order');
    if (!dates.some(function (d) { return d.iso >= from && d.iso <= to; })) return reject('date', p, dates[0].iso);
    if (vsNorm(p.vendorSettlementStatus) === 'fully settled' && p.lastVendorSettlementId !== currentSettlementId)
      return reject('settled', p, p.lastVendorSettlementId || '');
    const items = (p.items && p.items.length) ? p.items : [{ materialId: p.materialId, quantity: p.quantity, ratePerTon: p.rate, gstPercent: p.gst, subtotal: p.subtotal, gstAmount: p.gstAmount, crusherSite: p.crusherSite }];
    if (items.every(function (i) { return vsIsExcluded(i, vendor); })) return reject('excluded', p, 'water / excluded material');
    eligible.push(p);
  });
  eligible.sort(function (a, b) { return vsIsoDate(a.date) > vsIsoDate(b.date) ? 1 : -1; });
  return { eligible: eligible, vendorLinked: identity.linked, scanned: all.length, matchedVendor: matchedVendor, rejects: rejects };
}

function vsGetEligiblePurchases(vendorId, periodFrom, periodTo, coId, currentSettlementId) {
  return vsAuditEligiblePurchases(vendorId, periodFrom, periodTo, coId, currentSettlementId).eligible;
}

// ── Flatten eligible POs into purchase-line rows for the settlement table ───────────────────
function vsBuildPurchaseRows(purchases) {
  const rows = [];
  purchases.forEach(function (p) {
    const items = (p.items && p.items.length) ? p.items : [{ materialId: p.materialId, quantity: p.quantity, ratePerTon: p.rate, gstPercent: p.gst, subtotal: p.subtotal, gstAmount: p.gstAmount, crusherSite: p.crusherSite }];
    const vendor = Store.byId('vendors', p.vendorId);
    items.forEach(function (it) {
      if (vsIsExcluded(it, vendor)) return;
      const qty = parseFloat(it.quantity) || 0;
      const rate = parseFloat(it.ratePerTon) || 0;
      const gstPct = parseFloat(it.gstPercent != null ? it.gstPercent : it.gst) || 0;
      const sub = it.subtotal != null ? parseFloat(it.subtotal) : qty * rate;
      const gstAmt = it.gstAmount != null ? parseFloat(it.gstAmount) : sub * gstPct / 100; // exact — no rounding
      rows.push({
        purchaseId: p.id,
        poNo: p.challanNumber || ('#' + p.id.slice(0, 6).toUpperCase()),
        date: p.date,
        vendorId: p.vendorId,
        vendorName: Store.name('vendors', p.vendorId),
        material: Store.name('materials', it.materialId) || '—',
        quantity: qty,
        rate: rate,
        gstPct: gstPct,
        amount: sub,
        gstAmount: gstAmt,
        amountWithGst: sub + gstAmt,
        challanNumber: p.challanNumber || '—',
        vehicleFull: p.vehicleFull || '—',
        crusher: Store.name('crushers', it.crusherSite || p.crusherSite) || '—',
        customer: p.toCustomerId ? (Store.name('customers', p.toCustomerId) || '—') : '—',
        companyId: p.companyId,
        status: p.status,
        settlementStatus: p.vendorSettlementStatus || 'Pending',
      });
    });
  });
  return rows;
}

function vsCalcTotals(rows, vendorDiesel, deds) {
  const gross = rows.reduce(function (s, r) { return s + (r.amountWithGst || 0); }, 0);
  const qty = rows.reduce(function (s, r) { return s + (r.quantity || 0); }, 0);
  const dsl = (vendorDiesel && vendorDiesel.total) || 0;
  const manDeds = deds.reduce(function (s, d) { return s + (parseFloat(d.amount) || 0); }, 0);
  const totalD = dsl + manDeds;
  const net = gross - totalD;
  return { gross, dsl, manDeds, totalD, net, qty, rowCount: rows.length };
}

// Update settlement status on Purchase Orders after a Vendor Settlement is saved
function vsUpdatePurchaseSettlementStatus(purchaseIds, settlementId, settlementStatus) {
  if (!purchaseIds || !purchaseIds.length) return;
  const isFinalized = settlementStatus === 'Settled';
  const today = new Date().toISOString().slice(0, 10);
  purchaseIds.forEach(function (id) {
    const rec = (Store.all('purchases') || []).find(function (r) { return r.id === id; });
    if (!rec) return;
    if (rec.vendorSettlementStatus === 'Fully Settled' && rec.lastVendorSettlementId !== settlementId) return;
    Store.update('purchases', id, Object.assign({}, rec, {
      vendorSettlementStatus: isFinalized ? 'Fully Settled' : (settlementStatus === 'Cancelled' ? 'Pending' : 'Partially Settled'),
      lastVendorSettlementId: settlementId,
      lastVendorSettlementDate: today,
    }));
  });
}

// ── Vendor Ledger — running payable balance: purchases increase payable, diesel/deductions/payments reduce it ──
function vsBuildLedger(vendorId, coId, from, to) {
  if (!vendorId) return [];
  const entries = [];
  const identity = vsResolveVendorIds(vendorId);
  const wantCo = vsResolveCompanyId(coId);
  const scoped = wantCo && wantCo !== 'group';
  const f = vsIsoDate(from), t = vsIsoDate(to);
  (Store.all('purchases', 'group') || []).filter(function (p) {
    if (!vsPoMatchesVendor(p, identity)) return false;
    if (scoped && vsPoCompanyId(p) !== wantCo) return false;
    if (VS_BAD_STATUSES.indexOf(vsNorm(p.status)) !== -1) return false;
    const d = vsIsoDate(p.date);
    if (f && d < f) return false;
    if (t && d > t) return false;
    return true;
  }).forEach(function (p) {
    const amt = window.gAmt(p);
    entries.push({ id: 'p-' + p.id, date: p.date, txType: 'Purchase Bill', desc: (p.challanNumber || '—') + ' · ' + (Store.name('materials', p.items?.[0]?.materialId || p.materialId) || ''), debit: 0, credit: amt, ref: p.challanNumber || '—', coId: p.companyId });
  });
  (Store.all('vendorDieselAllocations', 'group') || []).filter(function (d) {
    if (identity.ids.indexOf(d.vendorId) === -1) return false;
    if (scoped && vsResolveCompanyId(d.companyId) !== wantCo) return false;
    const dt = vsIsoDate(d.date);
    if (f && dt < f) return false;
    if (t && dt > t) return false;
    return true;
  }).forEach(function (d) {
    entries.push({ id: 'd-' + d.id, date: d.date, txType: 'Diesel Allocated', desc: (d.dieselSource || '—') + ' · ' + (d.litres || 0) + 'L', debit: parseFloat(d.amount) || 0, credit: 0, ref: '—', coId: d.companyId });
  });
  (Store.all('vendorSettlements', 'group') || []).filter(function (s) {
    if (identity.ids.indexOf(s.vendorId) === -1) return false;
    if (scoped && vsResolveCompanyId(s.companyId) !== wantCo) return false;
    return true;
  }).forEach(function (s) {
    (s.deductions || []).forEach(function (ded) {
      const dt = ded.date || s.periodFrom || '';
      if (from && dt < from) return;
      if (to && dt > to) return;
      const txType = vsGetDedLabel(ded);
      entries.push({ id: 'sd-' + s.id + '-' + ded.id, date: dt, txType, desc: txType + (ded.remarks ? ' — ' + ded.remarks : ''), debit: parseFloat(ded.amount) || 0, credit: 0, ref: ded.reference || s.id.slice(0, 8), coId: s.companyId });
    });
    (s.payments || []).forEach(function (pay) {
      if (from && pay.date < from) return;
      if (to && pay.date > to) return;
      entries.push({ id: 'sp-' + pay.id, date: pay.date, txType: 'Settlement Payment', desc: 'Payment — ' + (pay.mode || '') + (pay.reference ? ' Ref ' + pay.reference : ''), debit: parseFloat(pay.amount) || 0, credit: 0, ref: pay.reference || pay.chequeNumber || s.id.slice(0, 8), coId: s.companyId });
    });
  });
  entries.sort(function (a, b) { return a.date > b.date ? 1 : a.date < b.date ? -1 : 0; });
  let bal = 0;
  return entries.map(function (e) { bal += e.credit - e.debit; return Object.assign({}, e, { bal }); });
}

// ── Badges ───────────────────────────────────────────────────────────────────────────────────
function VsBadge({ s }) {
  const m = { Pending: { bg: '#F3F4F6', color: '#374151' }, 'Partially Settled': { bg: '#FEF3C7', color: '#92400E' }, Settled: { bg: '#DCFCE7', color: '#166534' }, Cancelled: { bg: '#FEE2E2', color: '#991B1B' } };
  const c = m[s] || m.Pending;
  return <span style={{ fontSize: 11, fontWeight: 700, padding: '2px 8px', borderRadius: 3, background: c.bg, color: c.color }}>{s}</span>;
}
// vsGetDedLabel — returns user-facing display name for any deduction object
function vsGetDedLabel(d) {
  if (!d) return '';
  if (d.type === 'Others') return d.othersDescription || 'Others';
  if (d.type === 'Miscellaneous') return d.customType || 'Miscellaneous';
  return d.type || '';
}

function VsDedBadge({ d, type }) {
  // Accept a full deduction object (d) or a plain type string (legacy)
  const rawType = d ? (d.type || '') : (type || '');
  const label = d ? vsGetDedLabel(d) : rawType;
  const cl = { Adjustment: '#0369A1', Advance: '#D97706', RTO: '#1D4ED8', 'Royalty Recovery': '#7C3AED', Penalty: '#DC2626', 'Quality Deduction': '#B45309', 'Short Supply': '#DC2626', 'Damage Recovery': '#059669', Miscellaneous: '#6B7280', Others: '#0891B2' };
  const c = cl[rawType] || '#6B7280';
  return <span style={{ fontSize: 10, fontWeight: 700, padding: '1px 6px', borderRadius: 3, background: c + '22', color: c }}>{label}</span>;
}
function VsPurchaseStatusBadge({ status }) {
  const cfg = { Pending: { bg: '#F3F4F6', color: '#374151' }, 'Partially Settled': { bg: '#FEF3C7', color: '#92400E' }, 'Fully Settled': { bg: '#DCFCE7', color: '#166534' } };
  const c = cfg[status] || cfg.Pending;
  return <span style={{ fontSize: 10, fontWeight: 700, padding: '2px 6px', borderRadius: 3, background: c.bg, color: c.color, whiteSpace: 'nowrap' }}>{status || 'Pending'}</span>;
}

// ── Empty-result diagnostic ──────────────────────────────────────────────────────────────────
// When no Purchase Orders come back, show WHY — per stage, with the actual PO numbers — so an
// empty settlement is never ambiguous. Reads only the audit produced by the engine.
// Resolve the settlements that already own the excluded Purchase Orders, so the operator is
// told WHERE the lines went instead of just "already settled".
function vsSettledHint(rows) {
  const seen = [];
  (rows || []).forEach(function (x) {
    if (!x.detail || seen.indexOf(x.detail) !== -1) return;
    seen.push(x.detail);
  });
  const refs = seen.map(function (id) {
    const s = Store.byId('vendorSettlements', id);
    if (!s) return 'a settlement that no longer exists';
    return window.fmtDate(s.periodFrom) + '–' + window.fmtDate(s.periodTo) + ' · ' + (s.status || '') + (s.companyId && s.companyId !== 'group' ? ' · ' + (Store.name('companies', s.companyId) || '') : ' · OM Group');
  });
  return refs.length
    ? 'These lines belong to: ' + refs.join(' | ') + '. Open that settlement and edit it — its own lines always remain available inside it.'
    : 'Open the settlement that already contains these lines and edit it instead.';
}
function VsNoPoDiagnostic({ audit, coId }) {
  const a = audit || {};
  const r = a.rejects || {};
  const coName = coId && coId !== 'group' ? (Store.name('companies', vsResolveCompanyId(coId)) || '') : '';
  const list = function (arr) {
    return (arr || []).slice(0, 6).map(function (x) { return x.poNo; }).join(', ') + ((arr || []).length > 6 ? ' +' + ((arr || []).length - 6) + ' more' : '');
  };
  const lines = [
    ['flag', 'Create Vendor Settlement = No', 'Open the Purchase Order in Purchases and set Create Vendor Settlement to Yes.'],
    ['date', 'Dated outside this settlement period', 'Widen Period From / Period To, or check the Purchase Order date.'],
    ['status', 'Status is not Delivered / Completed', 'Only Delivered or Completed orders can be settled.'],
    ['cancelled', 'Cancelled / archived', 'Cancelled orders are never settled.'],
    ['settled', 'Already fully settled in another settlement', vsSettledHint(r.settled)],
    ['company', 'Belongs to a different company', 'Create the settlement under that company instead.'],
    ['noCompany', 'No company assigned on the Purchase Order', 'Assign a company to the order in Purchases.'],
    ['noDate', 'No date on the Purchase Order', 'Set the order date in Purchases.'],
    ['excluded', 'Excluded material (water)', 'Water purchases are never vendor-settled.'],
  ].filter(function (l) { return (r[l[0]] || []).length; });
  return (
    <div style={{ background: '#F9FAFB', border: '1px solid var(--bdr)', borderRadius: 6, padding: '14px 16px', marginBottom: 12, color: 'var(--txt2)', fontSize: 12 }}>
      <div style={{ fontWeight: 700, color: 'var(--txt)', marginBottom: 6 }}>No eligible Purchase Orders found</div>
      <div style={{ marginBottom: lines.length ? 10 : 0 }}>
        Scanned {a.matchedVendor || 0} Purchase Order{(a.matchedVendor || 0) !== 1 ? 's' : ''} for this vendor{coName ? ' across all companies' : ''}
        {(a.vendorLinked || []).length ? ' (including ' + a.vendorLinked.length + ' linked vendor record' + (a.vendorLinked.length !== 1 ? 's' : '') + ' with the same name)' : ''}.
        {coName ? ' Settlement company: ' + coName + '.' : ''}
      </div>
      {lines.length ? (
        <div style={{ display: 'grid', gap: 8 }}>
          {lines.map(function (l) {
            return (
              <div key={l[0]} style={{ background: '#fff', border: '1px solid var(--bdr)', borderRadius: 5, padding: '8px 10px' }}>
                <div style={{ fontWeight: 700, color: 'var(--txt)', fontSize: 11.5 }}>{r[l[0]].length} excluded — {l[1]}</div>
                <div style={{ fontFamily: 'var(--font)', fontSize: 11, color: 'var(--txt3)', margin: '3px 0' }}>{list(r[l[0]])}</div>
                <div style={{ fontSize: 11 }}>{l[2]}</div>
              </div>);
          })}
        </div>
      ) : (
        <div>This vendor has no Purchase Orders at all yet. Create one in <strong>Purchases</strong> with <strong>Create Vendor Settlement = Yes</strong>.</div>
      )}
    </div>);
}

window.VS_STATUSES = VS_STATUSES;
window.vsGetDedLabel = vsGetDedLabel;
window.VS_DED_TYPES = VS_DED_TYPES;
window.VS_PAY_MODES = VS_PAY_MODES;
window.VS_PAY_MODE_CONFIG = VS_PAY_MODE_CONFIG;
window.vsPayModeConfig = vsPayModeConfig;
window.VS_PAY_REF_COLUMN_LABEL = VS_PAY_REF_COLUMN_LABEL;
window.vsPayRefDisplay = vsPayRefDisplay;
window.vsGetEligiblePurchases = vsGetEligiblePurchases;
window.vsAuditEligiblePurchases = vsAuditEligiblePurchases;
window.vsNorm = vsNorm;
window.vsIsoDate = vsIsoDate;
window.vsResolveCompanyId = vsResolveCompanyId;
window.vsResolveVendorIds = vsResolveVendorIds;
window.vsPoCompanyId = vsPoCompanyId;
window.vsPoMatchesVendor = vsPoMatchesVendor;
window.vsBuildPurchaseRows = vsBuildPurchaseRows;
window.vsCalcTotals = vsCalcTotals;
window.vsUpdatePurchaseSettlementStatus = vsUpdatePurchaseSettlementStatus;
window.vsBuildLedger = vsBuildLedger;
window.VsBadge = VsBadge;
window.VsDedBadge = VsDedBadge;
window.VsPurchaseStatusBadge = VsPurchaseStatusBadge;
window.VsNoPoDiagnostic = VsNoPoDiagnostic;
