/* ============================================================
   FlowSpace Finder, mock data engine
   The real data pipeline / Claude call / sheet feed are out of
   scope (handled server-side). This fakes them convincingly:
   - a curated, CLEAN set of London spaces (teams up to 100)
   - an AI "company read" (pre-baked for a few names + a smart
     generic fallback derived from the input)
   - matching that produces a SENSIBLE teaser + varied, specific
     per-card reasons (no templated repetition, no mega-offices)
   Exposed on window.FinderData.
   ============================================================ */
(function () {
  "use strict";

  const gbp = (n) => "£" + Math.round(n).toLocaleString("en-GB");

  // Stable string hash → unsigned int
  function hash(str) {
    let h = 2166136261;
    for (let i = 0; i < str.length; i++) {
      h ^= str.charCodeAt(i);
      h = Math.imul(h, 16777619);
    }
    return h >>> 0;
  }

  // ---------- Area visual palettes (token-derived, no photos) ----------
  // Each area gets a deterministic tint so its "map tile" reads distinct.
  const PALETTES = [
    { a: "var(--color-brand-50)",   b: "var(--color-brand-200)",   ink: "var(--color-brand-600)",   street: "var(--color-brand-300)" },   // indigo
    { a: "var(--color-teal-50)",    b: "var(--color-teal-200)",    ink: "var(--color-teal-600)",    street: "var(--color-teal-300)" },    // teal
    { a: "var(--color-warning-50)", b: "var(--color-warning-200)", ink: "var(--color-warning-700)", street: "var(--color-warning-300)" }, // amber
    { a: "var(--color-success-50)", b: "var(--color-success-200)", ink: "var(--color-success-700)", street: "var(--color-success-300)" }, // green
    { a: "var(--color-brand-50)",   b: "var(--color-brand-300)",   ink: "var(--color-brand-800)",   street: "var(--color-brand-400)" },   // deep indigo
    { a: "var(--color-neutral-100)",b: "var(--color-neutral-300)", ink: "var(--color-neutral-700)", street: "var(--color-neutral-400)" }, // slate
  ];
  function paletteFor(area) {
    return PALETTES[hash(area || "London") % PALETTES.length];
  }

  // ---------- Curated, clean London availability ----------
  // operator/building are the GATED fields (hidden until email unlock).
  // area is shown pre-gate (area-level only, never street-level).
  // perDesk in £, monthly = desks * perDesk (sane, relatable numbers).
  const RAW = [
    { area: "Shoreditch",      pc: "EC2A", op: "Huckletree",     bld: "Huckletree Shoreditch",          d: 22, r: 595, av: "NOW",        tags: ["creative", "social", "tech"] },
    { area: "Old Street",      pc: "EC1V", op: "Mindspace",      bld: "Mindspace Shoreditch",           d: 14, r: 540, av: "NOW",        tags: ["tech", "buzzy"] },
    { area: "Clerkenwell",     pc: "EC1R", op: "The Office Group",bld: "TOG, Clerkenwell Green",       d: 18, r: 560, av: "1 Aug 2026", tags: ["design", "characterful"] },
    { area: "Farringdon",      pc: "EC1M", op: "Fora",           bld: "Fora, Clerkenwell Road",        d: 30, r: 680, av: "NOW",        tags: ["polished", "premium"] },
    { area: "King's Cross",    pc: "N1C",  op: "Kindred",        bld: "Kindred, Coal Drops Yard",      d: 26, r: 640, av: "NOW",        tags: ["modern", "well-connected"] },
    { area: "Soho",            pc: "W1F",  op: "The Office Group",bld: "TOG, Brock House",             d: 12, r: 820, av: "NOW",        tags: ["central", "members-club"] },
    { area: "Fitzrovia",       pc: "W1T",  op: "Fora",           bld: "Fora, Goodge Street",           d: 20, r: 760, av: "15 Jul 2026",tags: ["polished", "central"] },
    { area: "Spitalfields",    pc: "E1",   op: "Second Home",    bld: "Second Home Spitalfields",       d: 16, r: 350, av: "NOW",        tags: ["greenery", "creative", "value"] },
    { area: "Bank",            pc: "EC3V", op: "x+why",          bld: "x+why, Cornhill",               d: 34, r: 720, av: "NOW",        tags: ["corporate", "city"] },
    { area: "London Bridge",   pc: "SE1",  op: "Runway East",    bld: "Runway East, London Bridge",    d: 24, r: 560, av: "NOW",        tags: ["startup", "riverside"] },
    { area: "Bermondsey",      pc: "SE1",  op: "Techspace",      bld: "Techspace, Bermondsey",         d: 28, r: 480, av: "1 Sep 2026", tags: ["warehouse", "value", "creative"] },
    { area: "Victoria",        pc: "SW1E", op: "Fora",           bld: "Fora, Victoria Street",         d: 40, r: 700, av: "NOW",        tags: ["corporate", "transport"] },
    { area: "Marylebone",      pc: "W1U",  op: "The Office Group",bld: "TOG, Wigmore Street",           d: 10, r: 880, av: "NOW",        tags: ["quiet", "premium", "boutique"] },
    { area: "Paddington",      pc: "W2",   op: "Landmark",       bld: "Landmark, Paddington Central",  d: 36, r: 620, av: "NOW",        tags: ["transport", "modern"] },
    { area: "Camden",          pc: "NW1",  op: "Labs",           bld: "Labs, Camden Lock",             d: 18, r: 500, av: "NOW",        tags: ["creative", "characterful", "value"] },
    { area: "Canary Wharf",    pc: "E14",  op: "Plus X",         bld: "Plus X, Wood Wharf",            d: 44, r: 590, av: "1 Aug 2026", tags: ["corporate", "modern", "riverside"] },
    { area: "Hammersmith",     pc: "W6",   op: "Uncommon",       bld: "Uncommon, Hammersmith",         d: 16, r: 470, av: "NOW",        tags: ["value", "wellness"] },
    { area: "Holborn",         pc: "WC1V", op: "Fora",           bld: "Fora, Red Lion Square",         d: 22, r: 690, av: "NOW",        tags: ["central", "professional"] },
    { area: "Aldgate",         pc: "E1",   op: "Techspace",      bld: "Techspace, Aldgate East",       d: 30, r: 520, av: "NOW",        tags: ["tech", "value", "startup"] },
    { area: "Mayfair",         pc: "W1J",  op: "The Office Group",bld: "TOG, Berkeley Square",          d: 8,  r: 980, av: "NOW",        tags: ["premium", "quiet", "boutique"] },
  ];

  const SPACES = RAW.map((s, i) => ({
    id: "sp-" + i,
    ...s,
    m: s.d * s.r,
    central: ["Soho","Fitzrovia","Bank","Holborn","Farringdon","Clerkenwell","Shoreditch","Old Street","King's Cross","Victoria","Marylebone","Mayfair","Aldgate","Spitalfields"].includes(s.area),
  }));

  const ALL_AREAS = [...new Set(SPACES.map((s) => s.area))].sort();

  // ---------- The AI "company read" ----------
  // Pre-baked, hand-tuned reads for a few recognisable names; everything
  // else gets a believable generic read derived from the input.
  const VIBES = ["Vibrant & social", "Calm & focused", "Polished & professional", "Creative & characterful", "Fast-moving & scrappy"];
  const INDUSTRIES = ["Technology", "Financial services", "Creative & design", "Professional services", "Media", "Healthtech", "E-commerce", "Consultancy"];

  const BAKED = {
    pleo: {
      companyName: "Pleo", domain: "pleo.io", industry: "Financial services · fintech",
      currentLocation: "London", hasLondonPresence: true, londonStaff: 24,
      summary: "A fast-growing spend-management fintech with a polished, design-led product culture.",
      teamRead: "Collaborative and modern, they like bright, social space with room for huddles and demos, and they care about how the office represents the brand.",
      officeVibe: "Vibrant & social", vibeTags: ["Tech-forward", "Design-led", "Collaborative"],
      suggestedAreas: ["Shoreditch", "Old Street", "Bank"], maxDeskRate: 700,
      brandFit: "An East London tech base keeps them close to the fintech scene and the talent they hire from.",
    },
    stripe: {
      companyName: "Stripe", domain: "stripe.com", industry: "Technology · payments",
      currentLocation: "Dublin / San Francisco", hasLondonPresence: false, londonStaff: 30,
      summary: "Global payments infrastructure with a precise, engineering-first culture.",
      teamRead: "Considered and quietly ambitious, they'll want a polished, grown-up space that signals credibility to enterprise partners, with good meeting infrastructure.",
      officeVibe: "Polished & professional", vibeTags: ["Tech-forward", "Enterprise", "Global"],
      suggestedAreas: ["Soho", "Fitzrovia", "Holborn"], maxDeskRate: 850,
      brandFit: "A central West End base reads credible to the enterprise clients they sell to, and is easy for partners flying in.",
    },
  };

  function cleanInput(raw) {
    return (raw || "")
      .toLowerCase().trim()
      .replace(/^https?:\/\//, "").replace(/^www\./, "").replace(/\/.*$/, "").trim();
  }
  function titleCase(s) {
    return s.replace(/[-_.]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase()).trim();
  }

  function analyzeCompany(raw, brief) {
    const input = cleanInput(raw);
    const key = input.replace(/\.(com|co\.uk|co|io|ai|app|net|org|dev|xyz)$/,"");

    let a;
    if (BAKED[key]) {
      a = JSON.parse(JSON.stringify(BAKED[key]));
    } else {
      // ---- smart generic read ----
      const h = hash(input || "company");
      const name = input.includes(".") ? titleCase(key) : titleCase(input || "your team");
      const looksTech = /(io|ai|app|dev|tech|labs|hq|cloud|data)/.test(input);
      const looksCreative = /(studio|design|creative|brand|media|agency|works)/.test(input);
      const looksPro = /(law|legal|capital|partners|advisory|consult|finance|group|co\.uk)/.test(input);
      let industry, vibeIdx, areas, rate;
      if (looksCreative) { industry = "Creative & design"; vibeIdx = 3; areas = ["Clerkenwell", "Shoreditch", "Camden"]; rate = 560; }
      else if (looksPro) { industry = "Professional services"; vibeIdx = 2; areas = ["Bank", "Holborn", "Victoria"]; rate = 820; }
      else if (looksTech) { industry = "Technology"; vibeIdx = h % 2 ? 0 : 4; areas = ["Old Street", "Aldgate", "London Bridge"]; rate = 600; }
      else { industry = INDUSTRIES[h % INDUSTRIES.length]; vibeIdx = h % VIBES.length; areas = ["Farringdon", "Fitzrovia", "King's Cross"]; rate = 650; }

      const staff = 8 + (h % 38); // 8–45, relatable
      const hasLondon = (h >> 3) % 4 !== 0; // ~75% already here
      a = {
        companyName: name,
        domain: input.includes(".") ? input : key + ".com",
        industry,
        currentLocation: hasLondon ? "London" : ["Manchester","Berlin","New York","Amsterdam","Bristol"][h % 5],
        hasLondonPresence: hasLondon,
        londonStaff: staff,
        summary: `A ${industry.toLowerCase()} team with a clear sense of how they like to work.`,
        teamRead: [
          "Collaborative and people-first, they value bright, social spaces with breakout room and a bit of character.",
          "Heads-down and focused, they'll want calm, well-run space with proper meeting rooms and good light.",
          "Ambitious and fast-moving, flexible space they can grow into matters more than a fancy reception.",
        ][h % 3],
        officeVibe: VIBES[vibeIdx],
        vibeTags: looksCreative ? ["Design-led","Characterful"] : looksPro ? ["Professional","Established"] : ["Tech-forward","Growing"],
        suggestedAreas: areas,
        maxDeskRate: rate,
        brandFit: hasLondon
          ? `${areas[0]} keeps them near the people and partners they already work with.`
          : `A central, well-connected base makes their London launch easy to staff and easy to reach.`,
      };
    }

    // Brief overrides (optional improver) tweak the read
    if (brief) {
      if (brief.size) a.londonStaff = brief.size;
      if (brief.area && brief.area !== "any") a.suggestedAreas = [brief.area, ...a.suggestedAreas.filter((x) => x !== brief.area)];
      if (brief.budget) a.maxDeskRate = brief.budget;
      a.fromBrief = true;
    }
    return a;
  }

  // ---------- Matching ----------
  function scoreMatches(a, opts) {
    opts = opts || {};
    const team = Math.max(1, Math.min(100, a.londonStaff || 15));
    const ceil = a.maxDeskRate || null;
    const suggested = (a.suggestedAreas || []).map((s) => s.toLowerCase());
    const newToLondon = a.hasLondonPresence === false;

    let pool = SPACES.slice();

    // soft refine from chips / free-text intent
    const refine = opts.refine || {};
    if (refine.cheaper) pool = pool.filter((s) => s.r <= (refine.cheaperCeil || (ceil ? ceil * 0.85 : 560)) * 1.05);
    if (refine.bigger) pool = pool.filter((s) => s.d >= team);
    if (refine.area) pool = pool.filter((s) => s.area.toLowerCase() === refine.area.toLowerCase());
    if (refine.tag) pool = pool.filter((s) => s.tags.includes(refine.tag));
    if (!pool.length) pool = SPACES.slice(); // never dead-end

    const scored = pool.map((s) => {
      let score = 50;
      const diff = Math.abs(s.d - team);
      score += Math.max(-18, 26 - diff * 1.1);           // size fit
      if (s.d < team * 0.5) score -= 14;                  // too small
      if (ceil) score += Math.max(-16, Math.min(16, (ceil - s.r) / 22)); // budget fit
      if (suggested.some((p) => s.area.toLowerCase().includes(p))) score += 16; // area
      if (a.vibeTags && a.vibeTags.some((v) => s.tags.includes(v.toLowerCase().split(/[ -]/)[0]))) score += 6;
      if (s.av === "NOW") score += 7; else score += 2;
      if (newToLondon && s.central) score += 10;
      // gentle deterministic jitter so scores don't cluster at identical values
      score += (hash(s.id + a.companyName) % 9) - 4;
      score = Math.max(58, Math.min(97, Math.round(score)));
      return { ...s, score };
    });

    scored.sort((x, y) => y.score - x.score || x.r - y.r);
    return scored;
  }

  // The teaser must be a SENSIBLE match, not the biggest or priciest.
  // Take the top-ranked spaces, then prefer one near the team size with a
  // sane (sub-ceiling) price.
  function pickTeaser(ranked, a) {
    const team = Math.max(1, Math.min(100, a.londonStaff || 15));
    const ceil = a.maxDeskRate || 750;
    const top = ranked.slice(0, 6);
    const sane = top
      .filter((s) => s.r <= ceil * 1.05 && s.d <= team * 1.8 && s.d >= team * 0.5)
      .sort((x, y) => Math.abs(x.d - team) - Math.abs(y.d - team));
    return sane[0] || top.find((s) => s.r <= ceil * 1.1) || top[0];
  }

  // ---------- Varied, specific per-card reasoning ----------
  // Each card leads with a DIFFERENT angle so the shortlist never reads
  // templated. The angle is chosen deterministically from the space id.
  function reasonFor(space, a, isTeaser) {
    const team = a.londonStaff || 15;
    const angles = [];
    // area / vibe
    if ((a.suggestedAreas || []).some((x) => space.area.toLowerCase().includes(x.toLowerCase())))
      angles.push(`${space.area} is exactly the kind of area we read for ${a.companyName}, close to the people and partners you work with.`);
    // size
    if (Math.abs(space.d - team) <= 4)
      angles.push(`At ${space.d} desks it's sized almost spot-on for a team of ${team}, with a little breathing room.`);
    else if (space.d > team)
      angles.push(`${space.d} desks gives a team of ${team} clear room to grow into over the next year.`);
    // price
    if (a.maxDeskRate && space.r <= a.maxDeskRate)
      angles.push(`At ${gbp(space.r)}/desk it sits comfortably under the budget we estimated for you.`);
    // availability
    if (space.av === "NOW") angles.push(`It's available now, you could be in before your next quarter starts.`);
    else angles.push(`Comes free ${space.av}, which lines up well if you're planning a move rather than rushing one.`);
    // character / tags
    const charMap = {
      creative: "a creative, characterful feel", warehouse: "a converted-warehouse character",
      premium: "a polished, grown-up finish", quiet: "a calmer, heads-down atmosphere",
      "members-club": "a members-club feel for hosting clients", greenery: "unusual amounts of greenery and natural light",
      value: "strong value for a central spot", riverside: "a riverside setting", wellness: "wellness and end-of-trip facilities",
    };
    for (const t of space.tags) if (charMap[t]) { angles.push(`Expect ${charMap[t]}, it suits a ${(a.officeVibe || "").toLowerCase()} team.`); break; }

    // choose a primary angle deterministically, then maybe a supporting one
    const seed = hash(space.id + a.companyName + (isTeaser ? "T" : ""));
    const primary = angles[seed % angles.length];
    let support = angles[(seed >> 4) % angles.length];
    if (support === primary) support = null;
    return support ? primary + " " + support : primary;
  }

  window.FinderData = {
    SPACES, ALL_AREAS, paletteFor, analyzeCompany, scoreMatches, pickTeaser, reasonFor, gbp, hash, cleanInput,
  };
})();
