// data.jsx - VaultCova mock data + helpers (exported to window)

// Thin space (U+2009) after the symbol: JetBrains Mono sets ₦ tight against the
// first digit, so "₦3.7B" read as if they collided. The hair of space fixes it
// everywhere money is formatted, without looking spaced-out in running text.
const NAIRA = "₦ ";

// Compact money for summaries and cards: ₦2.5M, ₦1.2B, ₦58K. One decimal at
// most, trailing ".0" stripped (parseFloat), so it reads clean and scales the
// same whether someone holds ₦2.5M or ₦25B — never a wall of digits.
function fmtNaira(n) {
  if (n == null) return "-";
  n = Number(n) || 0;
  const short = (v, suffix) => NAIRA + parseFloat(v.toFixed(1)) + suffix;
  if (n >= 1e9) return short(n / 1e9, "B");
  if (n >= 1e6) return short(n / 1e6, "M");
  if (n >= 1e3) return NAIRA + Math.round(n / 1e3) + "K";
  return NAIRA + Math.round(n).toLocaleString();
}
function fmtFull(n) {
  if (n == null) return "-";
  return NAIRA + Math.round(n).toLocaleString("en-NG");
}

// asset categories -> placeholder hue + label
const CATEGORIES = {
  vehicle:   { label: "Vehicle",    hue: 210, glyph: "car" },
  property:  { label: "Property",   hue: 150, glyph: "home" },
  equipment: { label: "Equipment",  hue: 280, glyph: "cog" },
  electronics:{ label: "Electronics",hue: 30, glyph: "chip" },
  inventory: { label: "Inventory",  hue: 340, glyph: "box" },
  jewelry:   { label: "Valuables",  hue: 50,  glyph: "gem" },
  marine:    { label: "Marine",     hue: 190, glyph: "ship" },
};

// status: insured | partial | lapsing | uninsured
const STATUS_META = {
  insured:   { label: "Insured",     color: "var(--success)", soft: "var(--success-soft)" },
  partial:   { label: "Underinsured",color: "var(--warning)", soft: "var(--warning-soft)" },
  lapsing:   { label: "Lapsing",     color: "var(--warning)", soft: "var(--warning-soft)" },
  uninsured: { label: "Uninsured",   color: "var(--danger)",  soft: "var(--danger-soft)" },
};

let _id = 100;
const nextId = () => "VA-" + (++_id);

// ---- Business profile assets ----
const BUSINESS_ASSETS = [
  { id: "VA-01", name: "Toyota Hilux Fleet (×3)", category: "vehicle", purchase: 38000000, replacement: 52000000, sumInsured: 52000000, status: "insured", bundle: "fleet", insurer: "Leadway Assurance", premium: 1850000, renews: "2026-03-12", note: "Logistics delivery fleet, Lagos" },
  { id: "VA-02", name: "Cold Storage Warehouse", category: "property", purchase: 320000000, replacement: 410000000, sumInsured: 300000000, status: "partial", bundle: "premises", insurer: "AXA Mansard", premium: 4200000, renews: "2026-01-22", note: "2,000-pallet facility, Ogun State" },
  { id: "VA-03", name: "Refrigeration Units (×12)", category: "equipment", purchase: 96000000, replacement: 128000000, sumInsured: 128000000, status: "insured", bundle: "premises", insurer: "AXA Mansard", premium: 1100000, renews: "2026-01-22", note: "Machinery breakdown cover" },
  { id: "VA-04", name: "Frozen Inventory (rolling)", category: "inventory", purchase: 140000000, replacement: 140000000, sumInsured: 90000000, status: "partial", bundle: null, insurer: "AXA Mansard", premium: 980000, renews: "2026-01-22", note: "Stock throughput cover" },
  { id: "VA-05", name: "Forklifts (×4)", category: "equipment", purchase: 44000000, replacement: 58000000, sumInsured: 0, status: "uninsured", bundle: null, insurer: null, premium: 0, renews: null, note: "Recently acquired - not yet covered" },
  { id: "VA-06", name: "Office Generators (×2)", category: "equipment", purchase: 18000000, replacement: 24000000, sumInsured: 24000000, status: "lapsing", bundle: "premises", insurer: "Custodian", premium: 320000, renews: "2025-12-30", note: "Renewal due in 22 days" },
  { id: "VA-07", name: "Marine Cargo Shipment", category: "marine", purchase: 210000000, replacement: 210000000, sumInsured: 210000000, status: "insured", bundle: null, insurer: "Leadway Assurance", premium: 2450000, renews: "2026-06-15", note: "Lagos → Port Harcourt, in transit" },
];

// ---- Individual profile assets ----
const INDIVIDUAL_ASSETS = [
  { id: "VA-11", name: "Toyota Land Cruiser 2023", category: "vehicle", purchase: 78000000, replacement: 92000000, sumInsured: 92000000, status: "insured", bundle: "household", insurer: "AIICO", premium: 1380000, renews: "2026-04-02", note: "Comprehensive motor" },
  { id: "VA-12", name: "Family Home - Lekki", category: "property", purchase: 280000000, replacement: 350000000, sumInsured: 250000000, status: "partial", bundle: "household", insurer: "Leadway Assurance", premium: 1750000, renews: "2026-02-18", note: "Building + contents" },
  { id: "VA-13", name: "Rolex Submariner", category: "jewelry", purchase: 32000000, replacement: 41000000, sumInsured: 0, status: "uninsured", bundle: null, insurer: null, premium: 0, renews: null, note: "Valuables - needs all-risks cover" },
  { id: "VA-14", name: "MacBook Pro + Studio Setup", category: "electronics", purchase: 6800000, replacement: 7400000, sumInsured: 7400000, status: "lapsing", bundle: "household", insurer: "AXA Mansard", premium: 96000, renews: "2025-12-28", note: "Portable electronics" },
  { id: "VA-15", name: "Art Collection (×6)", category: "jewelry", purchase: 24000000, replacement: 30000000, sumInsured: 0, status: "uninsured", bundle: null, insurer: null, premium: 0, renews: null, note: "Fine art - appraisal pending" },
];

const BUNDLES = {
  business: [
    { id: "fleet", name: "Fleet & Transit", desc: "Vehicles in motion & cargo", icon: "car" },
    { id: "premises", name: "Premises & Plant", desc: "Buildings, machinery, equipment", icon: "home" },
  ],
  individual: [
    { id: "household", name: "Household", desc: "Home, motor & contents", icon: "home" },
  ],
};

const QUOTES = [
  { insurer: "Leadway Assurance", premium: 4250000, rating: 4.7, excess: "₦250K", claimDays: 14, badge: "Best value", features: ["Fire & perils", "Business interruption", "Machinery breakdown"] },
  { insurer: "AXA Mansard", premium: 4800000, rating: 4.6, excess: "₦200K", claimDays: 10, badge: "Fastest claims", features: ["Fire & perils", "Business interruption", "Burglary", "Public liability"] },
  { insurer: "AIICO Insurance", premium: 4100000, rating: 4.5, excess: "₦400K", claimDays: 18, badge: null, features: ["Fire & perils", "Machinery breakdown"] },
  { insurer: "Custodian", premium: 4550000, rating: 4.4, excess: "₦300K", claimDays: 16, badge: null, features: ["Fire & perils", "Business interruption", "Public liability"] },
];

const CLAIMS = [
  { id: "CL-2026-0021", asset: "Toyota Hilux Fleet", type: "Motor accident", loss: 6500000, status: "In progress", date: "2026-05-10", stage: 2 },
  { id: "CL-2026-0018", asset: "Cold Storage Warehouse", type: "Power surge", loss: 3200000, status: "Survey done", date: "2026-04-28", stage: 3 },
  { id: "CL-2025-0044", asset: "Marine Cargo", type: "Transit damage", loss: 9800000, status: "Settled", date: "2025-11-02", stage: 5 },
];

const CLAIM_STAGES = ["Reported", "Documents", "Survey", "Insurer review", "Settlement"];

// ---- Admin: insurer partners ----
const ADMIN_INSURERS = [
  { id: "INS-01", name: "Leadway Assurance", lines: ["Motor", "Marine", "Fire"], rating: 4.7, policies: 412, claimsRatio: "38%", status: "active", since: "2024" },
  { id: "INS-02", name: "AXA Mansard", lines: ["Property", "Liability", "Health"], rating: 4.6, policies: 358, claimsRatio: "41%", status: "active", since: "2024" },
  { id: "INS-03", name: "AIICO Insurance", lines: ["Motor", "Life", "Valuables"], rating: 4.5, policies: 290, claimsRatio: "35%", status: "active", since: "2025" },
  { id: "INS-04", name: "Custodian", lines: ["Fire", "Engineering"], rating: 4.4, policies: 176, claimsRatio: "44%", status: "paused", since: "2025" },
];

// ---- Cova risk assessment engine (transparent heuristic) ----
const RISK_BASE = { vehicle: 52, property: 44, equipment: 46, electronics: 38, inventory: 58, jewelry: 64, marine: 70 };
const INFO_NEEDED = {
  vehicle: ["Private or commercial use?", "Where is it parked overnight?"],
  property: ["Any flood history at this location?", "Is the building occupied 24/7?"],
  equipment: ["Is it operated by certified staff?"],
  electronics: ["Does it leave the premises?"],
  inventory: ["Is stock value seasonal?"],
  jewelry: ["Do you have a recent valuation report?", "Is it kept in a safe?"],
  marine: ["Which route does the cargo take?", "Is packing professionally done?"],
};
function assessRisk(asset) {
  let score = RISK_BASE[asset.category] ?? 50;
  const factors = [];
  factors.push("Auto-detected: " + (CATEGORIES[asset.category]?.label || "Asset"));
  if (asset.replacement >= 100000000) { score += 16; factors.push("High value (" + fmtNaira(asset.replacement) + ")"); }
  else if (asset.replacement >= 50000000) { score += 9; factors.push("Mid-high value (" + fmtNaira(asset.replacement) + ")"); }
  else factors.push("Value within standard band");
  if (asset.category === "marine") factors.push("Transit exposure - route-dependent");
  if (asset.category === "jewelry") factors.push("Portable & theft-attractive");
  if (asset.category === "vehicle") factors.push("Lagos traffic accident frequency");
  const level = score >= 66 ? "High" : score >= 48 ? "Medium" : "Low";
  const flag = level === "High" || asset.replacement >= 90000000;
  return {
    score: Math.min(95, score), level, factors: factors.slice(0, 3),
    infoNeeded: (INFO_NEEDED[asset.category] || []).slice(0, 2),
    flag,
    recommendation: level === "High"
      ? "Needs underwriter review before binding - I've flagged it to our team."
      : level === "Medium" ? "Insurable at standard terms once the questions below are answered."
      : "Low risk - I can bind cover instantly at the best matched rate.",
    premiumRate: level === "High" ? 0.018 : level === "Medium" ? 0.012 : 0.009,
  };
}
function assessClaim(claim, insured) {
  const auto = insured && claim.loss < 5000000;
  return {
    decision: auto ? "auto" : "flag",
    confidence: auto ? 0.93 : 0.61,
    note: auto
      ? "Loss is within auto-settlement limits and the policy is in force. Fast-tracked for settlement."
      : !insured ? "Asset has no active policy - routed to our team for manual review."
      : "Loss exceeds the auto-settlement threshold - it requires further assessment, settled within the 8-day average window or less.",
  };
}

// ============================================================
// Risk Discovery & Cross-Sell Engine
// Knowledge graph of customer exposures with confidence scores.
// Discovers naturally from chat, assets, policies, claims, docs.
// Recommends gently, only when confidence > 0.7.
// ============================================================
const RISK_FACTS = {
  vehicle:            { label: "Vehicle ownership",       dim: "Personal assets" },
  property:           { label: "Property ownership",      dim: "Personal assets" },
  contents:           { label: "Valuable contents",       dim: "Personal assets" },
  travel:             { label: "Travel habits",           dim: "Personal assets" },
  business:           { label: "Business ownership",      dim: "Business assets" },
  inventory:          { label: "Inventory / stock",       dim: "Business assets" },
  equipment:          { label: "Equipment / plant",       dim: "Business assets" },
  premises:           { label: "Warehouse / premises",    dim: "Business assets" },
  employees:          { label: "Employees",               dim: "Human exposure" },
  dependants:         { label: "Dependants",              dim: "Human exposure" },
  transit:            { label: "Goods in transit",        dim: "Logistics exposure" },
  commercialVehicles: { label: "Commercial vehicles",     dim: "Logistics exposure" },
  loans:              { label: "Loans / financing",       dim: "Financial exposure" },
  interruption:       { label: "Interruption exposure",   dim: "Financial exposure" },
};

// graph = { facts: { vehicle: {conf, sources:[], value?} }, log: [] }
function emptyGraph() { return { facts: {}, log: [] }; }

function graphLearn(graph, fact, conf, source, value) {
  const g = { facts: { ...graph.facts }, log: [...graph.log] };
  const prev = g.facts[fact];
  const newConf = Math.max(prev?.conf || 0, conf);
  g.facts[fact] = { conf: newConf, sources: [...new Set([...(prev?.sources || []), source])], value: value ?? prev?.value };
  if (!prev || newConf > prev.conf + 0.001) {
    g.log.unshift({ fact, conf: newConf, source, time: "Just now" });
    g.log = g.log.slice(0, 12);
  }
  return g;
}

// Seed from account type + VaultLog assets (source: vaultlog/policy)
function seedGraph(profile, assets) {
  let g = emptyGraph();
  if (profile === "business") g = graphLearn(g, "business", 1.0, "Account type");
  const catFact = { vehicle: "vehicle", property: "property", equipment: "equipment", inventory: "inventory", marine: "transit", jewelry: "contents", electronics: "contents" };
  assets.forEach((a) => {
    const f = catFact[a.category];
    if (f) g = graphLearn(g, f, a.insurer ? 1.0 : 0.95, a.insurer ? "Policy purchased" : "VaultLog asset");
    if (a.category === "marine") g = graphLearn(g, "interruption", 0.75, "Cargo in transit");
    if (profile === "business" && a.category === "property") g = graphLearn(g, "premises", 0.95, "VaultLog asset");
  });
  return g;
}

// Incremental discovery from natural language - returns [{fact, conf, source, value?}]
function detectRiskSignals(text) {
  const t = text.toLowerCase();
  const sig = [];
  const add = (fact, conf, value) => sig.push({ fact, conf, source: "Chat", value });
  const numMatch = t.match(/(\d+)\s*(staff|employees?|workers?|people|drivers?)/);
  if (numMatch) add("employees", 0.9, parseInt(numMatch[1], 10));
  else if (/\b(staff|employees?|workers?|my team|payroll)\b/.test(t)) add("employees", 0.75);
  if (/\b(vans?|trucks?|lorr(y|ies)|delivery|dispatch riders?|fleet)\b/.test(t)) { add("commercialVehicles", 0.85); add("transit", 0.8); }
  if (/\b(warehouse|factory|workshop|store ?room)\b/.test(t)) { add("premises", 0.85); add("business", 0.9); }
  if (/\b(my (shop|store|office|business)|we sell|customers)\b/.test(t)) add("business", 0.9);
  if (/\b(stock|inventory|goods|merchandise|raw materials?)\b/.test(t)) add("inventory", 0.85);
  if (/\b(my (house|home|apartment|flat|duplex)|flooded|landlord|tenants?)\b/.test(t)) add("property", 0.7);
  if (/\b(travel|trip|abroad|airport|visa|holiday)\b/.test(t)) add("travel", 0.75);
  if (/\b(loans?|financing|leased?|mortgage|collateral)\b/.test(t)) add("loans", 0.8);
  if (/\b(my (wife|husband|kids|children|family))\b/.test(t)) add("dependants", 0.8);
  if (/\b(car|jeep|suv|sedan|my ride)\b/.test(t)) add("vehicle", 0.85);
  if (/\b(ship(ment|ping)?|cargo|consignment|import|export)\b/.test(t)) add("transit", 0.85);
  return sig;
}

// Cross-sell triggers (spec) - gentle, ranked, only conf > 0.7, skipping covered lines
function crossSell(graph, assets) {
  const f = (k) => graph.facts[k]?.conf || 0;
  const has = (cat, insuredOnly) => assets.some((a) => a.category === cat && (!insuredOnly || a.insurer));
  const recs = [];
  const push = (id, products, reason, severity, conf) => recs.push({ id, products, reason, severity, conf, score: Math.round(severity * conf * 20) });

  if (f("vehicle") > 0.7 && f("property") > 0.7 && !has("property", true))
    push("home", ["Home Insurance", "Contents Insurance"], "I noticed you own a vehicle and likely a home, but I don't see home cover recorded. One storm or fire could cost far more than a year of premium - want to explore options?", 4, Math.min(f("vehicle"), f("property")));
  if (f("business") > 0.7 && !assets.some((a) => ["property", "equipment"].includes(a.category) && a.insurer))
    push("sme", ["Business Package", "Fire Insurance", "Burglary Insurance"], "You run a business, but I don't see core business protection recorded. A single fire or break-in could interrupt everything - shall we look at what cover would fit?", 5, f("business"));
  if (f("inventory") > 0.7 && !has("inventory", true))
    push("stock", ["Stock Insurance", "Fire Insurance", "Business Interruption"], "You've mentioned holding stock. If it's uninsured, a fire or flood would be a double loss - the goods and the income. Would you like me to size the right cover?", 5, f("inventory"));
  if (f("employees") > 0.7 && (graph.facts.employees?.value || 0) > 3)
    push("people", ["Group Life", "Employee Compensation", "Health Benefits"], `With ${graph.facts.employees.value} people depending on your business, Group Life and Employee Compensation aren't just statutory - they protect the people who keep you running. Want to see options?`, 4, f("employees"));
  if (f("transit") > 0.7 && !has("marine", true))
    push("transit", ["Goods in Transit", "Marine Cargo"], "Your goods move - and most losses happen on the road. Goods-in-Transit cover is one of the cheapest protections relative to what it saves. Interested?", 4, f("transit"));
  const bigProp = assets.find((a) => a.category === "property" && a.replacement >= 100000000 && !a.insurer);
  if (bigProp)
    push("fire", ["Fire & Special Perils", "Building Insurance"], `${bigProp.name} is worth ${fmtNaira(bigProp.replacement)} and has no fire protection recorded. That's a significant single point of loss - want me to get quotes?`, 5, 0.95);

  return recs.sort((a, b) => b.score - a.score);
}

// ---- Subscription architecture ----
// Free Vault is capped; higher tiers raise the cap. Cova insights are on every
// tier. Annual billing = pay for 10 months, get 2 FREE (a clean "2 months free"
// offer, ≈16.7% off). (Mirror of the Plan seed in prisma/seed.)
const FREE_ASSET_CAP = 35;
const ANNUAL_MONTHS_FREE = 2;           // 2 months free on annual
const ANNUAL_PAID_MONTHS = 12 - ANNUAL_MONTHS_FREE; // pay for 10
const ANNUAL_DISCOUNT = ANNUAL_MONTHS_FREE / 12;    // ≈0.1667, derived — keep in sync
// Exact annual charge for a monthly price (no rounding drift): 10 × monthly.
const annualTotal = (monthly) => monthly * ANNUAL_PAID_MONTHS;
// Effective per-month figure to display on annual (for the "/mo" line).
const annualPerMonth = (monthly) => Math.round(monthly * ANNUAL_PAID_MONTHS / 12);
const PLANS = [
  { id: "free", name: "Free Vault", price: 0, per: "forever", assetCap: FREE_ASSET_CAP, who: "Start your vault, insure when you're ready", color: "var(--text-muted)",
    feats: [`Track up to ${FREE_ASSET_CAP} assets`, "Automatic asset grouping", "Cova insights & risk score", "Schedule-of-assets export (PDF)", "Buy, compare & renew policies", "Claims & Cova guidance"] },
  { id: "individual", name: "Individual Vault", price: 800, per: "/month", assetCap: 80, who: "Individuals with more to protect", color: "var(--accent-2)",
    feats: ["Everything in Free Vault", "Up to 80 assets", "Renewal & valuation reminders", "VaultRewards cashback"] },
  { id: "pro", name: "Pro Vault", price: 2500, per: "/month", assetCap: 150, who: "Power users & growing households", color: "var(--accent)",
    feats: ["Everything in Individual Vault", "Up to 150 assets", "Assign up to 3 team members", "Risk dashboard & gap analysis", "Bundle savings optimiser", "Priority Cova support"] },
  { id: "business", name: "Business Vault", price: 4500, per: "/month", assetCap: null, who: "Businesses, warehouses & logistics", color: "var(--accent)",
    feats: ["Everything in Pro Vault", "Unlimited assets", "Assign up to 5 team members", "Group assets by location (site, warehouse, office)", "Insure a whole site, building & contents", "One master policy across every location", "Executive dashboard & dedicated support"] },
];

// Bundle savings — prorated by asset type + risk, hard-capped (ops-managed).
// Mirror of lib/bundle.ts; config comes from /api/settings (window.VC_BUNDLE).
const BUNDLE_DEFAULTS = { maxPct: 10, defaultPct: 7, riskPenalty: 0.4, perCategory: { property: 10, vehicle: 8, equipment: 8, electronics: 6, inventory: 6, jewelry: 4, marine: 3 } };
function bundleDiscount(assets, config) {
  const c = config || (typeof window !== "undefined" && window.VC_BUNDLE) || BUNDLE_DEFAULTS;
  if (!assets || assets.length < 2) return 0;
  const total = assets.reduce((s, a) => s + (a.replacement || 0), 0);
  let weighted = 0;
  for (const a of assets) {
    const rate = (c.perCategory && c.perCategory[a.category] != null) ? c.perCategory[a.category] : c.defaultPct;
    const w = total > 0 ? (a.replacement || 0) / total : 1 / assets.length;
    weighted += rate * w;
  }
  const highRisk = assets.filter((a) => ["marine", "jewelry"].includes(a.category) || (a.replacement || 0) >= 100000000).length;
  const riskFactor = 1 - Math.min(1, highRisk / assets.length) * (c.riskPenalty != null ? c.riskPenalty : 0.4);
  return Math.max(0, Math.min(c.maxPct != null ? c.maxPct : 10, +(weighted * riskFactor).toFixed(1)));
}

// Contextual upgrade nudges (never hard-sell). Ladder- and cap-aware, and only
// ever points at a real tier (free → individual → pro → business).
function upgradeSignal(plan, profile, assets, graph) {
  const f = (k) => graph.facts[k]?.conf || 0;
  const n = assets.length;
  const business = profile === "business" || f("business") > 0.7 || f("inventory") > 0.7;
  if (plan === "free") {
    if (business)
      return { to: "business", reason: "You're tracking business assets and inventory. Business Vault removes the asset cap entirely and adds gap analysis, a risk dashboard, multi-location and team access - built for exactly this." };
    if (n >= FREE_ASSET_CAP - 7)
      return { to: "individual", reason: `You're getting close to the ${FREE_ASSET_CAP}-asset Free Vault limit. Individual Vault (₦800/mo) raises it to 80 and adds schedule-of-assets export, renewal reminders and VaultRewards cashback.` };
  }
  if (plan === "individual" && n >= 64)
    return { to: "pro", reason: "You're approaching the 80-asset limit. Pro Vault (₦2,500/mo) lifts it to 150 and adds the risk dashboard, gap analysis and the bundle savings optimiser." };
  if (plan === "pro" && (n >= 120 || business))
    return { to: "business", reason: "With this many assets and a growing operation, Business Vault removes the cap entirely and adds multi-location tracking, team members and an executive risk dashboard." };
  return null;
}

// Cova surveyor recommendation: score by specialty match, region, capacity, rating, speed
// ---- derived helpers ----
function portfolio(assets) {
  const replacement = assets.reduce((s, a) => s + a.replacement, 0);
  const insured = assets.reduce((s, a) => s + a.sumInsured, 0);
  const gap = Math.max(0, replacement - insured);
  const premium = assets.reduce((s, a) => s + (a.premium || 0), 0);
  const counts = { insured: 0, partial: 0, lapsing: 0, uninsured: 0 };
  assets.forEach((a) => { counts[a.status] = (counts[a.status] || 0) + 1; });
  return { replacement, insured, gap, premium, counts, covered: replacement ? insured / replacement : 0 };
}

function statusFor(a) {
  if (!a.sumInsured) return "uninsured";
  if (a.sumInsured < a.replacement * 0.9) return "partial";
  return a.status === "lapsing" ? "lapsing" : "insured";
}

// A short, human-readable asset reference shown in the vault (instead of the
// raw database id). Shape: <LETTERS>[-<MODEL#>]-<YYMMDD>-<NNN>, e.g.
//   "iPhone 12"    added 2026-07-18, 3rd asset  -> IP-12-260718-003
//   "Land Cruiser" added same day,   2nd asset  -> LC-260718-002
// LETTERS come from the name (first two words' initials, or first two letters
// of a single word); the model number is any number in the name; the date is
// when it was added; NNN is the asset's position in the user's vault by add
// order — so no two of a user's assets ever share a reference.
function assetRef(asset, all) {
  if (!asset) return "";
  const name = String(asset.name || "").trim();
  const words = name.split(/\s+/).filter((w) => /[A-Za-z]/.test(w));
  let alpha;
  if (words.length >= 2) alpha = words.slice(0, 2).map((w) => (w.replace(/[^A-Za-z]/g, "")[0] || "")).join("");
  else alpha = (words[0] || "AS").replace(/[^A-Za-z]/g, "").slice(0, 2);
  alpha = (alpha || "AS").toUpperCase().slice(0, 3);
  const numMatch = name.match(/\d+/);
  const model = numMatch ? "-" + numMatch[0].slice(0, 4) : "";
  const d = asset.createdAt ? new Date(asset.createdAt) : new Date();
  const date = String(d.getFullYear()).slice(2) + String(d.getMonth() + 1).padStart(2, "0") + String(d.getDate()).padStart(2, "0");
  const ordered = (all || []).filter(Boolean).slice().sort((a, b) =>
    (new Date(a.createdAt || 0)) - (new Date(b.createdAt || 0)) || String(a.id).localeCompare(String(b.id)));
  const idx = ordered.findIndex((a) => a.id === asset.id);
  const seq = String((idx < 0 ? ordered.length : idx) + 1).padStart(3, "0");
  return alpha + model + "-" + date + "-" + seq;
}

window.VC_DATA = {
  NAIRA, fmtNaira, fmtFull, CATEGORIES, STATUS_META, BUSINESS_ASSETS, INDIVIDUAL_ASSETS,
  BUNDLES, QUOTES, CLAIMS, CLAIM_STAGES, portfolio, statusFor, nextId, assetRef,
  ADMIN_INSURERS, assessRisk, assessClaim,
  RISK_FACTS, emptyGraph, graphLearn, seedGraph, detectRiskSignals, crossSell,
  PLANS, FREE_ASSET_CAP, ANNUAL_DISCOUNT, ANNUAL_MONTHS_FREE, ANNUAL_PAID_MONTHS,
  annualTotal, annualPerMonth, BUNDLE_DEFAULTS, bundleDiscount, upgradeSignal,
};
