/* ctor-nav.jsx — меню «Конструктора» в облике кабинетов (client-v2, DESIGN.md v1.3; KSH-470): CtorTopNav — группы в строку
   шапки «ОБИТЕЛЬ», у каждой выпадающий список пунктов (из window.CtorNav; доступность, точка «есть черновик» и счётчик заявок — по
   unit пункта); CtorGroupTabs — пункты открытой группы строкой над окном раздела; CtorSubTabs — общая строка подвкладок над панелью.
   Префикс имён — cnv, чтобы не пересекаться с другими ctor-*.jsx (общий top-level scope). */
const { useEffect: cnvUseEffect, useRef: cnvUseRef, useState: cnvUseState } = React;

/* точка и счётчик пункта по unit: «Работы» — правки и каталога, и шаблонов, и правил — точка, если есть у любого unit, число — сумма */
function cnvBadgeOf(id, badges) {
  const N = window.CtorNav;
  const bs = badges ? N.unitsOf(id).map((u) => badges[u]).filter(Boolean) : [];
  return bs.length ? { dirty: bs.some((x) => x.dirty), count: bs.reduce((a, x) => a + (+x.count || 0), 0) } : null;
}
function CnvMark({ b }) {
  if (!b) return null;
  return <React.Fragment>
    {b.dirty && <span className="c2-dot" title="Есть неопубликованные изменения" />}
    {b.count > 0 && <span className="c2-count">{b.count}</span>}
  </React.Fragment>;
}

/* ============ CtorTopNav — «Главная» и группы меню в строку шапки ============
   visible — unit, доступные человеку (CtorRights.visibleSections); без него показываются все пункты. Группа без доступных пунктов не выводится.
   current — открытый пункт или null (главная). Клик по пункту — onGo(id); по «Главной» — onHome. */
function CtorTopNav({ current, onGo, onHome, badges, visible }) {
  const N = window.CtorNav;
  const [open, setOpen] = cnvUseState(null);
  const ref = cnvUseRef(null);
  cnvUseEffect(() => {
    if (!open) return undefined;
    const out = (e) => { if (ref.current && !ref.current.contains(e.target)) setOpen(null); };
    const esc = (e) => { if (e.key === 'Escape') setOpen(null); };
    document.addEventListener('mousedown', out); document.addEventListener('keydown', esc);
    return () => { document.removeEventListener('mousedown', out); document.removeEventListener('keydown', esc); };
  }, [open]);
  if (!N) return null;
  const shown = N.visibleItems(visible);
  const cur = shown.find((s) => s.id === current);
  return (
    <nav className="c2-nav" aria-label="Разделы конструктора" ref={ref}>
      <button type="button" aria-current={!current ? 'page' : undefined} onClick={() => { setOpen(null); onHome(); }}>Главная</button>
      {N.GROUPS.map((g) => {
        const secs = shown.filter((s) => s.group === g.id);
        if (!secs.length) return null;
        const dirty = secs.some((s) => { const b = cnvBadgeOf(s.id, badges); return b && (b.dirty || b.count > 0); });
        return (
          <div key={g.id} className={'c2-grp' + (cur && cur.group === g.id ? ' is-cur' : '')}>
            <button type="button" aria-expanded={open === g.id} aria-controls={'c2-grp-' + g.id} onClick={() => setOpen(open === g.id ? null : g.id)}>
              {g.label}{dirty && <span className="c2-dot" aria-hidden="true" />}<span aria-hidden="true" className="c2-caret">▾</span>
            </button>
            {open === g.id && <ul id={'c2-grp-' + g.id}>{secs.map((s) => (
              <li key={s.id}><button type="button" aria-current={s.id === current ? 'page' : undefined} onClick={() => { setOpen(null); onGo(s.id, null); }}>
                <span className="t">{s.label}{s.hint && <span className="h">{s.hint}</span>}</span><CnvMark b={cnvBadgeOf(s.id, badges)} />
              </button></li>))}</ul>}
          </div>);
      })}
    </nav>);
}

/* ============ CtorGroupTabs — пункты группы открытого раздела над окном ============ */
function CtorGroupTabs({ section, onGo, badges, visible }) {
  const N = window.CtorNav;
  if (!N) return null;
  const shown = N.visibleItems(visible);
  const cur = shown.find((s) => s.id === section);
  const secs = cur ? shown.filter((s) => s.group === cur.group) : [];
  if (secs.length < 2) return null;
  return (
    <nav className="c2-tabs" aria-label="Пункты группы">
      {secs.map((s) => (
        <button key={s.id} type="button" aria-current={s.id === section ? 'page' : undefined} onClick={() => onGo(s.id, null)} onMouseDown={(e) => e.preventDefault()}>
          {s.label}<CnvMark b={cnvBadgeOf(s.id, badges)} />
        </button>))}
    </nav>);
}

/* имя группы пункта — надпись над заголовком окна */
function ctorGroupLabel(sectionId) {
  const N = window.CtorNav;
  const s = N && N.SECTIONS.find((x) => x.id === sectionId);
  const g = s && N.GROUPS.find((x) => x.id === s.group);
  return g ? g.label : '';
}

/* ============ CtorSubTabs — подвкладки раздела (над панелью) ============ */
function CtorSubTabs({ subs, value, onChange }) {
  if (!subs || !subs.length) return null;
  return (
    <div style={{ ...ctorStyles.segmentedTrack, marginBottom: 22 }}>
      {subs.map((s) => (
        <button key={s.id} type="button" onClick={() => onChange(s.id)} style={ctorStyles.segmentedBtn(value === s.id)}>
          {s.label}
        </button>
      ))}
    </div>
  );
}

/* ============ CnvHowTo — «Как это работает» над панелями автоматизации ============
   Сворачиваемый блок: что делает панель, чем она отличается от соседних, пример. Флаг в localStorage ctor_howto_<id пункта>:
   нет — это первый показ в браузере, блок открыт (и помечается «показано»); seen — один раз показан, дальше свёрнут;
   open / closed — выбор человека, запоминается. Недоступное хранилище — блок просто открыт. */
const CNV_HOWTO = {
  'auto-packages': {
    title: 'Как работают пакеты услуг',
    lines: [
      'Пакет — услуга, которую выбирают целиком: клиент или менеджер. Её шаги ложатся в разные этапы сметы — каждый в свой, — а в смете включаются и выключаются вместе.',
      'Отличие от автоматики: пакет выбирают, а заготовки по анкете и перекрёстные работы включаются сами.',
    ],
    example: 'Пример: пакет «ТВ на стене» — шаги в штукатурке, электрике и чистовой.',
  },
  'auto-intake': {
    title: 'Как работают заготовки по анкете',
    lines: [
      'Заготовка связывает ответ клиента в анкете с составом сметы. Ответ совпал — этапы и пакеты услуг включаются в смету сами.',
      'Отличие от перекрёстных работ: заготовка срабатывает по анкете, а перекрёстная работа — по тому, что уже есть в смете.',
    ],
    example: 'Пример: заготовка «Вентиляция в анкете → этап Вентиляция + пакет смежных работ».',
  },
  'auto-cross': {
    title: 'Как работают перекрёстные работы',
    lines: [
      'Правило смотрит на состав сметы: если в ней есть работа X, подготовка к ней добавляется в других этапах — менеджеру не нужно помнить об этом.',
      'Отличие от заготовок: заготовка срабатывает по анкете, перекрёстная работа — по составу сметы.',
    ],
    example: 'Пример: «Кондиционер → дренаж в черновой сантехнике, кабель-канал в электрике».',
  },
};

function cnvHowtoInitial(id) {
  let v = null;
  try { v = window.localStorage.getItem('ctor_howto_' + id); } catch (e) { return true; }
  if (v === null) { try { window.localStorage.setItem('ctor_howto_' + id, 'seen'); } catch (e) { /* ignore */ } return true; }
  return v === 'open';
}

function CnvHowTo({ id }) {
  const info = CNV_HOWTO[id];
  const [open, setOpen] = cnvUseState(() => cnvHowtoInitial(id));
  if (!info) return null;
  const toggle = () => {
    const next = !open;
    setOpen(next);
    try { window.localStorage.setItem('ctor_howto_' + id, next ? 'open' : 'closed'); } catch (e) { /* ignore */ }
  };
  return (
    <section style={{ marginBottom: 18, borderRadius: 14, border: '1px solid var(--border-subtle)', background: 'var(--card)', overflow: 'hidden' }}>
      <button type="button" onClick={toggle} aria-expanded={open}
        style={{ display: 'flex', alignItems: 'center', gap: 9, width: '100%', padding: '12px 16px', border: 'none', background: 'transparent', cursor: 'pointer', fontFamily: 'inherit', fontSize: 14, fontWeight: 700, color: 'var(--foreground)', textAlign: 'left' }}>
        <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round"
          style={{ flexShrink: 0, color: 'var(--text-tertiary)', transform: open ? 'rotate(90deg)' : 'none', transition: 'transform .15s' }} aria-hidden="true"><polyline points="9 18 15 12 9 6"></polyline></svg>
        <span>Как это работает</span>
        <span style={{ fontSize: 12.5, fontWeight: 500, color: 'var(--text-tertiary)' }}>{info.title}</span>
      </button>
      {open && (
        <div style={{ padding: '0 16px 14px 39px', display: 'flex', flexDirection: 'column', gap: 8 }}>
          {info.lines.map((t, i) => <p key={i} style={{ margin: 0, fontSize: 13.5, lineHeight: 1.5, color: 'var(--text-secondary)', maxWidth: 760 }}>{t}</p>)}
          <div style={{ fontSize: 13, lineHeight: 1.5, color: 'var(--text-secondary)', background: 'var(--secondary)', borderRadius: 10, padding: '8px 12px', maxWidth: 760 }}>{info.example}</div>
        </div>
      )}
    </section>
  );
}

Object.assign(window, { CtorTopNav, CtorGroupTabs, ctorGroupLabel, CtorSubTabs, CnvHowTo, CNV_HOWTO });
