/* global React, API, Msg, Bubble, DocFrame, EmptyDoc, AiProg, Btn, now */
// Сценарий 1 — Заполнение документа по шаблону (РЕАЛЬНЫЙ DataDoc API).
// v2: минимум ручного ввода — данные извлекаются из приложенных документов (паспорт/реквизиты/…)
// и из сообщений в чате через Claude и раскладываются по полям шаблона. Ручная форма — для правок.

window.SCENARIOS = window.SCENARIOS || {};

function collectTree(nodes, path, out) {
  (nodes || []).forEach((node) => {
    const isFolder = node.type === 'folder' || Array.isArray(node.children) || Array.isArray(node.items);
    if (isFolder) collectTree(node.children, [...path, node.name || 'Папка'], out), collectTree(node.items, [...path, node.name || 'Папка'], out);
    else if (node.id) out.push({ id: node.id, name: node.name || 'Без названия', folders: path });
  });
}
window.collectTemplateTree = collectTree;

// плоский список полей шаблона с уникальным ключом si:id
function flattenFields(sides) {
  const out = [];
  (sides.sides || []).forEach((side, si) => (side.tattrFolders || []).forEach((folder) =>
    (folder.tattrs || []).slice().sort((a, b) => (a.priority ?? 0) - (b.priority ?? 0)).forEach((attr) =>
      out.push({ key: si + ':' + attr.id, si, id: attr.id, name: attr.name || attr.id, required: !!attr.required, type: attr.type, values: attr.values, inputText: attr.inputText, mask: attr.mask, maxLength: attr.maxLength }))));
  return out;
}

// подсказка (эвристика-фолбэк): какие документы можно приложить, судя по полям
function suggestDocs(fields) {
  const s = fields.map((f) => (f.name || '').toLowerCase()).join(' ');
  const out = [];
  if (/паспорт|фамили|отчеств|\bсерия\b|кем выдан|рожден|кода подразд/.test(s)) out.push('фото паспорта');
  if (/инн|огрн|кпп|наименован|директор|юр\.?\s*адрес|реквизит/.test(s)) out.push('реквизиты компании или визитку');
  if (/кадастр|помещени|\bобъект\b|недвиж|егрн/.test(s)) out.push('выписку ЕГРН');
  if (/счёт|сумма|\bцена\b|оплат|банк|р\/с|бик/.test(s)) out.push('счёт или банковские реквизиты');
  return out;
}

// AI-разметка: по полям шаблона Claude предлагает, какие документы приложить для авто-заполнения
const SUGGEST_DOCS_SYSTEM = `Ты — ассистент DataDoc. Тебе дают название шаблона документа и список его полей. Определи, какие исходные документы удобнее всего ПРИЛОЖИТЬ пользователю, чтобы автоматически заполнить эти поля распознаванием (OCR). Типовые источники: паспорт физлица, карточка компании / реквизиты, выписка ЕГРЮЛ/ЕГРИП, выписка ЕГРН, счёт, банковские реквизиты, свидетельство, доверенность, водительское удостоверение, СНИЛС, визитка. Верни СТРОГО JSON без markdown: {"docs":[{"name":"<что приложить>","fills":"<какие поля закроет, 2-4 слова>"}],"manual":["<поля, которые обычно вводят вручную>"],"tip":"<одна короткая подсказка>"}. Не более 4 документов. Только релевантное именно этим полям.`;

async function suggestDocsAI(tpl, fields) {
  try {
    const spec = fields.map((f) => ({ name: f.name, type: f.type, required: f.required }));
    const res = await API.claudeJSON(SUGGEST_DOCS_SYSTEM, [{ type: 'text', text: `Шаблон: «${tpl.name}»\nПоля (JSON):\n` + JSON.stringify(spec) }], { max_tokens: 900 });
    if (res.data && Array.isArray(res.data.docs) && res.data.docs.length) return res.data;
  } catch (e) { /* фолбэк ниже */ }
  return { docs: suggestDocs(fields).map((n) => ({ name: n })), manual: [], tip: '' };
}

// определить «вид» поля по названию — для подсказок Дадаты и авто-раскладки
function fieldKind(name) {
  // ВАЖНО: \b в JS не работает с кириллицей (это ASCII-границы), поэтому подстроки без \b
  const s = (name || '').toLowerCase();
  if (/адрес|местонахожд|мест[оа]\s*регистр|прописк/.test(s)) return 'address';
  if (/инн/.test(s)) return 'inn';
  if (/кпп/.test(s)) return 'kpp';
  if (/огрн/.test(s)) return 'ogrn';
  if (/товар|услуг|работ|предмет|объект|продукци|груз|материал|издели/.test(s)) return null; // предмет договора, не сторона
  if (/паспорт|снилс|фио|фамили|отчеств|рожден|телефон|e-?mail|почт[аеы]|полномоч|срок|основани|должност|директор|руководител|генеральн|подписант/.test(s)) return null; // персональные/прочие — не автоподбор компании
  if (/организац|компан|контрагент|заказчик|исполнител|поставщик|покупател|доверител|арендодател|арендатор|подрядчик|клиент|продавец|фирм|общество|наименовани/.test(s)) return 'company';
  return null;
}
const ROLE_WORDS = ['заказчик', 'исполнител', 'поставщик', 'покупател', 'доверител', 'представител', 'арендодател', 'арендатор', 'подрядчик', 'продавец', 'клиент'];
function roleOf(name) { const s = (name || '').toLowerCase(); for (const w of ROLE_WORDS) if (s.includes(w)) return w; return ''; }
const isDirectorField = (name) => /директор|руководител|генеральн|подписант|в лице/.test((name || '').toLowerCase());

// ── выбор шаблона (когда их несколько) ──
function TemplatePicker({ templates, onPick, presetFilter }) {
  const [q, setQ] = React.useState(presetFilter || '');
  const qq = q.toLowerCase();
  let list = templates.filter((t) => !qq || t.name.toLowerCase().includes(qq) || (t.folders || []).join(' ').toLowerCase().includes(qq));
  if (!list.length && q) list = templates; // не прячем всё, если фильтр ничего не дал
  return (
    <div className="cpcard" style={{ maxWidth: 460 }}>
      <div className="h"><div className="nm">Выберите шаблон</div><div className="ok">{templates.length} шт.</div></div>
      <input value={q} onChange={(e) => setQ(e.target.value)} placeholder="поиск по шаблонам…"
        style={{ width: '100%', margin: '8px 0', padding: '8px 10px', border: '1px solid var(--line-2)', borderRadius: 8, fontSize: 13, fontFamily: 'var(--sans)' }} />
      <div style={{ maxHeight: 260, overflowY: 'auto', display: 'flex', flexDirection: 'column', gap: 4 }}>
        {list.map((t) => (
          <div key={t.id} className="btn-aip" style={{ textAlign: 'left', padding: '8px 12px' }} onClick={() => onPick(t)}>
            {window.DocIcon ? <window.DocIcon size={14} /> : '▤'} {t.name}{t.folders.length ? <span style={{ color: 'var(--ink-3)', fontSize: 11, marginLeft: 6 }}>· {t.folders.join(' / ')}</span> : null}
          </div>
        ))}
      </div>
    </div>
  );
}

// ── одно поле формы с подсказками Дадаты (компании/ИНН/адрес) ──
function SmartField({ f, value, onChange, onParty }) {
  const base = { width: '100%', padding: '6px 8px', border: '1px solid var(--line-2)', borderRadius: 6, fontSize: 12.5, fontFamily: 'var(--sans)' };
  const filled = value !== undefined && value !== '' && value !== null;
  const kind = fieldKind(f.name);
  const isText = !(f.type === 'list' || f.type === 'date' || f.type === 'integer' || f.type === 'decimal' || f.type === 'money');
  const smart = isText && (kind === 'company' || kind === 'inn' || kind === 'address');
  const [sugg, setSugg] = React.useState([]);
  const [open, setOpen] = React.useState(false);
  const [loading, setLoading] = React.useState(false);
  const tRef = React.useRef(null);
  const boxRef = React.useRef(null);

  React.useEffect(() => {
    const off = (e) => { if (boxRef.current && !boxRef.current.contains(e.target)) setOpen(false); };
    document.addEventListener('mousedown', off);
    return () => document.removeEventListener('mousedown', off);
  }, []);

  const search = (q) => {
    if (!smart || !q || q.trim().length < 3) { setSugg([]); setOpen(false); return; }
    clearTimeout(tRef.current);
    tRef.current = setTimeout(async () => {
      setLoading(true);
      try {
        if (kind === 'address') {
          const r = await API.suggestAddress(q, 6);
          setSugg(((r && r.suggestions) || []).map((s) => ({ label: s.value, address: s.unrestricted_value || s.value })));
        } else {
          const r = await API.suggestPartyDirect(q, 6);
          const items = window.ddPickSuggestions ? window.ddPickSuggestions(r) : ((r && r.suggestions) || []);
          setSugg(items.map((s) => { const p = window.ddPartyFields ? window.ddPartyFields(s) : s; return { label: p.value, sub: [p.inn && 'ИНН ' + p.inn, p.address && p.address !== '—' ? p.address : ''].filter(Boolean).join(' · '), party: p }; }));
        }
        setOpen(true);
      } catch (e) { setSugg([]); } finally { setLoading(false); }
    }, 280);
  };
  const change = (v) => { onChange(v); search(v); };
  const pick = (s) => {
    if (s.party) { onChange(kind === 'inn' ? (s.party.inn || s.party.value) : (s.party.full && s.party.full !== '—' ? s.party.full : s.party.value)); if (onParty) onParty(s.party, f); }
    else onChange(s.address);
    setOpen(false); setSugg([]);
  };

  let input;
  if (f.type === 'list' && Array.isArray(f.values)) {
    input = <select style={base} value={value || ''} onChange={(e) => onChange(e.target.value)}><option value="">—</option>{f.values.map((v, i) => <option key={i} value={v}>{v}</option>)}</select>;
  } else if (f.type === 'date') {
    input = <input type="date" style={base} value={value || ''} onChange={(e) => onChange(e.target.value)} />;
  } else if (f.type === 'integer' || f.type === 'decimal' || f.type === 'money') {
    input = <input type="number" step={f.type === 'integer' ? '1' : '0.01'} style={base} value={value || ''} placeholder={f.inputText || ''} onChange={(e) => onChange(e.target.value)} />;
  } else if (smart) {
    input = <input type="text" style={base} value={value || ''} placeholder={kind === 'address' ? 'начните вводить адрес…' : 'название или ИНН — подскажет Дадата…'} autoComplete="off"
      onChange={(e) => change(e.target.value)} onFocus={() => { if (sugg.length) setOpen(true); }} />;
  } else {
    input = <input type="text" style={base} value={value || ''} placeholder={f.inputText || f.mask || ''} maxLength={f.maxLength || undefined} onChange={(e) => onChange(e.target.value)} />;
  }
  return (
    <div style={{ marginBottom: 7, position: 'relative' }} ref={boxRef}>
      <div className="k" style={{ marginBottom: 2, fontSize: 11 }}>{f.name}{f.required ? <span style={{ color: '#c33' }}> *</span> : null}{filled ? <span style={{ color: '#1f6b3a', marginLeft: 5 }}>✓</span> : null}{smart ? <span style={{ color: '#006EDD', marginLeft: 5, fontSize: 10 }}>◆ Дадата</span> : null}</div>
      {input}
      {smart && open && (loading || sugg.length) ? (
        <div style={{ position: 'absolute', left: 0, right: 0, top: '100%', zIndex: 50, background: 'var(--paper)', border: '1px solid var(--line-2)', borderRadius: 8, boxShadow: '0 10px 26px rgba(20,40,80,.16)', marginTop: 3, maxHeight: 220, overflowY: 'auto' }}>
          {loading && !sugg.length ? <div style={{ padding: '8px 10px', fontSize: 12, color: 'var(--ink-3)' }}>ищу в Дадате…</div> : null}
          {sugg.map((s, i) => (
            <div key={i} onMouseDown={(e) => { e.preventDefault(); pick(s); }} onClick={(e) => { e.preventDefault(); pick(s); }} style={{ padding: '7px 10px', cursor: 'pointer', borderTop: i ? '1px solid var(--line)' : 0, fontSize: 12.5 }}
              onMouseEnter={(e) => e.currentTarget.style.background = 'var(--paper-2)'} onMouseLeave={(e) => e.currentTarget.style.background = ''}>
              <div style={{ fontWeight: 600, color: 'var(--ink)' }}>{s.label}</div>
              {s.sub ? <div style={{ fontSize: 11, color: 'var(--ink-3)', marginTop: 1 }}>{s.sub}</div> : null}
            </div>
          ))}
        </div>
      ) : null}
    </div>
  );
}

// ── форма заполнения (реагирует на данные из чата/документов через window.__activeFill) ──
function TemplateFiller({ ctx, template, sides }) {
  const fields = React.useMemo(() => flattenFields(sides), [sides]);
  const [vals, setVals] = React.useState({});
  const [open, setOpen] = React.useState(true); // инпуты видны сразу — удобное ручное заполнение
  const [state, setState] = React.useState('form');
  const [err, setErr] = React.useState('');
  const [docName, setDocName] = React.useState(template.name + ' — ' + new Date().toLocaleDateString('ru-RU'));

  React.useEffect(() => {
    window.__activeFill = { template, fields, apply: (inc) => setVals((v) => ({ ...v, ...inc })) };
    return () => { if (window.__activeFill && window.__activeFill.template === template) window.__activeFill = null; };
  }, [template, fields]);

  const filledCount = fields.filter((f) => vals[f.key] !== undefined && vals[f.key] !== '' && vals[f.key] !== null).length;
  const missingReq = fields.filter((f) => f.required && !(vals[f.key] !== undefined && vals[f.key] !== '' && vals[f.key] !== null));

  // выбор компании из Дадаты в одном поле → авто-заполнение связанных полей той же стороны
  const applyParty = (p, src) => {
    const srcRole = roleOf(src.name);
    const inc = {};
    fields.forEach((f) => {
      const k = fieldKind(f.name);
      const dir = isDirectorField(f.name);
      if (!k && !dir) return;
      if (f.key !== src.key) { const r = roleOf(f.name); if (srcRole && r && r !== srcRole) return; } // другая сторона — не трогаем
      let v = '';
      if (k === 'company') v = (p.full && p.full !== '—') ? p.full : p.value;
      else if (k === 'inn') v = p.inn || '';
      else if (k === 'kpp') v = p.kpp || '';
      else if (k === 'ogrn') v = p.ogrn || '';
      else if (k === 'address') v = (p.address && p.address !== '—') ? p.address : '';
      else if (dir) v = (p.director && p.director !== '—') ? p.director : '';
      if (v) inc[f.key] = v;
    });
    if (Object.keys(inc).length) setVals((o) => ({ ...o, ...inc }));
  };

  const create = async () => {
    if (missingReq.length) { setErr('Не хватает обязательных полей: ' + missingReq.map((f) => f.name).join(', ') + '. Напишите их в чат или заполните ниже.'); setOpen(true); return; }
    setErr(''); setState('creating');
    // демо-шаблон (нет DataDoc-ключа) — собираем документ через Claude из значений полей
    if (template.demo) {
      const filled = fields.map((f) => ({ name: f.name, value: vals[f.key] })).filter((x) => x.value);
      const k = ctx.node(<Msg who="ai" ts={now()}><AiProg icon="▤" label="собираю документ по шаблону" count="Claude" /></Msg>);
      try {
        const sys = `Ты — юрист DataDoc. Составь готовый документ «${template.name}» на основе данных. Верни СТРОГО JSON без markdown: {"title":"<название>","text":"<полный текст документа с разделами и реквизитами сторон>"}. Деловой юридический русский. Чего не хватает — оставь «____».`;
        const d = (await API.claudeJSON(sys, [{ type: 'text', text: 'Шаблон: ' + template.name + '\nДанные (JSON):\n' + JSON.stringify(filled) }], { max_tokens: 3000 })).data;
        ctx.remove(k);
        if (!d || !d.text) throw new Error('Не удалось собрать документ');
        ctx.setDoc(<DocFrame title={d.title || docName} sub="демо-шаблон · редактируемый"><EditableDoc title={d.title || docName} text={d.text} fileName={d.title || docName} /></DocFrame>);
        ctx.uncapture(); window.__activeFill = null; setState('done');
        ctx.aiNode(<Bubble><span style={{ display: 'flex', gap: 8, alignItems: 'center' }}><span style={{ fontSize: 24, color: '#1f6b3a' }}>✓</span><span>Готово. <b>«{d.title || docName}»</b> собран по шаблону — превью справа, можно править и скачать. <span style={{ color: 'var(--ink-3)' }}>(демо: без DataDoc-ключа документ не сохраняется в аккаунт)</span></span></span></Bubble>);
      } catch (e) { ctx.remove(k); setState('form'); setErr(e.message); }
      return;
    }
    try {
      const sideValues = (sides.sides || []).map(() => ({ tattrValues: {} }));
      fields.forEach((f) => { const v = vals[f.key]; if (v !== undefined && v !== '' && v !== null) sideValues[f.si].tattrValues[f.id] = v; });
      const created = await API.datadoc('POST', `/templates/${encodeURIComponent(template.id)}/render`, { name: docName.trim() || template.name, sideValues });
      const rid = created.renderId || created.id;
      if (!rid) throw new Error('API не вернул ID документа');
      const pdf = await API.datadoc('GET', `/templates/${encodeURIComponent(template.id)}/render/${encodeURIComponent(rid)}?format=pdf`, null, { raw: true });
      if (!pdf.ok) throw new Error('PDF не получен (HTTP ' + pdf.status + ')');
      const url = URL.createObjectURL(await pdf.blob());
      const fname = (created.renderName || docName).replace(/[\\/:*?"<>|]/g, '_');
      ctx.setDoc(<DocFrame title={created.renderName || docName} sub={`№ ${created.renderNumber ?? '—'} · создан в DataDoc`} toolbar={<a className="b" href={url} download={fname + '.pdf'}>PDF</a>}>
        <iframe title="pdf" src={url} style={{ flex: 1, width: '100%', border: 0, borderRadius: 8, background: '#fff' }} />
      </DocFrame>);
      ctx.uncapture(); window.__activeFill = null; setState('done');
      ctx.charge(1); // документ создан в DataDoc — 1 докс
      ctx.aiNode(<Bubble><span style={{ display: 'flex', gap: 8, alignItems: 'center' }}><span style={{ fontSize: 24, color: '#1f6b3a' }}>✓</span><span>Готово. Документ <b>«{created.renderName || docName}»</b> создан и сохранён в DataDoc.</span></span>
        <div className="acta"><a className="btn-aip primary" href={url} download={fname + '.pdf'}>Скачать PDF →</a></div></Bubble>);
    } catch (e) { setState('form'); setErr(e.message); }
  };

  if (state === 'done') return <Bubble><span style={{ color: '#1f6b3a' }}>✓ Документ создан — превью справа.</span></Bubble>;

  return (
    <div className="cpcard" style={{ maxWidth: 480 }}>
      <div className="h"><div className="nm">{template.name}</div><div className="ok">{filledCount}/{fields.length} полей</div></div>
      {missingReq.length
        ? <div style={{ fontSize: 12, color: 'var(--ink-2)' }}>Осталось заполнить обязательные: <b>{missingReq.slice(0, 6).map((f) => f.name).join(', ')}</b>{missingReq.length > 6 ? ' …' : ''}. Напишите их в чат или приложите документ.</div>
        : <div style={{ fontSize: 12, color: '#1f6b3a' }}>Все обязательные поля заполнены — можно создавать документ.</div>}
      {err ? <div style={{ color: '#c33', fontSize: 12, margin: '6px 0' }}>{err}</div> : null}
      <div style={{ display: 'flex', gap: 8, alignItems: 'center', marginTop: 8, flexWrap: 'wrap' }}>
        <Btn kind="primary" onClick={state === 'creating' ? undefined : create}>{state === 'creating' ? 'Создаю…' : 'Создать документ →'}</Btn>
        <div className="btn-aip" onClick={() => setOpen((o) => !o)}>{open ? 'Скрыть поля' : 'Показать / править поля'}</div>
      </div>
      {open ? (
        <div style={{ marginTop: 10, borderTop: '1px solid var(--line)', paddingTop: 10 }}>
          <div style={{ marginBottom: 7 }}><div className="k" style={{ marginBottom: 2, fontSize: 11 }}>Название документа</div>
            <input value={docName} onChange={(e) => setDocName(e.target.value)} style={{ width: '100%', padding: '6px 8px', border: '1px solid var(--line-2)', borderRadius: 6, fontSize: 12.5, fontFamily: 'var(--sans)' }} /></div>
          {fields.map((f) => <SmartField key={f.key} f={f} value={vals[f.key]} onChange={(v) => setVals((o) => ({ ...o, [f.key]: v }))} onParty={applyParty} />)}
        </div>
      ) : null}
    </div>
  );
}

// ── извлечение данных из чата/документов и раскладка по полям ──
const FILL_SYSTEM = `Ты — модуль DataDoc, который извлекает данные для заполнения полей шаблона документа.
Тебе дают список целевых полей (id, name, type, options) и материалы: сканы/фото/PDF документов и/или текст от пользователя.
Верни СТРОГО валидный JSON без markdown: {"values":{"<id>":"<значение>"},"note":"что не удалось определить"}.
ПРАВИЛА:
- Ключи values — это id полей из списка. Заполняй ТОЛЬКО поля, значение которых явно есть в материалах. Не выдумывай.
- Даты — в формате YYYY-MM-DD. Числа/суммы — только число. Для type "list" выбирай значение строго из options.
- ФИО, реквизиты, ИНН, адреса бери как в документе. Если поле не определяется — не включай его в values.
- Русский язык значений.`;

async function fillExtract(ctx, { text, files }) {
  const af = window.__activeFill;
  if (!af) { ctx.uncapture(); return ctx.ai('Заполнение не активно. Напишите «заполнить документ», чтобы начать.'); }
  const t = (text || '').trim().toLowerCase();
  if (/^(отмена|стоп|назад|выйти|отменить)$/.test(t)) { ctx.uncapture(); window.__activeFill = null; return ctx.ai('Ок, вышла из заполнения. Чем ещё помочь?'); }

  const content = [];
  if (files && files.length) {
    const { blocks, warnings } = await API.filesToContent(files);
    content.push(...blocks);
    if (warnings.length) ctx.aiNode(<Bubble><span style={{ color: '#c33' }}>Не смог прочитать: {warnings.join('; ')}</span></Bubble>);
  }
  if (text && text.trim()) content.push({ type: 'text', text: 'Данные от пользователя:\n' + text });
  if (!content.length) return ctx.ai('Приложите документ (паспорт, реквизиты, выписку) или напишите данные текстом — разложу по полям.');

  const spec = af.fields.map((f) => ({ id: f.key, name: f.name, type: f.type, required: f.required, options: Array.isArray(f.values) ? f.values : undefined }));
  content.push({ type: 'text', text: 'Целевые поля шаблона (JSON):\n' + JSON.stringify(spec) + '\nИзвлеки значения из материалов и верни JSON строго по схеме.' });

  const res = await API.claudeJSON(FILL_SYSTEM, content, { max_tokens: 2500 });
  const values = (res.data && (res.data.values || res.data)) || {};
  const nameByKey = Object.fromEntries(af.fields.map((f) => [String(f.key), f.name]));
  const applied = {};
  Object.keys(values).forEach((k) => { if (nameByKey[k] !== undefined && values[k] !== '' && values[k] != null) applied[k] = values[k]; });
  af.apply(applied);

  const keys = Object.keys(applied);
  if (!keys.length) { ctx.aiNode(<Bubble>Не нашла подходящих данных в этом сообщении. Уточните — например: «ИНН 7707083893, директор Иванов И.И.» — или приложите документ.</Bubble>); return; }
  ctx.aiNode(
    <>
      <Bubble>Разложила данные по полям:</Bubble>
      <div className="fmap">
        {keys.slice(0, 12).map((k) => (
          <div className="r" key={k}><span className="src">{(files && files.length) ? 'из документа' : 'из сообщения'}</span><span className="arr">→</span><span className="dst"><span className="lbl">{nameByKey[k]}</span>{String(applied[k])}</span></div>
        ))}
      </div>
      {res.data && res.data.note ? <div style={{ fontSize: 11, color: 'var(--ink-3)', marginTop: 6 }}>{res.data.note}</div> : null}
    </>
  );
}

// ── открыть шаблон: AI разбирает поля → предлагает какие документы приложить → форма ──
async function openTemplateFlow(ctx, tpl, opts = {}) {
  const mass = !!opts.mass;
  ctx.setHead(mass ? 'Массовое создание документов' : 'Заполнение документа', tpl.name);
  ctx.setDoc(<DocFrame title={tpl.name} sub="загружаю поля…"><EmptyDoc lines={['▤', 'читаю поля шаблона…']} /></DocFrame>);
  let sides = tpl.sides || null;
  if (!sides) {
    const k = ctx.node(<Msg who="ai" ts={now()}><AiProg icon="▤" label="читаю поля шаблона" count="DataDoc" /></Msg>);
    try { sides = await API.datadoc('GET', `/templates/${encodeURIComponent(tpl.id)}/sides`); }
    catch (e) { ctx.remove(k); ctx.aiNode(<Bubble><span style={{ color: '#c33' }}>Не удалось загрузить поля: {e.message}</span></Bubble>); return; }
    ctx.remove(k);
  }

  const fields = flattenFields(sides);
  const req = fields.filter((f) => f.required);

  // Claude смотрит на поля и предлагает, какие документы приложить
  const kk = ctx.node(<Msg who="ai" ts={now()}><AiProg icon="🔎" label="разбираю поля шаблона · подбираю документы" count="Claude" /></Msg>);
  const advice = await suggestDocsAI(tpl, fields);
  ctx.remove(kk);

  ctx.setDoc(<DocFrame title={tpl.name} sub="данные из сканов, чата и Дадаты"><EmptyDoc lines={['▤', 'приложите документы или заполните поля —\nпревью документа появится здесь']} /></DocFrame>);
  ctx.aiNode(
    <>
      <Bubble>
        Шаблон <b>«{tpl.name}»</b>: {fields.length} полей{req.length ? `, обязательных ${req.length}` : ''}. Разобрала поля — вот что удобно приложить, я распознаю и разложу по полям:
        {advice.docs && advice.docs.length ? (
          <div style={{ display: 'flex', flexDirection: 'column', gap: 6, margin: '10px 0 4px' }}>
            {advice.docs.map((d, i) => (
              <div key={i} style={{ display: 'flex', gap: 8, alignItems: 'baseline', padding: '7px 10px', background: 'var(--paper-2)', borderRadius: 8 }}>
                <span style={{ fontSize: 14 }}>📎</span>
                <span><b>{d.name}</b>{d.fills ? <span style={{ color: 'var(--ink-3)', fontSize: 12 }}> — {d.fills}</span> : null}</span>
              </div>
            ))}
          </div>
        ) : null}
        <div style={{ fontSize: 12.5, color: 'var(--ink-2)', marginTop: 8 }}>
          Перетащите документы в чат 📎 (или напишите данные текстом). Остальное — в форме ниже: <b>наименование, ИНН и адрес подскажет Дадата</b> прямо в поле.{advice.tip ? ' ' + advice.tip : ''}
        </div>
      </Bubble>
      <TemplateFiller ctx={ctx} template={tpl} sides={sides} />
    </>
  );
  ctx.capture(fillExtract); // дальнейшие сообщения/файлы идут в заполнение
}
window.SCENARIOS.fillTemplate = openTemplateFlow;
window.TemplatePicker = TemplatePicker;
window.SmartField = SmartField;   // инпут с подсказками Дадаты — переиспользуется в batch
window.fieldKind = fieldKind;
window.flattenTemplateFields = flattenFields;

window.SCENARIOS.fill = async function (ctx, { text }) {
  ctx.setDoc(<DocFrame title="шаблон" sub="выбор шаблона"><EmptyDoc lines={['▤', 'подбираю шаблоны…']} /></DocFrame>);
  const k = ctx.node(<Msg who="ai" ts={now()}><AiProg icon="▤" label="загружаю шаблоны" count="DataDoc" /></Msg>);
  let templates = [];
  try {
    const tree = await API.datadoc('GET', '/folders/allcontent');
    collectTree(Array.isArray(tree) ? tree : (tree ? [tree] : []), [], templates);
  } catch (e) { ctx.remove(k); ctx.aiNode(<Bubble><span style={{ color: '#c33' }}>Не удалось загрузить шаблоны: {e.message}</span></Bubble>); return; }
  ctx.remove(k);

  if (!templates.length) { ctx.aiNode(<Bubble>В аккаунте нет размеченных шаблонов. Создайте шаблон в DataDoc и попробуйте снова.</Bubble>); return; }
  if (templates.length === 1) { return openTemplateFlow(ctx, templates[0]); } // один шаблон — открываем сразу

  const hint = (text.match(/(?:заполни|заполнить|создай|шаблон[у]?|договор)\s+([а-яa-zё-]{3,})/i) || [])[1] || '';
  const hintOk = hint && templates.some((t) => t.name.toLowerCase().includes(hint.toLowerCase()));
  ctx.aiNode(<><Bubble>Нашла <b>{templates.length}</b> шаблонов. Выберите нужный:</Bubble>
    <TemplatePicker templates={templates} onPick={(t) => { ctx.you('Заполнить: ' + t.name); openTemplateFlow(ctx, t); }} presetFilter={hintOk ? hint : ''} /></>);
};
