  const state = {
    data: { vendors: [], categories: [], products: [], product_links: [], links: [] },
    scope: "infra",
    selectedVendors: new Set(),
    selectedCategories: new Set(),
    vendorSearch: "",
    categorySearch: "",
  };

  const el = {
    vendorList: document.getElementById("vendorList"),
    categoryList: document.getElementById("categoryList"),
    vendorSearch: document.getElementById("vendorSearch"),
    categorySearch: document.getElementById("categorySearch"),
    resultRows: document.getElementById("resultRows"),
    stats: document.getElementById("stats"),
    clearBtn: document.getElementById("clearBtn"),
    modeInfra: document.getElementById("modeInfra"),
    modeIb: document.getElementById("modeIb"),
    resultSection: document.querySelector(".result"),
    filtersSection: document.querySelector(".board"),
    activeFilters: document.getElementById("activeFilters"),
    vendorBadge: document.getElementById("vendorBadge"),
    categoryBadge: document.getElementById("categoryBadge"),
  };

  let clickAudioCtx = null;

  // ── Vendor tooltip (desktop / hover-capable devices only) ──
  const canHover = window.matchMedia('(hover: hover) and (pointer: fine)').matches;
  const tooltip = document.createElement('div');
  tooltip.className = 'vendor-tooltip';
  document.body.appendChild(tooltip);
  if (canHover) {
    tooltip.addEventListener('mouseenter', () => { overTooltip = true; clearTimeout(hideTimer); });
    tooltip.addEventListener('mouseleave', () => { overTooltip = false; hideTooltip(); });
  }

  let tooltipTimer = null;
  let hideTimer = null;
  let overTooltip = false;
  let vendorMap = {};

  function buildVendorMap() {
    vendorMap = {};
    for (const v of state.data.vendors) {
      vendorMap[v.id] = v;
    }
  }

  function positionTooltip(chipEl) {
    const rect = chipEl.getBoundingClientRect();
    const tw = 280, th = 260;
    let left = rect.right + 10;
    let top = rect.top + rect.height / 2 - th / 2;
    if (left + tw > window.innerWidth - 8) left = rect.left - tw - 10;
    if (top < 8) top = 8;
    if (top + th > window.innerHeight - 8) top = window.innerHeight - 8 - th;
    tooltip.style.left = left + 'px';
    tooltip.style.top  = top  + 'px';
  }

  function showTooltip(chipEl, vendor) {
    const logo  = vendor.logo || '';
    const desc  = vendor.description || '';
    const mont  = vendor.mont_page || '';
    const site  = vendor.website || '';

    let logoHtml = '';
    if (logo) {
      logoHtml = `<div class="vtt-logo"><img src="/static/${logo}" alt="${vendor.name}" onerror="this.parentElement.innerHTML='<span class=vtt-logo-placeholder>${vendor.name.slice(0,2).toUpperCase()}</span>'"/></div>`;
    } else {
      logoHtml = `<div class="vtt-logo"><span class="vtt-logo-placeholder">${vendor.name.slice(0,2).toUpperCase()}</span></div>`;
    }

    let linksHtml = '';
    if (mont) linksHtml += `<a class="vtt-link mont" href="${mont}" target="_blank" rel="noopener">MONT ↗</a>`;
    if (site) linksHtml += `<a class="vtt-link site" href="${site}" target="_blank" rel="noopener">Сайт ↗</a>`;

    tooltip.innerHTML = `
      ${logoHtml}
      <div class="vtt-body">
        <div class="vtt-name">${vendor.name}</div>
        ${desc ? `<div class="vtt-desc">${desc}</div>` : ''}
        ${linksHtml ? `<div class="vtt-links">${linksHtml}</div>` : ''}
      </div>`;

    positionTooltip(chipEl);
    tooltip.classList.add('visible');
  }

  function hideTooltip(immediate) {
    clearTimeout(hideTimer);
    if (immediate) { tooltip.classList.remove('visible'); return; }
    hideTimer = setTimeout(() => {
      if (!overTooltip) tooltip.classList.remove('visible');
    }, 120);
  }


  function playScopeClick() {
    try {
      if (!clickAudioCtx) {
        clickAudioCtx = new (window.AudioContext || window.webkitAudioContext)();
      }
      const now = clickAudioCtx.currentTime;
      const osc = clickAudioCtx.createOscillator();
      const gain = clickAudioCtx.createGain();
      osc.type = "triangle";
      osc.frequency.setValueAtTime(1800, now);
      osc.frequency.exponentialRampToValueAtTime(950, now + 0.025);
      gain.gain.setValueAtTime(0.0001, now);
      gain.gain.linearRampToValueAtTime(0.14, now + 0.0025);
      gain.gain.exponentialRampToValueAtTime(0.0001, now + 0.04);
      osc.connect(gain);
      gain.connect(clickAudioCtx.destination);
      osc.start(now);
      osc.stop(now + 0.045);
    } catch (_) {
      // Ignore audio failures silently.
    }
  }

  function normalize(s) {
    return s.toLowerCase().replace(/ё/g, "е");
  }

  function getMaps() {
    const productsByVendor = new Map();
    const categoriesByProduct = new Map();
    const productsByCategory = new Map();

    for (const v of state.data.vendors) productsByVendor.set(v.id, new Set());
    for (const p of state.data.products) categoriesByProduct.set(p.id, new Set());
    for (const c of state.data.categories) productsByCategory.set(c.id, new Set());

    for (const p of state.data.products) {
      if (!productsByVendor.has(p.vendor_id)) productsByVendor.set(p.vendor_id, new Set());
      productsByVendor.get(p.vendor_id).add(p.id);
    }
    for (const l of state.data.product_links) {
      if (!categoriesByProduct.has(l.product_id)) categoriesByProduct.set(l.product_id, new Set());
      if (!productsByCategory.has(l.category_id)) productsByCategory.set(l.category_id, new Set());
      categoriesByProduct.get(l.product_id).add(l.category_id);
      productsByCategory.get(l.category_id).add(l.product_id);
    }

    return { productsByVendor, categoriesByProduct, productsByCategory };
  }

  function visibleSets() {
    const { productsByVendor, categoriesByProduct, productsByCategory } = getMaps();

    const allowedCategories = new Set(state.data.categories.map(c => c.id));
    const allowedVendors = new Set(state.data.vendors.map(v => v.id));
    const allowedProducts = new Set(state.data.products.map(p => p.id));

    if (state.selectedVendors.size > 0) {
      const fromVendorProducts = new Set();
      for (const vId of state.selectedVendors) {
        for (const pId of (productsByVendor.get(vId) || [])) fromVendorProducts.add(pId);
      }
      for (const pId of Array.from(allowedProducts)) {
        if (!fromVendorProducts.has(pId)) allowedProducts.delete(pId);
      }
    }

    if (state.selectedCategories.size > 0) {
      const fromCategories = new Set();
      for (const cId of state.selectedCategories) {
        for (const pId of (productsByCategory.get(cId) || [])) fromCategories.add(pId);
      }
      for (const pId of Array.from(allowedProducts)) {
        if (!fromCategories.has(pId)) allowedProducts.delete(pId);
      }
    }

    for (const cId of Array.from(allowedCategories)) {
      const products = productsByCategory.get(cId) || new Set();
      if (![...products].some(pId => allowedProducts.has(pId))) {
        allowedCategories.delete(cId);
      }
    }

    for (const vId of Array.from(allowedVendors)) {
      const products = productsByVendor.get(vId) || new Set();
      if (![...products].some(pId => allowedProducts.has(pId))) {
        allowedVendors.delete(vId);
      }
    }

    return { allowedCategories, allowedVendors, allowedProducts, productsByVendor, categoriesByProduct };
  }

  function renderChips() {
    const { allowedCategories, allowedVendors } = visibleSets();

    const vendorQ = normalize(state.vendorSearch);
    const categoryQ = normalize(state.categorySearch);

    el.vendorList.innerHTML = "";
    let vi = 0;
    for (const vendor of state.data.vendors) {
      if (vendorQ && !normalize(vendor.name).includes(vendorQ)) continue;
      const node = document.createElement("button");
      node.className = "chip";
      vi++;
      if (state.selectedVendors.has(vendor.id)) node.classList.add("active");
      else if (!allowedVendors.has(vendor.id)) node.classList.add("dim");
      node.textContent = vendor.name;
      node.addEventListener("click", () => {
        const wasSelected = state.selectedVendors.has(vendor.id);
        state.selectedVendors.clear();
        if (!wasSelected) state.selectedVendors.add(vendor.id);
        render();
        if (wasSelected) scrollAfterDeselect();
        else scrollToResultsSmooth();
      });
      if (canHover) {
        node.addEventListener("mouseenter", () => {
          clearTimeout(tooltipTimer);
          tooltipTimer = setTimeout(() => showTooltip(node, vendor), 220);
        });
        node.addEventListener("mouseleave", () => {
          clearTimeout(tooltipTimer);
          hideTooltip();
        });
      }
      el.vendorList.appendChild(node);
    }

    el.categoryList.innerHTML = "";
    const showOnlyLinkedCategories = state.selectedVendors.size > 0;
    let ci = 0;
    for (const category of state.data.categories) {
      if (categoryQ && !normalize(category.name).includes(categoryQ)) continue;
      if (showOnlyLinkedCategories && !allowedCategories.has(category.id) && !state.selectedCategories.has(category.id)) continue;
      const node = document.createElement("button");
      node.className = "chip";
      ci++;
      if (state.selectedCategories.has(category.id)) node.classList.add("active");
      else if (!allowedCategories.has(category.id)) node.classList.add("dim");
      node.textContent = category.name;
      node.addEventListener("click", () => {
        const wasSelected = state.selectedCategories.has(category.id);
        if (wasSelected) state.selectedCategories.delete(category.id);
        else state.selectedCategories.add(category.id);
        render();
        if (wasSelected) scrollAfterDeselect();
        else scrollToResultsSmooth();
      });
      el.categoryList.appendChild(node);
    }

    const ps = visibleSets().allowedProducts.size;
    el.stats.innerHTML = `<span class="stat-pill">Вендоры <b>${allowedVendors.size}</b>&thinsp;/&thinsp;${state.data.vendors.length}</span><span class="stat-pill">Категории <b>${allowedCategories.size}</b>&thinsp;/&thinsp;${state.data.categories.length}</span><span class="stat-pill">Продукты <b>${ps}</b>&thinsp;/&thinsp;${state.data.products.length}</span>`;
    if (el.vendorBadge) el.vendorBadge.textContent = allowedVendors.size;
    if (el.categoryBadge) el.categoryBadge.textContent = allowedCategories.size;
  }

  function renderResults() {
    const { allowedCategories, allowedVendors, allowedProducts, productsByVendor, categoriesByProduct } = visibleSets();
    const productsById = new Map(state.data.products.map(p => [p.id, p]));
    const vendorsById = new Map(state.data.vendors.map(v => [v.id, v]));
    const isIb = state.scope === 'ib';

    const rows = [];
    for (const vendor of state.data.vendors) {
      if (!allowedVendors.has(vendor.id)) continue;
      const productIds = [...(productsByVendor.get(vendor.id) || [])]
        .filter(pId => allowedProducts.has(pId))
        .filter(pId => {
          if (state.selectedCategories.size === 0) return true;
          const cats = categoriesByProduct.get(pId) || new Set();
          return [...state.selectedCategories].some(cId => cats.has(cId));
        });
      const products = productIds.map(pId => productsById.get(pId)).filter(Boolean);
      if (products.length === 0) continue;
      rows.push({ vendor, products });
    }

    el.resultRows.innerHTML = "";
    if (rows.length === 0) {
      el.resultRows.innerHTML = '<div class="row-card"><strong>По текущим фильтрам ничего не найдено</strong></div>';
      return;
    }

    // Vendor info bars for selected vendors
    if (state.selectedVendors.size > 0) {
      for (const vid of state.selectedVendors) {
        const v = vendorsById.get(vid);
        if (!v) continue;
        const bar = document.createElement('div');
        bar.className = 'vendor-info-bar';
        const logoInner = v.logo
          ? `<img src="/static/${v.logo}" alt="${v.name}" onerror="this.parentElement.innerHTML='<span class=vib-logo-text>${v.name.slice(0,2).toUpperCase()}</span>'">`
          : `<span class="vib-logo-text">${v.name.slice(0,2).toUpperCase()}</span>`;
        let linksHtml = '';
        if (v.slug) linksHtml += `<a class="vib-link mont" href="/vendor/${v.slug}">Подробнее →</a>`;
        if (v.mont_page) linksHtml += `<a class="vib-link site" href="${v.mont_page}" target="_blank" rel="noopener">MONT ↗</a>`;
        if (v.website) linksHtml += `<a class="vib-link site" href="${v.website}" target="_blank" rel="noopener">Сайт ↗</a>`;
        bar.innerHTML = `
          <div class="vib-logo">${logoInner}</div>
          <div class="vib-info">
            <div class="vib-name">${v.name}</div>
            ${v.description ? `<div class="vib-desc">${v.description}</div>` : ''}
            ${linksHtml ? `<div class="vib-links">${linksHtml}</div>` : ''}
          </div>`;
        el.resultRows.appendChild(bar);
      }
    }

    for (const row of rows) {
      const card = document.createElement("article");
      card.className = "row-card";
      const title = document.createElement("strong");
      if (row.vendor.slug) {
        const a = document.createElement("a");
        a.href = `/vendor/${row.vendor.slug}`;
        a.textContent = row.vendor.name;
        a.style.cssText = "color:inherit;text-decoration:none;";
        a.addEventListener("mouseenter", () => a.style.textDecoration = "underline");
        a.addEventListener("mouseleave", () => a.style.textDecoration = "none");
        title.appendChild(a);
      } else {
        title.textContent = row.vendor.name;
      }
      card.appendChild(title);
      const tags = document.createElement("div");
      tags.className = "tags";
      for (const product of row.products) {
        // IB scope: link to vendor's mont page; infra: link to product url
        let url = '';
        if (isIb) {
          url = row.vendor.mont_page || '';
        } else {
          url = (product.url && String(product.url).trim()) || '';
        }
        const tag = document.createElement(url ? "a" : "span");
        tag.className = "tag";
        tag.textContent = product.name;
        if (url) {
          tag.href = url;
          tag.target = "_blank";
          tag.rel = "noopener noreferrer";
        }
        tags.appendChild(tag);
      }
      card.appendChild(tags);
      el.resultRows.appendChild(card);
    }
  }

  function render() {
    el.modeInfra.classList.toggle("active", state.scope === "infra");
    el.modeIb.classList.toggle("active", state.scope === "ib");
    document.body.classList.toggle("scope-ib", state.scope === "ib");
    renderChips();
    renderActiveFilters();
    renderResults();
  }

  function scrollToResultsSmooth() {
    if (!el.resultSection) return;
    const top = Math.max(el.resultSection.getBoundingClientRect().top + window.scrollY - 10, 0);
    window.scrollTo({ top, behavior: "smooth" });
  }

  function scrollToFiltersSmooth() {
    if (!el.filtersSection) return;
    const top = Math.max(el.filtersSection.getBoundingClientRect().top + window.scrollY - 8, 0);
    window.scrollTo({ top, behavior: "smooth" });
  }

  function scrollToTopSmooth() {
    window.scrollTo({ top: 0, behavior: "smooth" });
  }

  function scrollAfterDeselect() {
    if (window.innerWidth > 980) {
      scrollToTopSmooth();
      return;
    }
    scrollToFiltersSmooth();
  }

  function renderActiveFilters() {
    if (!el.activeFilters) return;
    el.activeFilters.innerHTML = "";

    const vendorsById = new Map(state.data.vendors.map(v => [v.id, v.name]));
    const categoriesById = new Map(state.data.categories.map(c => [c.id, c.name]));

    const items = [];
    for (const id of state.selectedVendors) {
      const name = vendorsById.get(id);
      if (name) items.push({ kind: "Вендор", name, id, type: "vendor" });
    }
    for (const id of state.selectedCategories) {
      const name = categoriesById.get(id);
      if (name) items.push({ kind: "Категория", name, id, type: "category" });
    }

    if (items.length === 0) {
      el.activeFilters.style.display = "none";
      return;
    }
    el.activeFilters.style.display = "flex";

    for (const item of items) {
      const node = document.createElement("div");
      node.className = "active-filter";

      const text = document.createElement("span");
      text.innerHTML = `<span class="kind">${item.kind}:</span> ${item.name}`;
      node.appendChild(text);

      const remove = document.createElement("button");
      remove.className = "remove";
      remove.type = "button";
      remove.setAttribute("aria-label", `Убрать фильтр ${item.name}`);
      remove.textContent = "×";
      remove.addEventListener("click", () => {
        if (item.type === "vendor") state.selectedVendors.delete(item.id);
        else state.selectedCategories.delete(item.id);
        render();
        scrollToFiltersSmooth();
      });
      node.appendChild(remove);

      el.activeFilters.appendChild(node);
    }
  }

  async function loadScopeData(scope) {
    const res = await fetch(`/api/data?scope=${encodeURIComponent(scope)}`);
    state.data = await res.json();
    buildVendorMap();
  }

  async function init() {
    await loadScopeData(state.scope);
    render();
  }

  async function switchScope(scope) {
    if (scope === state.scope) return;
    playScopeClick();
    state.scope = scope;
    state.selectedVendors.clear();
    state.selectedCategories.clear();
    state.vendorSearch = "";
    state.categorySearch = "";
    el.vendorSearch.value = "";
    el.categorySearch.value = "";
    await loadScopeData(scope);
    render();
  }

  el.vendorSearch.addEventListener("input", e => {
    state.vendorSearch = e.target.value || "";
    render();
  });

  el.categorySearch.addEventListener("input", e => {
    state.categorySearch = e.target.value || "";
    render();
  });

  el.clearBtn.addEventListener("click", () => {
    state.selectedVendors.clear();
    state.selectedCategories.clear();
    state.vendorSearch = "";
    state.categorySearch = "";
    el.vendorSearch.value = "";
    el.categorySearch.value = "";
    render();
    scrollAfterDeselect();
  });

  el.modeInfra.addEventListener("click", () => {
    switchScope("infra");
  });

  el.modeIb.addEventListener("click", () => {
    switchScope("ib");
  });

  init();
