// V2Chips — выбор тегов новостей.
//
// Пропсы для production (интеграция с сервером):
//   categories    — массив категорий в формате CATEGORIES[] (из маппера tagNodesToCategories)
//   initialSelected — Set серверных ключей (загружается из /api/preferences)
//   onSave(selected) — вызывается при нажатии кнопки сохранения
//
// Если categories/initialSelected не переданы — использует window.CATEGORIES
// и хардкоденный набор для дизайн-превью.

function V2Chips({ dark = true, onClose, categories, initialSelected, onSave, onDone }) {
  const t = dark ? window.TG.dark : window.TG.light;
  const cats = categories || window.CATEGORIES;

  const [selected, setSelected] = React.useState(() => {
    if (initialSelected) return new Set(initialSelected);
    // Стартовый набор для дизайн-превью
    const s = new Set();
    s.add('macro:_:Инфляция');
    s.add('macro:_:Ключевая ставка');
    s.add('geo:_:Европа');
    s.add('geo:_:США');
    s.add('tech:themes:Искусственный интеллект');
    s.add('markets:banks:Сбербанк');
    s.add('markets:banks:Т-Банк');
    s.add('markets:oilgas:Газпром');
    return s;
  });
  const [query, setQuery] = React.useState('');
  const [keyboard, setKeyboard] = React.useState(false);
  const [saveStatus, setSaveStatus] = React.useState('idle'); // 'idle'|'pending'|'saving'|'saved'|'error'
  const saveTimerRef = React.useRef(null);
  const selectedRef = React.useRef(selected);
  React.useEffect(() => { selectedRef.current = selected; }, [selected]);

  const doSave = React.useCallback(async (sel) => {
    if (!onSave) return true;
    setSaveStatus('saving');
    try {
      await onSave(sel);
      setSaveStatus('saved');
      return true;
    } catch {
      setSaveStatus('error');
      return false;
    }
  }, [onSave]);

  const scheduleSave = React.useCallback(() => {
    clearTimeout(saveTimerRef.current);
    setSaveStatus('pending');
    saveTimerRef.current = setTimeout(() => {
      saveTimerRef.current = null;
      doSave(selectedRef.current);
    }, 1500);
  }, [doSave]);

  const handleMain = React.useCallback(async () => {
    const hasPending = saveTimerRef.current !== null;
    clearTimeout(saveTimerRef.current);
    saveTimerRef.current = null;
    if (hasPending || saveStatus === 'error') {
      const ok = await doSave(selectedRef.current);
      if (!ok) return; // сохранение не удалось — не закрываем
    }
    if (onDone) onDone();
  }, [saveStatus, doSave, onDone]);
  // Свёрнутые подкатегории: set 'catId:groupId'
  const [collapsedGroups, setCollapsedGroups] = React.useState(new Set());
  // Свёрнутые категории целиком: set 'catId'
  const [collapsedCats, setCollapsedCats] = React.useState(new Set());

  const toggle = (key) => {
    const next = new Set(selected);
    next.has(key) ? next.delete(key) : next.add(key);
    setSelected(next);
    scheduleSave();
  };
  const toggleGroupCollapse = (gk) => {
    const next = new Set(collapsedGroups);
    next.has(gk) ? next.delete(gk) : next.add(gk);
    setCollapsedGroups(next);
  };
  const toggleCatCollapse = (cid) => {
    const next = new Set(collapsedCats);
    next.has(cid) ? next.delete(cid) : next.add(cid);
    setCollapsedCats(next);
  };
  const collapseAll = () => {
    setCollapsedCats(new Set(cats.map((c) => c.id)));
  };
  const expandAll = () => setCollapsedCats(new Set());
  const selectAllCat = (cat) => {
    const all = window.flattenCat(cat);
    const next = new Set(selected);
    const allIn = all.every((it) => next.has(it.key));
    all.forEach((it) => { allIn ? next.delete(it.key) : next.add(it.key); });
    setSelected(next);
    scheduleSave();
  };
  const selectAllGroup = (cat, group) => {
    const keys = group.tags.map((tg) => {
      const o = window.tagObj(tg);
      return o.key || `${cat.id}:${group.id}:${o.label}`;
    });
    const next = new Set(selected);
    const allIn = keys.every((k) => next.has(k));
    keys.forEach((k) => { allIn ? next.delete(k) : next.add(k); });
    setSelected(next);
    scheduleSave();
  };

  // Поиск
  const q = query.trim().toLowerCase();
  const matchTag = (it) => !q || it.label.toLowerCase().includes(q) || (it.code && it.code.toLowerCase().includes(q));

  // Для отображения: фильтруем категории по попаданию
  const filtered = cats.map((cat) => {
    const all = window.flattenCat(cat);
    const catHit = cat.title.toLowerCase().includes(q);
    const tagHits = all.filter(matchTag);
    return {
      ...cat,
      all,
      catHit,
      tagHits,
      hidden: q && !catHit && tagHits.length === 0,
    };
  });

  return (
    <>
    <window.TGShell
      dark={dark}
      mainLabel={selected.size === 0 ? 'Готово' : `Готово · ${selected.size}`}
      onMain={handleMain}
      keyboard={keyboard}
      onCancelKeyboard={() => { document.activeElement && document.activeElement.blur(); }}
    >
      <div style={{ padding: '12px 12px 10px' }}>
        <window.TGSearch dark={dark} value={query} onChange={setQuery} onFocus={() => setKeyboard(true)} onBlur={() => setKeyboard(false)} />
      </div>

      {/* Панель управления */}
      <div style={{
        display: 'flex', alignItems: 'center', justifyContent: 'space-between',
        padding: '0 12px 8px',
      }}>
        <div style={{ fontSize: 11, color: t.textHint, letterSpacing: 0.3, textTransform: 'uppercase', fontWeight: 600 }}>
          Категории
        </div>
        <button
          onClick={collapsedCats.size === cats.length ? expandAll : collapseAll}
          style={{
            border: 'none', background: 'transparent', padding: '2px 6px',
            color: t.accent, fontSize: 12, fontWeight: 510, cursor: 'pointer',
            fontFamily: 'inherit',
          }}>
          {collapsedCats.size === cats.length ? 'Развернуть всё' : 'Свернуть всё'}
        </button>
      </div>

      <div style={{ padding: '0 8px 12px', display: 'flex', flexDirection: 'column', gap: 8 }}>
        {filtered.map((cat) => {
          if (cat.hidden) return null;
          const count = cat.all.filter((it) => selected.has(it.key)).length;
          const allIn = count === cat.all.length;
          const hasGroups = !!cat.groups;

          const catCollapsed = collapsedCats.has(cat.id) && !q;

          return (
            <section key={cat.id} style={{
              background: dark ? 'rgba(255,255,255,0.04)' : 'rgba(0,0,0,0.025)',
              borderRadius: 14, padding: catCollapsed ? '10px 14px' : '12px 14px 14px',
              border: `1px solid ${t.divider}`,
              transition: 'padding .18s',
            }}>
              {/* Шапка категории: чекбокс слева (выбрать все), вся остальная шапка — свернуть */}
              <div style={{
                display: 'flex', alignItems: 'center', gap: 10,
                marginBottom: catCollapsed ? 0 : (hasGroups ? 8 : 10),
                userSelect: 'none',
              }}>
                {/* Чекбокс (tri-state) */}
                <CatCheckbox
                  dark={dark}
                  state={allIn ? 'on' : count > 0 ? 'partial' : 'off'}
                  hue={cat.hue}
                  onClick={() => selectAllCat(cat)}
                />
                {/* Основной toggle-area: иконка, заголовок, счётчик, шеврон */}
                <div
                  role="button"
                  onClick={() => !q && toggleCatCollapse(cat.id)}
                  style={{
                    flex: 1, display: 'flex', alignItems: 'center', gap: 10,
                    cursor: q ? 'default' : 'pointer',
                    minWidth: 0,
                    padding: '4px 0',
                  }}>
                  <div style={{
                    width: 28, height: 28, borderRadius: 8,
                    background: `oklch(65% 0.14 ${cat.hue} / ${dark ? 0.22 : 0.16})`,
                    color: `oklch(${dark ? 82 : 45}% 0.18 ${cat.hue})`,
                    display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0,
                  }}>
                    <window.IconSVG name={cat.icon} size={16} strokeWidth={2.2} />
                  </div>
                  <div style={{ flex: 1, minWidth: 0 }}>
                    <div style={{ fontSize: 14, fontWeight: 590, letterSpacing: -0.1 }}>{cat.title}</div>
                    <div style={{ fontSize: 11, color: t.textMuted, marginTop: 1 }}>
                      {count} из {cat.all.length}
                    </div>
                  </div>
                  {!q && (
                    <span style={{
                      color: t.textMuted, display: 'flex',
                      transform: catCollapsed ? 'rotate(-90deg)' : 'rotate(0deg)',
                      transition: 'transform .2s',
                    }}>
                      <window.IconSVG name="chevron" size={18} strokeWidth={2.2} />
                    </span>
                  )}
                </div>
              </div>

              {catCollapsed ? null : hasGroups ? (
                <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
                  {cat.groups.map((g) => {
                    const gKey = `${cat.id}:${g.id}`;
                    const collapsed = collapsedGroups.has(gKey) && !q;
                    const groupTags = g.tags.map((tg) => {
                      const o = window.tagObj(tg);
                      return { ...o, key: o.key || `${cat.id}:${g.id}:${o.label}` };
                    });
                    const visibleTags = q ? groupTags.filter(matchTag) : groupTags;
                    if (q && visibleTags.length === 0 && !cat.catHit && !g.title.toLowerCase().includes(q)) return null;
                    const gCount = groupTags.filter((it) => selected.has(it.key)).length;
                    const gAll = gCount === groupTags.length;

                    return (
                      <div key={g.id} style={{
                        background: dark ? 'rgba(255,255,255,0.03)' : 'rgba(0,0,0,0.02)',
                        borderRadius: 10,
                        padding: '8px 10px 10px',
                      }}>
                        <div style={{
                          display: 'flex', alignItems: 'center', gap: 8,
                          marginBottom: collapsed ? 0 : 8,
                        }}>
                          <button
                            onClick={() => !q && toggleGroupCollapse(gKey)}
                            style={{
                              flex: 1, display: 'flex', alignItems: 'center', gap: 6,
                              border: 'none', background: 'transparent', padding: 0,
                              color: t.text, cursor: q ? 'default' : 'pointer', textAlign: 'left',
                              fontFamily: 'inherit',
                            }}>
                            <span style={{
                              color: t.textMuted, display: 'flex',
                              transform: collapsed ? 'rotate(-90deg)' : 'rotate(0deg)',
                              transition: 'transform .18s',
                            }}>
                              <window.IconSVG name="chevron" size={14} strokeWidth={2.4} />
                            </span>
                            <span style={{ fontSize: 12, fontWeight: 600, letterSpacing: 0.2, textTransform: 'uppercase', color: t.textMuted }}>
                              {g.title}
                            </span>
                            <span style={{ fontSize: 11, color: t.textHint, fontWeight: 500 }}>
                              {gCount}/{groupTags.length}
                            </span>
                          </button>
                          <button onClick={() => selectAllGroup(cat, g)} style={{
                            border: 'none', background: 'transparent', padding: '2px 6px',
                            color: t.accent, fontSize: 12, fontWeight: 510, cursor: 'pointer',
                            borderRadius: 6, fontFamily: 'inherit',
                          }}>
                            {gAll ? 'Снять' : 'Все'}
                          </button>
                        </div>

                        {!collapsed && (
                          <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
                            {visibleTags.map((it) => (
                              <TagChip key={it.key} item={it} cat={cat} on={selected.has(it.key)} onClick={() => toggle(it.key)} dark={dark} q={q} />
                            ))}
                          </div>
                        )}
                      </div>
                    );
                  })}
                </div>
              ) : (
                <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
                  {(q ? cat.tagHits : cat.all).map((it) => (
                    <TagChip key={it.key} item={it} cat={cat} on={selected.has(it.key)} onClick={() => toggle(it.key)} dark={dark} q={q} />
                  ))}
                </div>
              )}
            </section>
          );
        })}

        {filtered.every((c) => c.hidden) && (
          <div style={{ padding: '40px 24px', textAlign: 'center', color: t.textMuted, fontSize: 14 }}>
            Ничего не найдено по запросу «{query}»
          </div>
        )}

        <div style={{ padding: '8px 16px 76px', textAlign: 'right', color: t.textMuted, fontSize: 11, opacity: 0.4 }}>
          v11
        </div>
      </div>
    </window.TGShell>
    </>
  );
}

function TagChip({ item, cat, on, onClick, dark, q }) {
  const t = dark ? window.TG.dark : window.TG.light;
  return (
    <button
      onClick={onClick}
      style={{
        display: 'inline-flex', alignItems: 'center', gap: 6,
        padding: '7px 12px',
        borderRadius: 999,
        border: on ? 'none' : `1px solid ${dark ? 'rgba(255,255,255,0.14)' : 'rgba(0,0,0,0.12)'}`,
        background: on
          ? `oklch(${dark ? 60 : 55}% 0.16 ${cat.hue})`
          : 'transparent',
        color: on ? '#fff' : t.text,
        fontSize: 13, fontWeight: 500, letterSpacing: -0.1,
        cursor: 'pointer',
        transition: 'background .15s, color .15s, transform .08s',
        fontFamily: 'inherit',
      }}
      onMouseDown={(e) => (e.currentTarget.style.transform = 'scale(0.96)')}
      onMouseUp={(e) => (e.currentTarget.style.transform = '')}
      onMouseLeave={(e) => (e.currentTarget.style.transform = '')}
    >
      {on && (
        <span style={{ display: 'flex', marginLeft: -2 }}>
          <window.IconSVG name="check" size={13} strokeWidth={3} />
        </span>
      )}
      <span>{highlight(item.label, q, on)}</span>
    </button>
  );
}

function highlight(text, q, onBg) {
  if (!q) return text;
  const i = text.toLowerCase().indexOf(q.toLowerCase());
  if (i < 0) return text;
  const hlStyle = { fontWeight: 700, textDecoration: 'underline', textUnderlineOffset: 2 };
  return (
    <>
      {text.slice(0, i)}
      <span style={hlStyle}>{text.slice(i, i + q.length)}</span>
      {text.slice(i + q.length)}
    </>
  );
}

function CatCheckbox({ dark, state, hue, onClick }) {
  const on = state === 'on';
  const partial = state === 'partial';
  const active = on || partial;
  const color = `oklch(${dark ? 60 : 55}% 0.16 ${hue})`;
  return (
    <button
      onClick={onClick}
      aria-label={on ? 'Снять все теги категории' : 'Выбрать все теги категории'}
      style={{
        width: 22, height: 22, borderRadius: 6,
        border: active ? 'none' : `1.5px solid ${dark ? 'rgba(255,255,255,0.28)' : 'rgba(0,0,0,0.25)'}`,
        background: active ? color : 'transparent',
        cursor: 'pointer',
        display: 'flex', alignItems: 'center', justifyContent: 'center',
        color: '#fff', padding: 0, flexShrink: 0,
        transition: 'background .15s, border-color .15s, transform .08s',
      }}
      onMouseDown={(e) => (e.currentTarget.style.transform = 'scale(0.9)')}
      onMouseUp={(e) => (e.currentTarget.style.transform = '')}
      onMouseLeave={(e) => (e.currentTarget.style.transform = '')}
    >
      {on && <window.IconSVG name="check" size={15} strokeWidth={3} />}
      {partial && <div style={{ width: 10, height: 2, background: '#fff', borderRadius: 1 }} />}
    </button>
  );
}

Object.assign(window, { V2Chips });
