// ZINTEX Tech Stack — data source
// Exports:
//   window.DEPARTMENTS, window.deptColor
//   window.DEFAULT_TOOLS  (built-in fallback used when Google Sheet isn't reachable)
//   window.loadTools(sheetUrl)   async — fetches CSV, returns { tools, source, updatedAt, error }
//   window.buildStats(tools)
//   window.parseCSV(text)

const DEPARTMENTS = [
  { id: "All",          label: "Company-wide",   hue: 25,  short: "ALL" },
  { id: "CRM",          label: "CRM",            hue: 220, short: "CRM" },
  { id: "Sales",        label: "Sales",          hue: 50,  short: "SLS" },
  { id: "Call Center",  label: "Call Center",    hue: 170, short: "CC"  },
  { id: "Production",   label: "Production",     hue: 140, short: "PRD" },
  { id: "Marketing",    label: "Marketing",      hue: 320, short: "MKT" },
  { id: "Accounting",   label: "Accounting",     hue: 100, short: "ACC" },
  { id: "IT",           label: "IT",             hue: 250, short: "IT"  },
  { id: "HR",           label: "HR",             hue: 290, short: "HR"  },
  { id: "Recruiting",   label: "Recruiting",     hue: 350, short: "REC" },
  { id: "Company Wide", label: "Company Wide",   hue: 0,   short: "CW",  neutral: true },
  { id: "Multiple",     label: "Multiple",       hue: 200, short: "MUL", neutral: true },
  { id: "President",    label: "President",      hue: 70,  short: "PRS" },
];

const deptColor = (id, l = 0.72, c = 0.13) => {
  const d = DEPARTMENTS.find((x) => x.id === id);
  if (!d) return `oklch(${l} 0 0)`;
  if (d.neutral) return `oklch(${l} 0.02 ${d.hue})`;
  return `oklch(${l} ${c} ${d.hue})`;
};

// ---------- Default tool data (fallback when no sheet configured) ----------
// `logoFile` → loaded from assets/<logoFile> by LogoTile via logoUrl.
// `logoBg`   → tile background (default white).
// `logoFullBleed` → if true, no padding (logo fills tile; use for self-contained logos).

const DEFAULT_TOOLS = [
  { name: "Itilite", useCase: "Travel booking & management", dept: "All", connects: ["Sales","Production","Company Wide"], monthly: 75000, qtrly: 225000, annual: 900000, billing: "Term — Monthly", notes: "Travel platform used company-wide for crew + sales travel.", monogram: "It", swatch: ["#EB5C24","#FF8A4C"], logoFile: "itilite.svg", logoBg: "#ffffff" },
  { name: "Salesforce + Slack + OwnBackup", useCase: "CRM database, internal comms, and backup", dept: "CRM", connects: ["Sales","Marketing","Company Wide","Call Center"], monthly: 62507.77, qtrly: 187523.30, annual: 750093.20, billing: "Quarterly bill — 2/1/26 thru 4/30/26", expires: "2026-04-30", notes: "Bundled CRM + collaboration + backup contract.", monogram: "SF", swatch: ["#1B5DA8","#4FB7E8"], logoFile: "salesforce.svg", logoBg: "#ffffff" },
  { name: "Regal", useCase: "Call center dialer system", dept: "Call Center", connects: ["Sales","CRM"], monthly: 41722.45, qtrly: 125167.34, annual: 500669.36, billing: "Monthly — costs include overages", notes: "Overage charges roll into the monthly invoice.", monogram: "RG", swatch: ["#5B2EAD","#9D6BFF"] },
  { name: "Rillavoice", useCase: "Sales appointment AI / conversation intel", dept: "Sales", connects: ["Call Center","CRM"], monthly: 15862.08, qtrly: 49447.96, annual: 197791.84, billing: "Monthly", monogram: "RV", swatch: ["#0E7C66","#34D399"], logoFile: "rilla.jpg", logoFullBleed: true },
  { name: "Active Prospect", useCase: "Lead generation funnel", dept: "CRM", connects: ["Sales","Marketing"], monthly: 15572.52, qtrly: 46717.57, annual: 186870.28, billing: "Annual", expires: "2027-05-01", notes: "Expiration 5/1/2027.", monogram: "AP", swatch: ["#B45309","#F59E0B"] },
  { name: "LEAP (SalesPro)", useCase: "Field sales / in-home estimating tool", dept: "Sales", connects: ["Production","CRM"], monthly: 12450.50, qtrly: 37351.50, annual: 149406.00, billing: "Monthly", monogram: "LP", swatch: ["#0B5FFF","#4F8DFF"] },
  { name: "Company Cam", useCase: "Photo-based project management", dept: "Production", connects: ["Sales","Marketing"], monthly: 8528.00, qtrly: 25584.00, annual: 102336.00, billing: "Monthly", monogram: "CC", swatch: ["#1B5E20","#66BB6A"], logoFile: "companycam.svg", logoBg: "#ffffff" },
  { name: "Project Map It", useCase: "Sales territory mapping tool", dept: "Sales", connects: ["Marketing"], monthly: 8000, qtrly: 24000, annual: 96000, billing: "Monthly", monogram: "PM", swatch: ["#7C2D12","#FB923C"] },
  { name: "Good Contractor", useCase: "Reputation & reviews platform", dept: "Marketing", connects: ["Sales"], monthly: 7875, qtrly: 23625, annual: 94500, billing: "Monthly", monogram: "GC", swatch: ["#155E75","#22D3EE"], logoFile: "good-contractors.jpg", logoFullBleed: true },
  { name: "DOCEBO", useCase: "Sales training LMS", dept: "Sales", connects: ["HR","Recruiting"], monthly: 7688.29, qtrly: 23064.87, annual: 92259.48, billing: "Monthly", monogram: "DC", swatch: ["#0EA5E9","#7DD3FC"] },
  { name: "Paycom", useCase: "Payroll & HRIS", dept: "Accounting", connects: ["HR","Company Wide"], monthly: 7292.92, qtrly: 21878.76, annual: 87515.04, billing: "Term — Monthly", monogram: "PC", swatch: ["#15803D","#86EFAC"], logoFile: "paycom.svg", logoBg: "#ffffff" },
  { name: "Neustar", useCase: "Call center AT&T spam remediation", dept: "Call Center", connects: ["IT"], monthly: 6338.09, qtrly: 19014.27, annual: 76057.08, billing: "Monthly — TransUnion", notes: "Listed as TransUnion on the invoice.", monogram: "NS", swatch: ["#7E22CE","#C084FC"] },
  { name: "Faraday", useCase: "Lead screening for the call center", dept: "Sales", connects: ["Call Center","CRM"], monthly: 6250, qtrly: 18750, annual: 75000, billing: "Monthly", monogram: "FD", swatch: ["#9F1239","#FB7185"] },
  { name: "Channel Automation", useCase: "Call-center workflow automation", dept: "Call Center", connects: ["CRM"], monthly: 6088, qtrly: 18264, annual: 73056, billing: "Term — Monthly", monogram: "CA", swatch: ["#1D4ED8","#60A5FA"] },
  { name: "Google Workspace", useCase: "Email, docs, and productivity", dept: "Company Wide", connects: ["All","IT","Marketing","Sales","CRM"], monthly: 5811.67, qtrly: 17435.01, annual: 69740.04, billing: "Monthly", monogram: "GW", swatch: ["#374151","#9CA3AF"], logoFile: "google.svg", logoFullBleed: true },
  { name: "RMM / SaaS Backup", useCase: "Remote management of PCs + Google backup", dept: "IT", connects: ["Company Wide"], monthly: 5768, qtrly: 17304, annual: 69216, billing: "Monthly — bundled into Data Magic invoice", notes: "Bundled into Data Magic invoice.", monogram: "RM", swatch: ["#334155","#94A3B8"] },
  { name: "Ingage", useCase: "Interactive sales presentation tool", dept: "Sales", connects: ["Marketing"], monthly: 5027.40, qtrly: 15082.20, annual: 60328.80, billing: "Monthly", monogram: "IG", swatch: ["#BE185D","#F472B6"] },
  { name: "1&Fund", useCase: "Customer financing platform", dept: "Multiple", connects: ["Sales","Accounting"], monthly: 4515.76, qtrly: 13547.29, annual: 54189.16, billing: "Monthly", monogram: "1F", swatch: ["#0F766E","#5EEAD4"] },
  { name: "QuickBooks", useCase: "Accounting software", dept: "Accounting", connects: ["President"], monthly: 3790.17, qtrly: 11370.51, annual: 45482.04, billing: "Term — Monthly", monogram: "QB", swatch: ["#166534","#4ADE80"], logoFile: "quickbooks.svg", logoBg: "#ffffff" },
  { name: "Get The Referral", useCase: "Marketing & referral sales tool", dept: "Sales", connects: ["Marketing"], monthly: 3563.04, qtrly: 10689.12, annual: 42756.48, billing: "Monthly", monogram: "GR", swatch: ["#A16207","#FACC15"] },
  { name: "HubSpot", useCase: "Email marketing & automation", dept: "Marketing", connects: ["Sales","CRM"], monthly: 3407.87, qtrly: 10223.60, annual: 40894.40, billing: "Quarterly — $10,223.60 invoice 3/31/26 – 6/29/26", expires: "2026-06-29", monogram: "HS", swatch: ["#C2410C","#FB923C"], logoFile: "hubspot.svg", logoBg: "#ffffff" },
  { name: "Fathom", useCase: "AI meeting notes & transcripts", dept: "IT", connects: ["Company Wide","Sales"], monthly: 3155.70, qtrly: 9467.10, annual: 37864.40, billing: "Monthly", monogram: "FT", swatch: ["#1E40AF","#3B82F6"], logoFile: "fathom.svg", logoBg: "#0f1a2e" },
  { name: "Adobe", useCase: "Document tool & Creative Cloud", dept: "Company Wide", connects: ["Marketing","All"], monthly: 2255.29, qtrly: 6765.87, annual: 27063.48, billing: "Monthly", monogram: "Ad", swatch: ["#B91C1C","#F87171"], logoFile: "adobe.svg", logoFullBleed: true },
  { name: "Notability — Business", useCase: "PDF markup for field managers", dept: "Production", connects: ["Sales"], monthly: 2100, qtrly: 6300, annual: 25200, billing: "Monthly", monogram: "Nb", swatch: ["#4338CA","#818CF8"], logoFile: "notability.jpg", logoFullBleed: true },
  { name: "Snoball", useCase: "Referral service", dept: "Marketing", connects: ["Sales"], monthly: 1650, qtrly: 4950, annual: 19800, billing: "Monthly", monogram: "Sn", swatch: ["#0369A1","#38BDF8"], logoFile: "snoball.jpg", logoFullBleed: true },
  { name: "QuickPage", useCase: "Lead generation microsites", dept: "Marketing", connects: ["Sales"], monthly: 1574, qtrly: 4722, annual: 18888, billing: "Paid quarterly — total invoice $4,722.00", monogram: "QP", swatch: ["#7F1D1D","#FCA5A5"], logoFile: "quickpage.png", logoBg: "#ffffff" },
  { name: "Arevy (formerly Sonar)", useCase: "CRM management tool", dept: "CRM", connects: ["IT"], monthly: 1332.50, qtrly: 3997.50, annual: 15990, billing: "Annual — contract expires 8/20/27", expires: "2027-08-20", monogram: "Av", swatch: ["#065F46","#34D399"] },
  { name: "Hatch", useCase: "Automated customer communications", dept: "Call Center", connects: ["Sales","CRM"], monthly: 1209, qtrly: 3627, annual: 14508, billing: "Monthly", monogram: "Ht", swatch: ["#0F766E","#2DD4BF"] },
  { name: "800 Response", useCase: "Vanity phone numbers", dept: "Call Center", connects: ["Marketing"], monthly: 1039.08, qtrly: 3117.24, annual: 12468.96, billing: "Monthly", monogram: "800", swatch: ["#0C4A6E","#0EA5E9"] },
  { name: "DocuSign", useCase: "Onboarding & e-signature", dept: "Recruiting", connects: ["HR","Sales","Accounting"], monthly: 1007.62, qtrly: 3022.86, annual: 12091.45, billing: "Annual — term 2/26 to 2/27", expires: "2027-02-28", monogram: "DS", swatch: ["#1E3A8A","#60A5FA"], logoFile: "docusign.svg", logoBg: "#ffffff" },
  { name: "Microsoft Office", useCase: "Office productivity", dept: "Company Wide", connects: ["IT","All"], monthly: 896.63, qtrly: 2689.89, annual: 10759.56, billing: "Monthly", monogram: "MO", swatch: ["#B45309","#FBBF24"], logoFile: "microsoft-office.svg", logoBg: "#ffffff" },
  { name: "Nextiva", useCase: "VOIP software for account managers", dept: "Production", connects: ["IT","Call Center"], monthly: 800.95, qtrly: 2402.85, annual: 9611.40, billing: "Monthly", monogram: "Nx", swatch: ["#6D28D9","#A78BFA"], logoFile: "nextiva.png", logoFullBleed: true },
  { name: "Clearfly", useCase: "Voice / SIP carrier", dept: "IT", connects: ["Call Center"], monthly: 736.63, qtrly: 2209.89, annual: 8839.56, billing: "Monthly", monogram: "Cf", swatch: ["#0E7490","#67E8F9"], logoFile: "clearfly.jpg", logoFullBleed: true },
  { name: "The Predictive Index", useCase: "Behavioral assessments for hiring", dept: "HR", connects: ["Recruiting"], monthly: 658.33, qtrly: 1975, annual: 7900, billing: "Annual — term 8/25/25 to 8/24/26", expires: "2026-08-24", monogram: "PI", swatch: ["#9D174D","#F472B6"] },
  { name: "DataGroomr", useCase: "CRM cleanup tool", dept: "CRM", connects: ["IT"], monthly: 541.44, qtrly: 1624.32, annual: 6497.28, billing: "Monthly", monogram: "DG", swatch: ["#3730A3","#818CF8"] },
  { name: "Jira", useCase: "CRM management ticketing", dept: "CRM", connects: ["IT"], monthly: 482.68, qtrly: 1448.04, annual: 5792.16, billing: "Monthly", monogram: "Jr", swatch: ["#1D4ED8","#60A5FA"], logoFile: "jira.svg", logoBg: "#ffffff" },
  { name: "MailParser.io", useCase: "Inbound email parsing", dept: "IT", connects: ["CRM","Marketing"], monthly: 434.29, qtrly: 1302.87, annual: 5211.48, billing: "Monthly", monogram: "MP", swatch: ["#3F3F46","#A1A1AA"] },
  { name: "Graphus", useCase: "Email security", dept: "IT", connects: ["Company Wide"], monthly: 426, qtrly: 1278, annual: 5112, billing: "Monthly", monogram: "Gp", swatch: ["#5B21B6","#8B5CF6"] },
  { name: "KnowBe4", useCase: "Security & HR trainings", dept: "IT", connects: ["HR","Company Wide"], monthly: 425.95, qtrly: 1277.85, annual: 5111.40, billing: "Monthly — contract ending 6/7/2026", expires: "2026-06-07", monogram: "KB", swatch: ["#B91C1C","#F87171"] },
  { name: "Zapier", useCase: "Workflow automation", dept: "CRM", connects: ["IT","Marketing","Company Wide"], monthly: 302.21, qtrly: 906.63, annual: 6233.98, billing: "Monthly", monogram: "Zp", swatch: ["#92400E","#FDBA74"], logoFile: "zapier.svg", logoBg: "#ffffff" },
  { name: "JAMF", useCase: "Mobile device management", dept: "IT", connects: ["Company Wide"], monthly: 209.67, qtrly: 629.01, annual: 2518.43, billing: "Monthly", monogram: "JF", swatch: ["#1E3A8A","#3B82F6"] },
  { name: "Datto NAS Backup", useCase: "Backup storage", dept: "IT", connects: ["Company Wide"], monthly: 165, qtrly: 495, annual: 1980, billing: "Bundled into Data Magic invoice", notes: "Bundled into Data Magic invoice.", monogram: "Dt", swatch: ["#1F2937","#6B7280"] },
  { name: "Claude", useCase: "AI assistant", dept: "President", connects: ["Company Wide"], monthly: 106.60, qtrly: 319.80, annual: 1279.20, billing: "Monthly", monogram: "Cl", swatch: ["#9A3412","#F97316"], logoFile: "claude.svg", logoBg: "#ffffff" },
  { name: "SOC SentinelOne", useCase: "24/7 endpoint protection", dept: "IT", connects: ["Company Wide"], monthly: 81, qtrly: 243, annual: 972, billing: "Monthly", monogram: "S1", swatch: ["#7F1D1D","#EF4444"] },
  { name: "IT Glue", useCase: "Password & documentation mgmt", dept: "IT", connects: ["Company Wide"], monthly: 42, qtrly: 126, annual: 504, billing: "Bundled into Data Magic invoice", notes: "Bundled into Data Magic invoice.", monogram: "IG", swatch: ["#2563EB","#60A5FA"] },
  { name: "Apple Business Essentials", useCase: "Mobile device management", dept: "IT", connects: ["Company Wide"], monthly: 7.08, qtrly: 21.24, annual: 84.96, billing: "Monthly", monogram: "AB", swatch: ["#111827","#6B7280"] },
];

// ---------- CSV parsing ----------
// Robust enough for Google Sheets CSV export: handles quoted fields, escaped quotes ("")
function parseCSV(text) {
  const rows = [];
  let row = [];
  let cell = "";
  let i = 0;
  let inQuotes = false;
  while (i < text.length) {
    const ch = text[i];
    if (inQuotes) {
      if (ch === '"') {
        if (text[i + 1] === '"') { cell += '"'; i += 2; continue; }
        inQuotes = false; i++; continue;
      }
      cell += ch; i++; continue;
    }
    if (ch === '"') { inQuotes = true; i++; continue; }
    if (ch === ',') { row.push(cell); cell = ""; i++; continue; }
    if (ch === '\r') { i++; continue; }
    if (ch === '\n') { row.push(cell); rows.push(row); row = []; cell = ""; i++; continue; }
    cell += ch; i++;
  }
  if (cell.length || row.length) { row.push(cell); rows.push(row); }
  return rows.filter(r => r.length > 1 || (r.length === 1 && r[0].trim() !== ""));
}

function normalizeKey(s) {
  return String(s || "").toLowerCase().replace(/[^a-z0-9]/g, "");
}

const COL_ALIASES = {
  name: ["name", "software", "tool"],
  useCase: ["usecase", "purpose", "use"],
  dept: ["department", "dept"],
  connects: ["connects", "alsoserves", "secondarydepts", "connections"],
  monthly: ["monthly"],
  qtrly: ["quarterly", "qtrly", "qtr"],
  annual: ["annual", "yearly", "yearlytotal"],
  billing: ["billing", "billingnotes", "billingschedule"],
  expires: ["expires", "expiration", "expirationdate", "renewal"],
  notes: ["notes"],
  monogram: ["monogram", "initials"],
  swatchA: ["swatcha", "colora", "primarycolor"],
  swatchB: ["swatchb", "colorb", "secondarycolor"],
  logoFile: ["logofile", "logo", "logofilename"],
  logoBg: ["logobg", "logobackground", "logobgcolor"],
  logoFullBleed: ["logofullbleed", "fullbleed"],
};

function parseMoney(s) {
  if (s == null || s === "") return 0;
  if (typeof s === "number") return s;
  const v = String(s).replace(/[\$,\s]/g, "");
  const n = parseFloat(v);
  return isNaN(n) ? 0 : n;
}

function parseBool(s) {
  if (s == null) return false;
  const v = String(s).trim().toLowerCase();
  return v === "true" || v === "yes" || v === "y" || v === "1";
}

function parseList(s) {
  if (!s) return [];
  return String(s).split(/[,;|]/).map(x => x.trim()).filter(Boolean);
}

function parseDate(s) {
  if (!s) return undefined;
  const v = String(s).trim();
  if (!v) return undefined;
  // Accept YYYY-MM-DD, M/D/YY, M/D/YYYY
  if (/^\d{4}-\d{2}-\d{2}$/.test(v)) return v;
  const m = v.match(/^(\d{1,2})\/(\d{1,2})\/(\d{2,4})$/);
  if (m) {
    let [_, mo, day, yr] = m;
    if (yr.length === 2) yr = "20" + yr;
    return `${yr}-${String(mo).padStart(2, "0")}-${String(day).padStart(2, "0")}`;
  }
  // Fall back to Date parsing
  const d = new Date(v);
  if (!isNaN(d.getTime())) return d.toISOString().slice(0, 10);
  return undefined;
}

function rowsToTools(rows) {
  if (!rows.length) return [];
  const header = rows[0].map(h => normalizeKey(h));
  const colIndex = {};
  for (const [field, aliases] of Object.entries(COL_ALIASES)) {
    colIndex[field] = -1;
    for (const a of aliases) {
      const i = header.indexOf(a);
      if (i !== -1) { colIndex[field] = i; break; }
    }
  }
  const get = (row, field) => {
    const i = colIndex[field];
    return i === -1 ? "" : (row[i] || "").trim();
  };
  const tools = [];
  for (let r = 1; r < rows.length; r++) {
    const row = rows[r];
    const name = get(row, "name");
    if (!name) continue;
    const t = {
      name,
      useCase: get(row, "useCase"),
      dept: get(row, "dept") || "Multiple",
      connects: parseList(get(row, "connects")),
      monthly: parseMoney(get(row, "monthly")),
      qtrly: parseMoney(get(row, "qtrly")),
      annual: parseMoney(get(row, "annual")),
      billing: get(row, "billing"),
      notes: get(row, "notes"),
      monogram: get(row, "monogram") || name.split(/\s+/).map(w => w[0]).join("").slice(0, 2).toUpperCase(),
      swatch: [get(row, "swatchA") || "#475569", get(row, "swatchB") || "#94a3b8"],
    };
    const exp = parseDate(get(row, "expires"));
    if (exp) t.expires = exp;
    const lf = get(row, "logoFile");
    if (lf) t.logoFile = lf;
    const lb = get(row, "logoBg");
    if (lb) t.logoBg = lb;
    if (parseBool(get(row, "logoFullBleed"))) t.logoFullBleed = true;
    tools.push(t);
  }
  return tools;
}

// ---------- Loader ----------
async function loadTools(sheetUrl) {
  if (!sheetUrl) {
    return { tools: DEFAULT_TOOLS, source: "bundled", updatedAt: null, error: null };
  }
  try {
    // Add cache-buster
    const url = sheetUrl + (sheetUrl.includes("?") ? "&" : "?") + "_=" + Date.now();
    const resp = await fetch(url, { cache: "no-store" });
    if (!resp.ok) throw new Error("HTTP " + resp.status);
    const text = await resp.text();
    const rows = parseCSV(text);
    const tools = rowsToTools(rows);
    if (!tools.length) throw new Error("Sheet returned no tools — check that the first row is a header.");
    return { tools, source: "sheet", updatedAt: new Date(), error: null };
  } catch (e) {
    console.warn("[ZINTEX] Falling back to bundled data:", e);
    return { tools: DEFAULT_TOOLS, source: "bundled-fallback", updatedAt: null, error: e.message || String(e) };
  }
}

// ---------- Stats ----------
function buildStats(tools) {
  const totalMonthly = tools.reduce((s, t) => s + (Number(t.monthly) || 0), 0);
  const totalAnnual = tools.reduce((s, t) => s + (Number(t.annual) || 0), 0);
  const byDept = {};
  DEPARTMENTS.forEach((d) => (byDept[d.id] = { count: 0, annual: 0 }));
  tools.forEach((t) => {
    if (!byDept[t.dept]) byDept[t.dept] = { count: 0, annual: 0 };
    byDept[t.dept].count += 1;
    byDept[t.dept].annual += Number(t.annual) || 0;
  });
  return { totalMonthly, totalAnnual, byDept, total: tools.length };
}

Object.assign(window, {
  DEPARTMENTS,
  DEFAULT_TOOLS,
  deptColor,
  parseCSV,
  rowsToTools,
  loadTools,
  buildStats,
});
