/* dp-brief-view.jsx — бриф на дизайн-проект в режиме чтения: презентация для дизайнера (и клиента после отправки).
   Ответы анкеты (FormInstance.responses + карточка объекта) раскладываются в понятную структуру: шапка с ключевыми
   фактами, портрет клиента и быт, стиль и атмосфера (картинки крупно), цвет и материалы, референсы, антипримеры,
   планировка и кухня, помещения, инженерия, мебель, бюджет и состав ДП, комментарии, задание для AI.
   Экспорт: «PDF для AI» (brief-print.html → печать в PDF) и «Скопировать для AI» (Markdown в буфер).
   Exports on window: DpBriefView, DpBriefExport { markdown, aiPrompt, facts } */
(function () {
  const { Badge, Button } = window.DesignSystem_9e0a09;
  const { Ic } = window;
  const { useState, useMemo, useEffect } = React;
  const Mock = () => window.DpBriefTemplateMock;
  const isFilled = (v) => !(v == null || v === '' || v === false || (Array.isArray(v) && !v.length));
  const visible = (f, r) => { const M = Mock(); return M && M.fieldVisible ? M.fieldVisible(f, r) : true; };
  const L = {
    housing: { apartment: 'Квартира', apart_hotel: 'Апартаменты', house: 'Дом', commercial: 'Коммерция' },
    obj: { new_build: 'новостройка', secondary: 'вторичка' },
    finish: { without: 'без отделки', partial: 'white box', renovation: 'с ремонтом' },
    repair: { cosmetic: 'косметический', capital: 'капитальный' },
    tier: { economy: 'Эконом', mid: 'Комфорт', premium: 'Премиум' },
    prio: { high: 'высокий', medium: 'средний', low: 'низкий' },
  };
  const fmtDate = (s) => { if (!s) return ''; const d = new Date(s); return isNaN(d) ? '' : d.toLocaleDateString('ru-RU', { day: 'numeric', month: 'long', year: 'numeric' }); };

  /* значение поля в человеческом виде: строка или массив (чипы) */
  function fieldValue(f, r) {
    let v = r[f.id];
    if (!isFilled(v)) return null;
    if (f.type === 'chip_single' && Array.isArray(f.options)) { const o = f.options.find((x) => x && typeof x === 'object' && x.v === v); v = o ? o.l : v; }
    if (f.type === 'media') return v.filter((m) => m.url).map((m) => m.url);
    if (f.type === 'checkbox') return 'да';
    if (Array.isArray(v)) { const out = [...v]; if (f.allowCustom && f.customId && r[f.customId]) out.push(String(r[f.customId])); return out; }
    return String(v);
  }
  const secById = (schema, id) => (schema.sections || []).find((s) => s.id === id) || null;
  const fld = (schema, secId, fid) => { const s = secById(schema, secId); return s && (s.fields || []).find((f) => f.id === fid) || null; };
  const val = (schema, r, secId, fid) => { const f = fld(schema, secId, fid); return f && visible(f, r) ? fieldValue(f, r) : null; };
  const txt = (v) => (Array.isArray(v) ? v.join(', ') : (v || ''));

  /* факты об объекте из карточки сделки */
  function objectFacts(intake) {
    const it = intake || {};
    const area = it.measureSession && it.measureSession.totals && it.measureSession.totals.area ? it.measureSession.totals.area + ' м² по замеру' : (it.areaApprox ? '≈ ' + it.areaApprox + ' м²' : '');
    const rows = [
      ['Объект', [L.housing[it.housingType], L.obj[it.objectType], L.finish[it.finish]].filter(Boolean).join(' · ')],
      ['Адрес', [it.city, it.address, it.apt ? 'кв. ' + it.apt : ''].filter(Boolean).join(', ')],
      ['Площадь', area],
      ['Комнат · санузлов · уровней', [it.roomsCount, it.bathsCount, it.levels].filter(Boolean).join(' · ')],
      ['Потолки · год дома', [it.ceiling ? it.ceiling + ' м' : '', it.year ? it.year + ' г.' : ''].filter(Boolean).join(' · ')],
      ['Открытые зоны', (it.outdoor || []).filter((x) => x !== 'Нет').join(', ')],
      ['Ремонт', [L.repair[(it.prefs || {}).repairType], L.tier[(it.prefs || {}).finishTier]].filter(Boolean).join(' · ')],
      ['Сроки', [(it.prefs || {}).startWanted ? 'старт ' + it.prefs.startWanted : '', (it.prefs || {}).deadlineDate ? 'закончить к ' + it.prefs.deadlineDate : ''].filter(Boolean).join(' · ')],
    ];
    return rows.filter(([, v]) => v);
  }

  /* портрет клиента — короткий связный текст из ответов блока «Семья и быт» */
  function familyNarrative(schema, r) {
    const g = (id) => val(schema, r, 'family', id);
    const p = [];
    const adults = g('familyAdults'); const kids = g('hasChildren');
    const age = g('adultsAge'); const prof = g('profession');
    if (adults) p.push((adults === '1' ? 'Один взрослый' : adults + ' взрослых') + (age ? ' (' + txt(age) + ' лет)' : ''));
    if (prof) p.push('сфера: ' + txt(prof).toLowerCase());
    if (kids === 'Да') { const n = g('childrenCount'); const ages = g('childrenAges'); const N = { '1': 'один ребёнок', '2': 'двое детей', '3': 'трое детей', '4+': 'четверо и больше детей' }; p.push((N[n] || 'есть дети') + (ages ? ' (' + txt(ages) + ' лет)' : '')); }
    else if (kids === 'Пока нет, планируем') p.push('детей пока нет, планируют');
    const rooms = g('childrenRooms'); if (rooms) p.push('детские: ' + txt(rooms).toLowerCase());
    const more = g('moreChildren'); if (more && more !== 'Нет') p.push('ещё дети: ' + txt(more).toLowerCase());
    const eld = g('elderly'); if (eld && eld !== 'Не живут') p.push('пожилые ' + txt(eld).toLowerCase());
    const pets = g('pets'); if (pets && !(Array.isArray(pets) && pets.length === 1 && pets[0] === 'Нет')) p.push('питомцы: ' + txt(pets).toLowerCase());
    const guests = g('guests'); if (guests) p.push('гости — ' + txt(guests).toLowerCase());
    const wfh = g('workFromHome'); if (wfh && wfh !== 'Нет') p.push('работа из дома: ' + txt(wfh).toLowerCase());
    const hob = g('hobbies'); if (hob) p.push('увлечения: ' + txt(hob).toLowerCase());
    return p.length ? p.join('; ') + '.' : '';
  }

  /* структура презентации: группы → секции анкеты; секции показываются как факт-сетки, текстовые поля — абзацами */
  const GROUPS = [
    { id: 'family', title: 'Портрет клиента и быт', icon: 'users', secs: ['family'], narrative: true },
    { id: 'style', title: 'Стиль и атмосфера', icon: 'sparkles', secs: ['styleVotes', 'styleDetails'] },
    { id: 'color', title: 'Цвет и материалы', icon: 'palette', secs: ['color'] },
    { id: 'refs', title: 'Референсы', icon: 'image', secs: ['references'], gallery: 'references' },
    { id: 'anti', title: 'Антипримеры — чего избегаем', icon: 'ban', secs: ['anti'], gallery: 'antiReferences' },
    { id: 'layout', title: 'Планировка, функции, кухня', icon: 'layout-grid', secs: ['layout', 'kitchen'] },
    { id: 'rooms', title: 'Помещения', icon: 'door-open', secs: ['rooms'] },
    { id: 'eng', title: 'Инженерия, свет, климат', icon: 'zap', secs: ['engineering'] },
    { id: 'furn', title: 'Мебель, техника, хранение', icon: 'armchair', secs: ['furniture'] },
    { id: 'budget', title: 'Бюджет, сроки, состав ДП', icon: 'wallet', secs: ['budget'] },
  ];
  const isLong = (f) => f.type === 'textarea' || f.type === 'url_list';

  /* ── Markdown для AI / буфера обмена ── */
  function markdown(schema, responses, intake, opts) {
    const r = responses || {}; const it = intake || {}; const o = opts || {};
    const lines = [];
    lines.push('# Бриф на дизайн-проект' + (o.dealId ? ' · ' + o.dealId : ''));
    lines.push('');
    lines.push('**Клиент:** ' + (it.clientName || '—'));
    objectFacts(it).forEach(([k, v]) => lines.push('**' + k + ':** ' + v));
    lines.push('');
    GROUPS.forEach((g) => {
      const parts = [];
      g.secs.forEach((sid) => {
        const sec = secById(schema, sid); if (!sec) return;
        if (sec.kind === 'style_cards') {
          const v = r[sec.id] || {}; const cards = sec.cards || [];
          const like = cards.filter((c) => v[c.id] === 'like').map((c) => c.title + (c.sub ? ' (' + c.sub + ')' : ''));
          const dis = cards.filter((c) => v[c.id] === 'dislike').map((c) => c.title);
          const un = cards.filter((c) => v[c.id] === 'unsure').map((c) => c.title);
          if (like.length) parts.push('- Нравится: ' + like.join(', '));
          if (un.length) parts.push('- Сомневаются: ' + un.join(', '));
          if (dis.length) parts.push('- Не нравится: ' + dis.join(', '));
        } else if (sec.kind === 'room_group') {
          (Array.isArray(r[sec.id]) ? r[sec.id] : []).filter((x) => x && x.name).forEach((x) => {
            parts.push('- ' + x.name + (x.priority ? ' — приоритет ' + (L.prio[x.priority] || x.priority) : '') + (x.mood && x.mood.length ? ' · ' + x.mood.join(', ') : '') + (x.note ? ' · ' + x.note : ''));
          });
        } else {
          (sec.fields || []).forEach((f) => {
            if (!visible(f, r)) return;
            if (f.id === 'referenceUrls' || f.id === 'antiUrls') return;
            const v = fieldValue(f, r); if (v == null) return;
            if (f.type === 'media') { parts.push('- ' + f.label + ': ' + v.length + ' фото'); return; }
            parts.push('- ' + f.label + ': ' + txt(v));
          });
        }
      });
      if (g.gallery) {
        const refs = it[g.gallery] || [];
        refs.filter((x) => x.url).forEach((x) => parts.push('- Ссылка: ' + x.url));
        const im = refs.filter((x) => x.imageUrl).length; if (im) parts.push('- Картинок: ' + im);
      }
      if (parts.length) { lines.push('## ' + g.title); lines.push(...parts); lines.push(''); }
    });
    const notes = [];
    (schema.sections || []).forEach((sec) => (sec.fields || []).forEach((f) => { if (isLong(f) && f.type === 'textarea' && visible(f, r) && isFilled(r[f.id]) && !lines.some((l) => l.startsWith('- ' + f.label + ':'))) notes.push('- ' + f.label + ': ' + r[f.id]); }));
    if (notes.length) { lines.push('## Комментарии'); lines.push(...notes); lines.push(''); }
    return lines.join('\n');
  }
  function aiPrompt(schema, responses, intake, opts) {
    return [
      'Ты — интерьерный дизайнер с опытом работы с частными заказчиками в России. Ниже — структурированный бриф клиента на дизайн-проект.',
      'Задача: (1) предложи 3 стилевых направления, которые лучше всего отвечают брифу — название, суть, почему подходит именно этой семье;',
      '(2) для каждого — палитра (5–6 цветов с HEX), ключевые материалы полов/стен/фасадов, свет, 3–5 характерных приёмов;',
      '(3) отметь противоречия и пробелы в брифе и сформулируй до 7 вопросов клиенту; (4) учти антипримеры — чего избегать.',
      'Отвечай по-русски, структурированно, без воды.',
      '',
      markdown(schema, responses, intake, opts),
    ].join('\n');
  }

  /* ── компонент презентации ── */
  function Chips({ items, tone }) { return <span className={'dpv-chips' + (tone ? ' dpv-chips--' + tone : '')}>{items.map((x, i) => <span key={i} className="dpv-chip">{x}</span>)}</span>; }
  function Fact({ label, value }) {
    if (value == null || value === '') return null;
    return <div className="dpv-fact"><span className="dpv-fact-l">{label}</span><span className="dpv-fact-v">{Array.isArray(value) ? <Chips items={value} /> : value}</span></div>;
  }
  function FieldsFacts({ sec, r, skip }) {
    const facts = []; const longs = [];
    (sec.fields || []).forEach((f) => {
      if (!visible(f, r) || (skip && skip.includes(f.id))) return;
      const v = fieldValue(f, r); if (v == null) return;
      if (f.type === 'media') { longs.push(<div key={f.id} className="dpv-long"><div className="dpv-long-l">{f.label}</div><div className="dpv-gallery dpv-gallery--sm">{v.map((u, i) => <a key={i} href={u} target="_blank" rel="noreferrer" className="dpv-img" style={{ backgroundImage: 'url(' + u + ')' }} />)}</div></div>); return; }
      if (isLong(f)) { longs.push(<div key={f.id} className="dpv-long"><div className="dpv-long-l">{f.label}</div><p>{txt(v)}</p></div>); return; }
      facts.push(<Fact key={f.id} label={f.label} value={v} />);
    });
    if (!facts.length && !longs.length) return null;
    return <React.Fragment>{facts.length > 0 && <div className="dpv-facts">{facts}</div>}{longs}</React.Fragment>;
  }
  function StyleBlock({ sec, r }) {
    const M = Mock(); const v = r[sec.id] || {}; const cards = sec.cards || [];
    const img = (c) => (M && M.cardImages ? M.cardImages(c) : c.images || []);
    const like = cards.filter((c) => v[c.id] === 'like'); const dis = cards.filter((c) => v[c.id] === 'dislike'); const un = cards.filter((c) => v[c.id] === 'unsure');
    if (!like.length && !dis.length && !un.length) return <p className="dpv-muted">Стиль по карточкам не отмечен.</p>;
    return (
      <React.Fragment>
        {like.length > 0 && <div className="dpv-styles">{like.map((c) => <figure key={c.id} className="dpv-style"><div className="dpv-style-imgs">{img(c).slice(0, 2).map((u, i) => <span key={i} className="dpv-img" style={{ backgroundImage: 'url(' + u + ')' }} />)}</div><figcaption><b>{c.title}</b>{c.sub && <span>{c.sub}</span>}</figcaption></figure>)}</div>}
        <div className="dpv-facts">
          {un.length > 0 && <Fact label="Сомневаются" value={un.map((c) => c.title)} />}
          {dis.length > 0 && <Fact label="Не нравится" value={dis.map((c) => c.title)} />}
        </div>
      </React.Fragment>
    );
  }
  function RoomsBlock({ sec, r, intake }) {
    const rooms = (Array.isArray(r[sec.id]) ? r[sec.id] : []).filter((x) => x && x.name);
    if (!rooms.length) return <p className="dpv-muted">Помещения не описаны.</p>;
    const meas = (intake && intake.rooms) || [];
    const areaOf = (nm) => { const m = meas.find((x) => (x.name || '').toLowerCase() === nm.toLowerCase()); return m && m.areaFloorM2 ? Math.round(m.areaFloorM2 * 10) / 10 + ' м²' : ''; };
    const tone = { high: 'danger', medium: 'warning', low: 'neutral' };
    return (
      <div className="dpv-rooms">
        {rooms.map((x) => (
          <div key={x.id || x.name} className="dpv-room">
            <div className="dpv-room-h"><b>{x.name}</b>{areaOf(x.name) && <span className="t-num dpv-muted">{areaOf(x.name)}</span>}{x.priority && <Badge tone={tone[x.priority] || 'neutral'} dot>{L.prio[x.priority] || x.priority}</Badge>}</div>
            {x.mood && x.mood.length > 0 && <Chips items={x.mood} />}
            {x.note && <p>{x.note}</p>}
          </div>
        ))}
      </div>
    );
  }
  function Gallery({ refs }) {
    const images = (refs || []).filter((x) => x.imageUrl); const links = (refs || []).filter((x) => !x.imageUrl && x.url);
    if (!images.length && !links.length) return null;
    return (
      <React.Fragment>
        {images.length > 0 && <div className="dpv-gallery">{images.map((x) => <a key={x.id} href={x.imageUrl} target="_blank" rel="noreferrer" className="dpv-img" style={{ backgroundImage: 'url(' + x.imageUrl + ')' }} title={x.title || ''} />)}</div>}
        {links.length > 0 && <ul className="dpv-links">{links.map((x) => <li key={x.id}><a href={x.url} target="_blank" rel="noreferrer"><Ic n="external-link" s={12} />{x.title || x.url}</a> <span className="dpv-muted">{x.url}</span></li>)}</ul>}
      </React.Fragment>
    );
  }

  function DpBriefView({ dealId, intake, inst, schema, responses, who, print, onEdit, onApprove, onClose, onShowForm }) {
    const r = responses || {}; const it = intake || {};
    const [copied, setCopied] = useState(false);
    const state = inst ? inst.accessState : '';
    const facts = objectFacts(it);
    const narrative = familyNarrative(schema, r);
    const liked = (() => { const s = secById(schema, 'styleVotes'); if (!s) return []; const v = r[s.id] || {}; return (s.cards || []).filter((c) => v[c.id] === 'like').map((c) => c.title); })();
    const key = [
      ['Стиль', liked.join(', ')],
      ['Атмосфера', txt(val(schema, r, 'styleDetails', 'atmosphere'))],
      ['Бюджет отделки', txt(val(schema, r, 'budget', 'budgetFinish'))],
      ['Бюджет мебели', txt(val(schema, r, 'budget', 'budgetFurniture'))],
      ['Концепция', txt(val(schema, r, 'budget', 'conceptDeadline'))],
      ['Важнее всего', txt(val(schema, r, 'budget', 'priorities'))],
      ['Состав ДП', txt(val(schema, r, 'budget', 'dpScope'))],
    ].filter(([, v]) => v);
    const md = () => markdown(schema, r, it, { dealId });
    const copyAi = () => { try { const pr = navigator.clipboard.writeText(aiPrompt(schema, r, it, { dealId })); if (pr && pr.catch) pr.catch(() => {}); } catch (e) {} setCopied(true); setTimeout(() => setCopied(false), 1800); };
    const pdf = () => { try { const u = new URL('brief-print.html', window.location.href); u.searchParams.set('deal', dealId); if (inst && inst.linkToken) u.searchParams.set('t', inst.linkToken); u.searchParams.set('print', '1'); window.open(u.toString(), '_blank'); } catch (e) {} };
    const isClient = who === 'client';
    const stMap = { submitted: ['отправлен · ждёт согласования', 'warning'], approved: ['согласован', 'success'], in_progress: ['заполняется', 'info'], active: ['ссылка у клиента', 'info'], pending: ['не начат', 'neutral'] };
    const st = stMap[state] || [state, 'neutral'];
    const toc = GROUPS.filter((g) => g.secs.some((sid) => { const s = secById(schema, sid); if (!s) return false; if (s.kind === 'style_cards') return Object.values(r[s.id] || {}).some(Boolean); if (s.kind === 'room_group') return (r[s.id] || []).some((x) => x && x.name); return (s.fields || []).some((f) => visible(f, r) && fieldValue(f, r) != null); }) || (g.gallery && (it[g.gallery] || []).length));
    return (
      <div className={'dpv' + (print ? ' dpv--print' : '')}>
        {!print && (
          <aside className="dpv-side">
            <div className="dpv-side-card">
              <div className="dpv-side-t">Экспорт</div>
              <Button variant="accent" size="md" className="dpv-side-btn" iconLeft={<Ic n="file-down" s={14} />} onClick={pdf}>PDF для AI</Button>
              <Button variant="secondary" size="md" className="dpv-side-btn" iconLeft={<Ic n={copied ? 'check' : 'copy'} s={14} />} onClick={copyAi}>{copied ? 'Скопировано' : 'Скопировать для AI'}</Button>
              <div className="dpv-side-hint">PDF открывается в новой вкладке с диалогом печати — сохраните как PDF и загрузите в AI. Текст для AI уже содержит задание: подобрать 3 стилевых направления.</div>
            </div>
            {!isClient && (
              <div className="dpv-side-card">
                <div className="dpv-side-t">Действия</div>
                {state === 'submitted' && onApprove && <Button variant="accent" size="md" className="dpv-side-btn" iconLeft={<Ic n="check" s={14} />} onClick={onApprove}>Согласовать бриф</Button>}
                {onEdit && <Button variant="secondary" size="md" className="dpv-side-btn" iconLeft={<Ic n="pencil" s={14} />} onClick={onEdit}>Редактировать</Button>}
                {onShowForm && <Button variant="ghost" size="md" className="dpv-side-btn" iconLeft={<Ic n="list" s={14} />} onClick={onShowForm}>Показать анкету</Button>}
                {onClose && <Button variant="ghost" size="md" className="dpv-side-btn" onClick={onClose}>Закрыть</Button>}
                {onEdit && <div className="dpv-side-hint">«Редактировать» переоткрывает анкету — ссылка клиента снова активна до повторной отправки.</div>}
              </div>
            )}
            {isClient && onClose && <div className="dpv-side-card"><Button variant="ghost" size="md" className="dpv-side-btn" onClick={onClose}>Закрыть</Button></div>}
            <nav className="dpv-toc">
              {toc.map((g) => <a key={g.id} href={'#dpv-' + g.id} onClick={(e) => { e.preventDefault(); const el = document.getElementById('dpv-' + g.id); if (el) el.scrollIntoView({ behavior: 'smooth', block: 'start' }); }}><Ic n={g.icon} s={13} />{g.title}</a>)}
            </nav>
          </aside>
        )}
        <article className="dpv-doc">
          <header className="dpv-hero">
            <div className="dpv-eyebrow">Бриф на дизайн-проект · {dealId}{inst && inst.approvedAt ? ' · согласован ' + fmtDate(inst.approvedAt) : inst && inst.submittedAt ? ' · отправлен ' + fmtDate(inst.submittedAt) : ''}</div>
            <div className="dpv-hero-row">
              <h1>{it.clientName || 'Клиент'}</h1>
              {!print && <Badge tone={st[1]} dot>{st[0]}</Badge>}
            </div>
            <p className="dpv-lede">{facts.filter(([k]) => k === 'Адрес' || k === 'Объект' || k === 'Площадь' || k === 'Комнат · санузлов · уровней').map(([, v]) => v).join(' · ')}</p>
            {key.length > 0 && <div className="dpv-key">{key.map(([k, v]) => <div key={k} className="dpv-key-it"><span>{k}</span><b>{v}</b></div>)}</div>}
            {facts.length > 0 && <div className="dpv-facts dpv-facts--obj">{facts.map(([k, v]) => <Fact key={k} label={k} value={v} />)}</div>}
          </header>
          {GROUPS.map((g) => {
            const secs = g.secs.map((sid) => secById(schema, sid)).filter(Boolean);
            const refs = g.gallery ? (it[g.gallery] || []) : [];
            const body = [];
            secs.forEach((sec) => {
              if (sec.kind === 'style_cards') body.push(<StyleBlock key={sec.id} sec={sec} r={r} />);
              else if (sec.kind === 'room_group') body.push(<RoomsBlock key={sec.id} sec={sec} r={r} intake={it} />);
              else { const node = <FieldsFacts key={sec.id || sec.title} sec={sec} r={r} skip={['referenceUrls', 'antiUrls']} />; body.push(node); }
            });
            if (refs.length) body.push(<Gallery key="g" refs={refs} />);
            const hasContent = toc.some((x) => x.id === g.id);
            if (!hasContent) return null;
            return (
              <section key={g.id} id={'dpv-' + g.id} className="dpv-sec">
                <h2><span className="dpv-sec-ic"><Ic n={g.icon} s={16} /></span>{g.title}</h2>
                {g.narrative && narrative && <p className="dpv-narrative">{narrative}</p>}
                {body}
              </section>
            );
          })}
          <section className="dpv-sec dpv-sec--ai" id="dpv-ai">
            <h2><span className="dpv-sec-ic"><Ic n="bot" s={16} /></span>Задание для AI</h2>
            <p className="dpv-muted">Этот текст добавляется в PDF и в буфер обмена вместе с брифом — вставьте в ChatGPT / Claude / другой AI, чтобы получить стилевые направления.</p>
            <pre className="dpv-pre">{aiPrompt(schema, r, it, { dealId }).split('\n').slice(0, 5).join('\n')}</pre>
          </section>
        </article>
      </div>
    );
  }

  window.DpBriefView = DpBriefView;
  window.DpBriefExport = { markdown, aiPrompt, objectFacts, familyNarrative, GROUPS };
})();
