/* site-intake-readonly.jsx — вкладки карточки объекта в калькуляторе (spec §2.2, §2.8).
   Read-only для большинства ролей; inline-edit для manager/super (объект, замер, анкета)
   и designer (бриф на вкладке ДП). */
(function () {
  const { Badge } = window.DesignSystem_9e0a09;
  const { Ic } = window;
  const { useState, useEffect, useRef } = React;
  const R = window.CalcIntakeReadiness;

  const TABS = [
    ['basic', 'Основное'],
    ['measure', 'Замер'],
    ['wishes', 'Пожелания'],
    ['dp', 'Дизайн-проект'],
    ['docs', 'Документы'],
  ];

  const OBJ_TYPES = [['new_build', 'Новостройка'], ['secondary', 'Вторичка']];
  const HOUSING = [['apartment', 'Квартира'], ['house', 'Дом'], ['commercial', 'Коммерция']];
  const FINISH = [['without', 'Без отделки'], ['partial', 'Черновая'], ['renovation', 'С ремонтом']];
  const REPAIR = [['cosmetic', 'Косметический'], ['capital', 'Капитальный']];
  const TIERS = [['economy', 'Эконом'], ['mid', 'Комфорт'], ['premium', 'Премиум']];
  const WISH_OPTS = {
    material: ['Плитка крупный формат', 'Ламинат 33 класс', 'Паркет', 'Микроцемент', 'Керамогранит'],
    plumbing: ['Скрытые смесители', 'Инсталляция', 'Душ без поддона', 'Тёплый пол в СУ'],
    electrical: ['Умный дом', 'Больше розеток', 'Сценарное освещение', 'Тёплый пол'],
    lighting: ['Тёплый свет', 'Нейтральный', 'Холодный', 'Люстра', 'Треки'],
  };

  const BRIEF_STYLES = ['Минимализм', 'Тёплый сканди', 'Современная классика', 'Лофт', 'Япанди'];
  const BRIEF_COLORS = ['Тёплые нейтрали', 'Светлые тона', 'Тёмные акценты', 'Натуральное дерево', 'Монохром', 'Без глянца'];
  const BRIEF_BUDGET = ['до 800 тыс', '800 тыс – 1.2 млн', '1.2–1.6 млн', '1.6–2.2 млн', 'от 2.2 млн'];
  const BRIEF_FURNITURE = [['built_in', 'Встроенная'], ['own', 'Своя'], ['mixed', 'Смешанная']];
  const BRIEF_FURNITURE_MAP = Object.fromEntries(BRIEF_FURNITURE);

  const DP_STATUS = window.DesignProjectMock?.STATUS_LABEL || {
    draft: 'Черновик', client_review: 'На согласовании', client_approved: 'Утверждён клиентом',
    revision: 'На доработке', archived: 'Архив', superseded: 'Заменён',
  };
  const PAGE_TYPES = window.DesignProjectMock?.PAGE_TYPE_LABEL || { work_instruction: 'Инструкция' };
  const fmtDate = (iso) => (window.DesignProjectMock?.formatDate(iso) || (iso ? iso.slice(0, 10) : null));
  const f1 = (n) => (Math.round(n * 10) / 10).toFixed(1);

  function intakePerms(role) {
    const mgr = role === 'manager' || role === 'super';
    const designer = role === 'designer';
    const client = role === 'client';
    return {
      editBasic: mgr,
      editMeasure: mgr,
      editWishes: mgr,
      editBrief: mgr || designer,
      editMediaMeta: mgr,
      hideClientInternals: client,
    };
  }

  function tabCanEdit(tab, perms, dpMeta) {
    if (tab === 'basic') return perms.editBasic;
    if (tab === 'measure') return perms.editMeasure;
    if (tab === 'wishes') return perms.editWishes;
    if (tab === 'dp') return canEditDpBrief(perms.editBrief, dpMeta);
    if (tab === 'media') return perms.editMediaMeta;
    return false;
  }

  function tabIsLocked(tab, dpMeta) {
    if (tab !== 'dp') return false;
    return !canEditDpBrief(true, dpMeta);
  }

  /** Бриф редактируется только до согласования ДП с клиентом. */
  function canEditDpBrief(rolePerm, dpMeta) {
    if (!rolePerm) return false;
    if (!dpMeta || !dpMeta.status) return true;
    return !['client_approved', 'client_review', 'archived', 'superseded'].includes(dpMeta.status);
  }

  function Field({ label, value }) {
    if (value == null || value === '') return null;
    return (
      <div className="cc-ir-field">
        <span className="cc-ir-field-l">{label}</span>
        <span className="cc-ir-field-v">{value}</span>
      </div>
    );
  }

  function EditableField({ label, value, onChange, edit, type = 'text', placeholder }) {
    return (
      <div className="cc-ir-field">
        <span className="cc-ir-field-l">{label}</span>
        {edit ? (
          <input
            className="cc-ir-input"
            type={type}
            value={value ?? ''}
            placeholder={placeholder}
            onChange={(e) => onChange(type === 'number' ? (+e.target.value || 0) : e.target.value)}
          />
        ) : (
          <span className="cc-ir-field-v">{value != null && value !== '' ? value : '—'}</span>
        )}
      </div>
    );
  }

  function EditableTextarea({ label, value, onChange, edit, rows = 3, placeholder }) {
    return (
      <div className="cc-ir-field">
        <span className="cc-ir-field-l">{label}</span>
        {edit ? (
          <textarea className="cc-ir-input cc-ir-textarea" rows={rows} value={value || ''} placeholder={placeholder}
            onChange={(e) => onChange(e.target.value)} />
        ) : value ? (
          <p className="cc-ir-note-text">{value}</p>
        ) : (
          <span className="cc-ir-muted">—</span>
        )}
      </div>
    );
  }

  function ChipRow({ label, options, value, onChange, edit }) {
    const cur = value || (options[0] && options[0][0]);
    return (
      <div className="cc-ir-field">
        <span className="cc-ir-field-l">{label}</span>
        {edit ? (
          <div className="cc-ir-chip-row">
            {options.map(([k, l]) => (
              <button key={k} type="button" className={'cc-ir-chip-btn' + (cur === k ? ' on' : '')} onClick={() => onChange(k)}>{l}</button>
            ))}
          </div>
        ) : (
          <span className="cc-ir-field-v">{options.find(([k]) => k === cur)?.[1] || cur || '—'}</span>
        )}
      </div>
    );
  }

  function MultiChipPicker({ label, options, value, onChange, edit }) {
    const sel = value || [];
    const toggle = (opt) => {
      const next = sel.includes(opt) ? sel.filter((x) => x !== opt) : [...sel, opt];
      onChange(next);
    };
    return (
      <div className="cc-ir-field">
        <span className="cc-ir-field-l">{label}</span>
        {edit ? (
          <div className="cc-ir-chip-row">
            {options.map((opt) => (
              <button key={opt} type="button" className={'cc-ir-chip-btn' + (sel.includes(opt) ? ' on' : '')} onClick={() => toggle(opt)}>{opt}</button>
            ))}
          </div>
        ) : (
          <ChipList items={sel} />
        )}
      </div>
    );
  }

  function ChipList({ items }) {
    if (!items || !items.length) return <span className="cc-ir-muted">—</span>;
    return (
      <div className="cc-ir-chips">
        {items.map((x) => <span key={x} className="cc-ir-chip">{x}</span>)}
      </div>
    );
  }

  function EmptyCard({ title, text }) {
    return (
      <div className="cc-ir-empty">
        <Ic n="info" s={18} c="var(--text-tertiary)" />
        <div className="cc-ir-empty-t">{title}</div>
        <div className="cc-ir-empty-s">{text}</div>
      </div>
    );
  }

  function EditBanner({ show }) {
    if (!show) return null;
    return (
      <div className="cc-ir-edit-banner" role="status">
        <Ic n="pencil" s={14} c="var(--primary)" />
        <span>Редактирование доступно — изменения сохраняются автоматически</span>
      </div>
    );
  }

  function areaDisplay(intake) {
    const d = R.deriveArea(intake);
    if (d.source === 'measured') return `${d.value} м² · по замеру`;
    if (d.source === 'approx') return `≈ ${d.value} м² · ориентир клиента`;
    return 'Не указана';
  }

  function BasicTab({ intake, readiness, edit, patch, hideInternal }) {
    const tier = R.finishTierLabel(intake);
    const setPrefs = (k, v) => patch({ prefs: { ...intake.prefs, [k]: v } });
    return (
      <div className="cc-ir-bento">
        <div className="cc-ir-card">
          <div className="cc-ir-card-h">Клиент</div>
          <EditableField label="ФИО" value={intake.clientName} edit={edit} onChange={(v) => patch({ clientName: v })} />
          {!hideInternal && (
            <EditableField label="Телефон" value={intake.clientPhone} edit={edit} onChange={(v) => patch({ clientPhone: v })} />
          )}
        </div>
        <div className="cc-ir-card">
          <div className="cc-ir-card-h">Объект</div>
          <EditableField label="Адрес" value={intake.address} edit={edit} onChange={(v) => patch({ address: v })} />
          <ChipRow label="Жильё" options={HOUSING} value={intake.housingType} edit={edit} onChange={(v) => patch({ housingType: v })} />
          <ChipRow label="Тип объекта" options={OBJ_TYPES} value={intake.objectType} edit={edit} onChange={(v) => patch({ objectType: v })} />
          <ChipRow label="Отделка" options={FINISH} value={intake.finishState} edit={edit} onChange={(v) => patch({ finishState: v })} />
          {edit && (
            <EditableField label="Площадь-ориентир" type="number" value={intake.areaApprox} edit edit placeholder="м²"
              onChange={(v) => patch({ areaApprox: v })} />
          )}
        </div>
        <div className="cc-ir-card">
          <div className="cc-ir-card-h">Ремонт</div>
          <ChipRow label="Тип ремонта" options={REPAIR} value={intake.repairType || 'capital'} edit={edit} onChange={(v) => patch({ repairType: v })} />
          {edit ? (
            <label className="cc-ir-check">
              <input type="checkbox" checked={!!intake.requiresDesign} onChange={(e) => patch({ requiresDesign: e.target.checked })} />
              <span>Нужен дизайн-проект</span>
            </label>
          ) : (
            <Field label="Дизайн-проект" value={intake.requiresDesign ? 'Нужен' : 'Не нужен'} />
          )}
          {edit ? (
            <ChipRow label="Уровень отделки" options={TIERS} value={intake.prefs?.finishTier} edit
              onChange={(v) => setPrefs('finishTier', v)} />
          ) : (
            <Field label="Уровень отделки" value={tier} />
          )}
        </div>
        <div className="cc-ir-card">
          <div className="cc-ir-card-h">Площадь и готовность</div>
          <Field label="Площадь для расчёта" value={areaDisplay(intake)} />
          {!hideInternal && readiness && (
            <>
              <div className="cc-ir-readiness-total">
                <span className="cc-ir-readiness-total-l">Готовность объекта</span>
                <strong className="t-num">{readiness.total}%</strong>
              </div>
              <div className="cc-ir-readiness-stack">
                {(readiness.groups || []).filter((g) => !g.na).map((g) => (
                  <div key={g.key} className="cc-ir-readiness-row">
                    <div className="cc-ir-readiness-row-h">
                      <span>{g.label}</span>
                      <span className="t-num">{g.value}%</span>
                    </div>
                    <div className="cc-ir-bar"><span style={{ width: g.value + '%' }} /></div>
                  </div>
                ))}
              </div>
            </>
          )}
        </div>
      </div>
    );
  }

  function MeasureTab({ intake, dealId, edit, patch }) {
    const rooms = intake.rooms || [];
    const media = resolveIntakeMedia(intake, dealId);
    if (!edit && !intake.measurementDate && !rooms.length && !intake.preferredMeasureDate) {
      return <EmptyCard title="Замер не начат" text="Данные замера появятся после назначения даты и заполнения формы замерщиком или анкеты клиента." />;
    }
    const derived = R.deriveArea(intake);
    const windows = rooms.reduce((a, r) => a + (r.openings || []).filter((o) => o.kind === 'window').length, 0);
    const doors = rooms.reduce((a, r) => a + (r.openings || []).filter((o) => o.kind === 'door').length, 0);
    const photos = media.filter((m) => m.kind !== 'video').length;
    const videos = media.filter((m) => m.kind === 'video').length;

    const setRoom = (id, p) => patch({ rooms: rooms.map((r) => (r.id === id ? { ...r, ...p } : r)) });
    const addRoom = () => {
      const id = 'r' + Math.random().toString(36).slice(2, 6);
      patch({
        rooms: [...rooms, {
          id, name: 'Комната ' + (rooms.length + 1), openings: [], engineering: { sockets: 0, switches: 0, water: 0, sewer: 0, vent: false, radiators: 0, panelPhoto: false }, photos: {},
        }],
        measurementDate: intake.measurementDate || new Date().toISOString().slice(0, 10),
      });
    };

    const roomMedia = (rid) => media.filter((m) => m.room === rid);

    return (
      <div>
        {(intake.clientForms?.measurePrep) && (
          <div className="cc-ir-form-status">
            <Badge tone={intake.clientForms.measurePrep.status === 'submitted' ? 'success' : 'info'} dot>
              Анкета клиента · замер · {intake.clientForms.measurePrep.progress || 0}%
            </Badge>
            {intake.clientForms.measurePrep.lastSavedAt && (
              <span className="cc-ir-muted t-num">обновлено {intake.clientForms.measurePrep.lastSavedAt.slice(11, 16)}</span>
            )}
          </div>
        )}
        <div className="cc-ir-measure-summary cc-ir-grid-adaptive">
          {edit ? (
            <>
              <EditableField label="Дата" type="date" value={intake.measurementDate} edit onChange={(v) => patch({ measurementDate: v })} />
              <EditableField label="Замерщик" value={intake.measuredBy} edit onChange={(v) => patch({ measuredBy: v })} />
            </>
          ) : (
            <>
              <Field label="Дата" value={intake.measurementDate} />
              <Field label="Замерщик" value={intake.measuredBy} />
            </>
          )}
          <Field label="Желаемая дата" value={intake.preferredMeasureDate} />
          <Field label="Контакт на объекте" value={intake.onSiteContact} />
          <Field label="Площадь" value={derived.value ? `${derived.value} м²` : '—'} />
          <Field label="Помещений" value={String(rooms.length)} />
          <Field label="Окна / двери" value={windows + ' / ' + doors} />
          <Field label="Фото / видео" value={photos + ' / ' + videos} />
          <Field label="Этаж" value={intake.floor} />
          <Field label="Лифт" value={intake.hasElevator ? 'Есть' : intake.hasElevator === false ? 'Нет' : null} />
          <Field label="Доступ" value={intake.accessNote || (intake.accessTags || []).join(', ')} />
        </div>
        {edit && rooms.length === 0 && (
          <div className="cc-ir-measure-start">
            <button type="button" className="cc-ir-btn" onClick={addRoom}><Ic n="plus" s={14} />Начать замер</button>
          </div>
        )}
        <div className="cc-ir-rooms cc-ir-rooms-grid">
          {rooms.map((r) => {
            const L = +r.lengthM || 0, W = +r.widthM || 0;
            const rMedia = roomMedia(r.id);
            return (
              <div key={r.id} className="cc-ir-room cc-ir-room-media">
                {edit ? (
                  <>
                    <input className="cc-ir-input cc-ir-room-name-in" value={r.name} onChange={(e) => setRoom(r.id, { name: e.target.value })} />
                    <div className="cc-ir-room-dims">
                      {['lengthM', 'widthM', 'heightM'].map((k, i) => (
                        <label key={k} className="cc-ir-dim">
                          <span>{['Д', 'Ш', 'В'][i]}</span>
                          <input type="number" step="0.05" value={r[k] || ''} onChange={(e) => setRoom(r.id, { [k]: +e.target.value })} />
                        </label>
                      ))}
                    </div>
                    <span className="cc-ir-room-m t-num">{L && W ? f1(L * W) + ' м²' : 'геометрия неполная'}</span>
                  </>
                ) : (
                  <>
                    <span className="cc-ir-room-n">{r.name}</span>
                    <span className="cc-ir-room-m t-num">{L && W ? f1(L * W) + ' м² · ' + L + '×' + W + '×' + (r.heightM || '—') : 'геометрия неполная'}</span>
                    <span className="cc-ir-room-o t-num">{(r.openings || []).length} проёмов</span>
                  </>
                )}
                {rMedia.length > 0 && (
                  <div className="cc-ir-room-media-strip">
                    <span className="cc-ir-room-media-label">Фото и видео · {rMedia.length}</span>
                    <div className="cc-ir-room-media-grid">
                      {rMedia.map((m, index) => (
                        <div key={m.id} className="cc-ir-room-media-cell" style={mediaThumbStyle(m, index)} title={m.label}>
                          {m.kind === 'video' && <span className="cc-ir-media-play" aria-hidden="true"><Ic n="play" s={12} /></span>}
                        </div>
                      ))}
                    </div>
                  </div>
                )}
              </div>
            );
          })}
        </div>
        {edit && rooms.length > 0 && (
          <button type="button" className="cc-ir-btn ghost" onClick={addRoom}><Ic n="plus" s={14} />Добавить помещение</button>
        )}
      </div>
    );
  }

  function WishCard({ title, children }) {
    return (
      <div className="cc-ir-card cc-ir-wish-card">
        <div className="cc-ir-card-h">{title}</div>
        {children}
      </div>
    );
  }

  function WishesTab({ intake, dealId, edit, patch }) {
    const p = intake.prefs || {};
    const references = resolveIntakeReferences(intake, dealId);
    const [refLightbox, setRefLightbox] = useState(null);
    const hasContent = p.sent || p.finishTier || p.freeText || references.length;
    if (!edit && !hasContent) {
      return <EmptyCard title="Анкета не заполнена" text="Пожелания клиента появятся после отправки или заполнения анкеты в CRM." />;
    }
    const setP = (k, v) => patch({ prefs: { ...p, [k]: v } });
    const tier = R.finishTierLabel(intake);
    const chipGroups = [
      { key: 'material', title: 'Материалы' },
      { key: 'plumbing', title: 'Сантехника' },
      { key: 'electrical', title: 'Электрика' },
      { key: 'lighting', title: 'Освещение' },
    ];
    const hasNotes = edit || p.deadlineNote || p.logisticsNote || p.freeText;
    return (
      <div className="cc-ir-wishes">
        {(intake.clientForms?.measurePrep || intake.clientForms?.dpPrefs) && (
          <div className="cc-ir-form-status">
            {intake.clientForms.measurePrep && (
              <Badge tone={intake.clientForms.measurePrep.status === 'submitted' ? 'success' : 'info'} dot>
                Анкета · замер · {intake.clientForms.measurePrep.progress || 0}%
              </Badge>
            )}
            {intake.clientForms.dpPrefs && intake.requiresDesign && (
              <Badge tone={intake.clientForms.dpPrefs.status === 'submitted' ? 'success' : 'neutral'} dot>
                Анкета · ДП · {intake.clientForms.dpPrefs.progress || 0}%
              </Badge>
            )}
          </div>
        )}
        {(p.sent || edit) && (
          <div className="cc-ir-wishes-status">
            {edit ? (
              <label className="cc-ir-check">
                <input type="checkbox" checked={!!p.sent} onChange={(e) => setP('sent', e.target.checked)} />
                <span>Анкета отправлена / получена</span>
              </label>
            ) : p.sent ? (
              <Badge tone="success" dot>Анкета получена</Badge>
            ) : null}
          </div>
        )}
        <div className="cc-ir-wishes-grid">
          {(tier || edit) && (
            <WishCard title="Уровень отделки">
              {edit ? (
                <ChipRow label="" options={TIERS} value={p.finishTier} edit onChange={(v) => setP('finishTier', v)} />
              ) : (
                <ChipList items={[tier]} />
              )}
            </WishCard>
          )}
          {chipGroups.map((g) => (
            <WishCard key={g.key} title={g.title}>
              {edit ? (
                <MultiChipPicker label="" options={WISH_OPTS[g.key]} value={p[g.key]} edit onChange={(v) => setP(g.key, v)} />
              ) : (
                <ChipList items={p[g.key]} />
              )}
            </WishCard>
          ))}
        </div>
        {hasNotes && (
          <div className="cc-ir-wishes-notes">
            <div className="cc-ir-card">
              <div className="cc-ir-card-h">Сроки</div>
              <EditableTextarea label="" value={p.deadlineNote} edit={edit} rows={2} placeholder="Нужно к дате…"
                onChange={(v) => setP('deadlineNote', v)} />
            </div>
            <div className="cc-ir-card">
              <div className="cc-ir-card-h">Логистика</div>
              <EditableTextarea label="" value={p.logisticsNote} edit={edit} rows={2} placeholder="Лифт, парковка…"
                onChange={(v) => setP('logisticsNote', v)} />
            </div>
            <div className="cc-ir-card cc-ir-card-full">
              <div className="cc-ir-card-h">Комментарий</div>
              <EditableTextarea label="" value={p.freeText} edit={edit} rows={3} placeholder="Что важно / чего не хотим"
                onChange={(v) => setP('freeText', v)} />
            </div>
          </div>
        )}
        {references.length > 0 && (
          <section className="cc-ir-wishes-refs">
            <div className="cc-ir-wishes-refs-head">
              <h4 className="cc-ir-card-h">Референсы</h4>
              <span className="cc-ir-muted t-num">{references.length}</span>
            </div>
            <div className="cc-ir-dp-gallery-grid">
              {references.map((item, index) => (
                <button
                  key={item.id}
                  type="button"
                  className="cc-ir-dp-gallery-cell"
                  style={dpThumbStyle(item, index, 'refs')}
                  onClick={() => setRefLightbox(item)}
                  aria-label={'Открыть: ' + item.title}
                >
                  {item.source && (
                    <span className="cc-ir-dp-gallery-tag">{item.source}</span>
                  )}
                  <span className="cc-ir-dp-gallery-cap">{item.title}</span>
                </button>
              ))}
            </div>
            <DpLightbox
              item={refLightbox}
              items={references}
              intake={intake}
              kind="refs"
              onClose={() => setRefLightbox(null)}
              onChange={setRefLightbox}
            />
          </section>
        )}
      </div>
    );
  }

  function dpStatusTone(status) {
    return (window.DesignProjectMock?.STATUS_TONE || {})[status] || 'neutral';
  }

  function DpKv({ label, value }) {
    if (value == null || value === '') return null;
    return (
      <div className="cc-ir-dp-kv">
        <span className="cc-ir-dp-kv-l">{label}</span>
        <span className="cc-ir-dp-kv-v">{value}</span>
      </div>
    );
  }

  function BriefBlock({ intake, editBrief, patch, locked }) {
    const brief = intake.brief || {};
    const setBrief = (k, v) => patch({ brief: { ...brief, [k]: v } });
    const canEdit = editBrief && !locked;
    const colorLabel = (brief.colorPresets || []).join(', ') || brief.colors;

    if (canEdit) {
      return (
        <div className="cc-ir-dp-brief-edit">
          <MultiChipPicker label="Стиль" options={BRIEF_STYLES} value={brief.style} edit
            onChange={(v) => setBrief('style', v)} />
          <MultiChipPicker label="Цвета" options={BRIEF_COLORS} value={brief.colorPresets || (brief.colors ? [brief.colors] : [])} edit
            onChange={(v) => setBrief('colorPresets', v)} />
          <ChipRow label="Бюджет отделки" options={BRIEF_BUDGET.map((b) => [b, b])} value={brief.budgetFinish} edit
            onChange={(v) => setBrief('budgetFinish', v)} />
          <ChipRow label="Мебель" options={BRIEF_FURNITURE} value={brief.furnitureKey || 'built_in'} edit
            onChange={(v) => setBrief('furnitureKey', v)} />
        </div>
      );
    }

    return (
      <div className="cc-ir-dp-brief-col" aria-readonly="true">
        <DpKv label="Стиль" value={(brief.style || []).join(', ')} />
        <DpKv label="Цвета" value={colorLabel} />
        <DpKv label="Бюджет отделки" value={brief.budgetFinish} />
        <DpKv label="Мебель" value={BRIEF_FURNITURE_MAP[brief.furnitureKey] || brief.furniture} />
      </div>
    );
  }

  function DpBriefSection({ intake, canEditBrief, briefLocked, patch }) {
    const isLocked = briefLocked && !canEditBrief;
    return (
      <section className={'cc-ir-dp-section' + (isLocked ? ' cc-ir-dp-section-locked' : '')}>
        <h4 className="cc-ir-dp-label">Бриф</h4>
        <BriefBlock intake={intake} editBrief={canEditBrief} patch={patch} locked={briefLocked} />
      </section>
    );
  }

  const DP_THUMB_VIZ = [
    'linear-gradient(155deg, #ebe3d8 0%, #c9b8a4 42%, #8a7560 100%)',
    'linear-gradient(155deg, #f0ebe4 0%, #d4c4b0 40%, #9a8570 100%)',
    'linear-gradient(155deg, #e4eef0 0%, #b8cdd2 45%, #6e8a92 100%)',
    'linear-gradient(155deg, #ece8e2 0%, #c8bfb4 38%, #7d7268 100%)',
    'linear-gradient(155deg, #e8e4ef 0%, #c4bdd4 42%, #7a708a 100%)',
    'linear-gradient(155deg, #e2e2e2 0%, #b8b8b8 50%, #707070 100%)',
  ];
  const DP_THUMB_REF = [
    'linear-gradient(135deg, #f5ebe0 0%, #e8d5c4 55%, #c4a484 100%)',
    'linear-gradient(135deg, #e8f0f2 0%, #c5dce3 55%, #7fa8b5 100%)',
    'linear-gradient(135deg, #f0ece6 0%, #d9cfc0 55%, #a89478 100%)',
    'linear-gradient(135deg, #ece8f0 0%, #cfc5dc 55%, #9488a8 100%)',
  ];

  function dpThumbStyle(item, index, kind) {
    if (item.imageUrl) {
      return {
        backgroundImage: 'url(' + item.imageUrl + ')',
        backgroundSize: 'cover',
        backgroundPosition: 'center',
      };
    }
    const palette = kind === 'refs' ? DP_THUMB_REF : DP_THUMB_VIZ;
    const i = item.thumb != null ? item.thumb : index;
    return { background: palette[i % palette.length] };
  }

  function resolveDpAssets(dp) {
    const demo = window.DesignProjectMock?.demoAssets?.();
    const assets = dp?.assets || {};
    if (!demo) return assets;
    const gallery = (assets.gallery && assets.gallery.length) ? assets.gallery : demo.gallery;
    const useDemoGallery = gallery.length && !gallery[0]?.kind;
    return {
      ...demo,
      ...assets,
      gallery: useDemoGallery ? demo.gallery : gallery,
      videos: (assets.videos && assets.videos.length) ? assets.videos : (demo.videos || []),
      albumPdf: assets.albumPdf || demo.albumPdf,
      texturesPdf: assets.texturesPdf || demo.texturesPdf,
      specificationPdf: assets.specificationPdf || demo.specificationPdf,
    };
  }

  const MEDIA_THUMBS = [
    'linear-gradient(155deg, #ebe3d8 0%, #c9b8a4 42%, #8a7560 100%)',
    'linear-gradient(155deg, #e8eef2 0%, #b5c8d4 45%, #6a8494 100%)',
    'linear-gradient(155deg, #f0ebe4 0%, #d4c4b0 40%, #9a8570 100%)',
    'linear-gradient(155deg, #ece8e2 0%, #c8bfb4 38%, #7d7268 100%)',
    'linear-gradient(155deg, #e4eef0 0%, #b8cdd2 45%, #6e8a92 100%)',
    'linear-gradient(155deg, #e8e4ef 0%, #c4bdd4 42%, #7a708a 100%)',
    'linear-gradient(155deg, #f2ece4 0%, #d9cfc0 50%, #9a8878 100%)',
    'linear-gradient(155deg, #dfe8ec 0%, #a8bcc8 48%, #5a7484 100%)',
    'linear-gradient(155deg, #ece4dc 0%, #c9b8a8 45%, #887868 100%)',
    'linear-gradient(155deg, #e6e8f0 0%, #b8bdd0 48%, #707890 100%)',
    'linear-gradient(155deg, #eae6e0 0%, #ccc4b8 50%, #888078 100%)',
  ];

  function mediaThumbStyle(item, index) {
    if (item.imageUrl) {
      return {
        backgroundImage: 'url(' + item.imageUrl + ')',
        backgroundSize: 'cover',
        backgroundPosition: 'center',
      };
    }
    const i = item.thumb != null ? item.thumb : index;
    return { background: MEDIA_THUMBS[i % MEDIA_THUMBS.length] };
  }

  function resolveIntakeMedia(intake, dealId) {
    const media = intake?.media || [];
    if (media.length >= 8 && media.every((m) => m.kind)) return media;
    if (window.loadSiteIntake) {
      const fresh = window.loadSiteIntake(dealId || 'D-404');
      if (fresh?.media?.length) return fresh.media;
    }
    return media;
  }

  function resolveIntakeReferences(intake, dealId) {
    const refs = intake?.references || [];
    if (refs.length >= 4) return refs;
    if (window.loadSiteIntake) {
      const fresh = window.loadSiteIntake(dealId || 'D-404');
      if (fresh?.references?.length) return fresh.references;
    }
    return refs;
  }

  function DpGalleryBlock({ gallery, videos, intake, onOpen, approved, dpStatus, canUpload, onUploadVideo }) {
    const [mode, setMode] = useState('viz');
    const fileRef = useRef(null);
    const viz = gallery || [];
    const vids = videos || [];
    const items = mode === 'video' ? vids : viz;
    const kind = mode === 'video' ? 'video' : 'viz';

    const handleFile = (e) => {
      const file = e.target.files && e.target.files[0];
      e.target.value = '';
      if (file && onUploadVideo) onUploadVideo(file);
    };

    if (!approved) {
      return (
        <section className="cc-ir-dp-gallery-block">
          <div className="cc-ir-dp-gallery-head">
            <h4 className="cc-ir-dp-label">Галерея</h4>
          </div>
          {dpStatus === 'client_review' ? (
            <div className="cc-ir-dp-note">На согласовании. Галерея откроется после утверждения.</div>
          ) : (
            <div className="cc-ir-dp-gallery-empty">Галерея откроется после утверждения ДП</div>
          )}
        </section>
      );
    }

    return (
      <section className="cc-ir-dp-gallery-block">
        <div className="cc-ir-dp-gallery-head">
          <h4 className="cc-ir-dp-label">Галерея</h4>
          <div className="cc-ir-dp-seg" role="tablist" aria-label="Галерея">
            <button type="button" role="tab" aria-selected={mode === 'viz'} className={mode === 'viz' ? 'on' : ''}
              onClick={() => setMode('viz')}>Визуализации <span className="t-num">{viz.length}</span></button>
            <button type="button" role="tab" aria-selected={mode === 'video'} className={mode === 'video' ? 'on' : ''}
              onClick={() => setMode('video')}>Видео <span className="t-num">{vids.length}</span></button>
          </div>
          {canUpload && mode === 'video' && (
            <>
              <input ref={fileRef} type="file" accept="video/*" hidden onChange={handleFile} />
              <button type="button" className="cc-ir-dp-upload-btn" onClick={() => fileRef.current?.click()}>
                <Ic n="file-up" s={13} /> Загрузить видео
              </button>
            </>
          )}
        </div>
        {items.length === 0 ? (
          <div className="cc-ir-dp-gallery-empty">Нет элементов в этой группе</div>
        ) : (
          <div className="cc-ir-dp-gallery-grid" key={mode}>
            {items.map((item, index) => (
              <button
                key={item.id}
                type="button"
                className="cc-ir-dp-gallery-cell"
                style={dpThumbStyle(item, index, kind)}
                onClick={() => onOpen(item, items, kind)}
                aria-label={'Открыть: ' + item.title}
              >
                {item.roomId && roomLabel(intake, item.roomId) && (
                  <span className="cc-ir-dp-gallery-tag">{roomLabel(intake, item.roomId)}</span>
                )}
                {item.source && !item.roomId && (
                  <span className="cc-ir-dp-gallery-tag">{item.source}</span>
                )}
                {(item.kind === 'video' || kind === 'video') && (
                  <span className="cc-ir-media-play" aria-hidden="true"><Ic n="play" s={14} /></span>
                )}
                {item.duration && <span className="cc-ir-media-dur t-num">{item.duration}</span>}
                <span className="cc-ir-dp-gallery-cap">{item.title}</span>
              </button>
            ))}
          </div>
        )}
      </section>
    );
  }

  function DpLightbox({ item, items, intake, kind, onClose, onChange }) {
    const dlgRef = useRef(null);
    useEffect(() => {
      const dlg = dlgRef.current;
      if (!dlg) return;
      if (item) {
        if (!dlg.open) dlg.showModal();
      } else if (dlg.open) {
        dlg.close();
      }
    }, [item]);

    if (!item) return null;
    const idx = items.findIndex((x) => x.id === item.id);
    const go = (delta) => {
      const next = items[idx + delta];
      if (next) onChange(next);
    };
    const stageStyle = dpThumbStyle(item, idx, kind || 'viz');

    return (
      <dialog ref={dlgRef} className="cc-ir-dp-lightbox" onClose={onClose}>
        <div className="cc-ir-dp-lightbox-panel">
          <button type="button" className="cc-ir-dp-lightbox-x" onClick={onClose} aria-label="Закрыть">
            <Ic n="x" s={18} />
          </button>
          <div className={'cc-ir-dp-lightbox-stage' + (item.videoUrl ? ' cc-ir-dp-lightbox-stage-video' : '')} style={item.videoUrl ? undefined : stageStyle}>
            {item.videoUrl ? (
              <video className="cc-ir-dp-lightbox-video" src={item.videoUrl} controls playsInline />
            ) : (
              <>
                {(item.kind === 'video' || kind === 'video') && (
                  <span className="cc-ir-media-play-lg" aria-hidden="true"><Ic n="play" s={28} /></span>
                )}
                {!item.imageUrl && <span className="cc-ir-dp-lightbox-preview">{item.title}</span>}
              </>
            )}
          </div>
          <div className="cc-ir-dp-lightbox-meta">
            <strong>{item.title}</strong>
            {item.roomId && roomLabel(intake, item.roomId) && (
              <span className="cc-ir-muted">{roomLabel(intake, item.roomId)}</span>
            )}
            {item.source && <span className="cc-ir-muted">{item.source}</span>}
            {item.duration && <span className="cc-ir-muted t-num">{item.duration}</span>}
            {item.fileName && <span className="cc-ir-muted">{item.fileName}</span>}
            <span className="cc-ir-muted t-num">{idx + 1} / {items.length}</span>
          </div>
          <div className="cc-ir-dp-lightbox-nav">
            <button type="button" disabled={idx <= 0} onClick={() => go(-1)} aria-label="Предыдущее">
              <Ic n="chevron-left" s={16} /> Назад
            </button>
            <button type="button" disabled={idx >= items.length - 1} onClick={() => go(1)} aria-label="Следующее">
              Вперёд <Ic n="chevron-right" s={16} />
            </button>
          </div>
        </div>
      </dialog>
    );
  }

  function FileRow({ name, meta, badge }) {
    return (
      <button type="button" className="cc-ir-file-row">
        <span className="cc-ir-row-main">{name}</span>
        {meta ? <span className="cc-ir-row-meta t-num">{meta}</span> : <span />}
        {badge}
      </button>
    );
  }

  function MetaStrip({ items }) {
    const rows = items.filter((i) => i.v != null && i.v !== '' && i.v !== '—');
    if (!rows.length) return null;
    return (
      <dl className="cc-ir-kv-strip">
        {rows.map(({ k, v }) => (
          <div key={k} className="cc-ir-kv">
            <dt>{k}</dt>
            <dd>{v}</dd>
          </div>
        ))}
      </dl>
    );
  }

  function CompactRow({ main, meta, badge }) {
    return (
      <div className="cc-ir-row-compact">
        <span className="cc-ir-row-main">{main}</span>
        {meta ? <span className="cc-ir-row-meta">{meta}</span> : <span />}
        {badge || null}
      </div>
    );
  }

  function CompactList({ title, count, children }) {
    return (
      <div className="cc-ir-block-compact">
        {title && (
          <div className="cc-ir-block-h">
            <span>{title}</span>
            {count != null ? <span className="cc-ir-muted t-num">{count}</span> : null}
          </div>
        )}
        <div className="cc-ir-list-compact">{children}</div>
      </div>
    );
  }

  function roomLabel(intake, roomId) {
    if (!roomId) return null;
    const r = (intake.rooms || []).find((x) => x.id === roomId);
    return r ? r.name : roomId;
  }

  function DpTab({ intake, dp, dpMeta, kitStatus, editBrief, patch, dealId, role }) {
    const [lightbox, setLightbox] = useState(null);
    const [lightboxItems, setLightboxItems] = useState([]);
    const [lightboxKind, setLightboxKind] = useState('viz');
    const [assets, setAssets] = useState(() => resolveDpAssets(dp));

    useEffect(() => {
      setAssets(resolveDpAssets(dp));
    }, [dp, dpMeta?.version, dpMeta?.status]);

    const canUploadVideo = role === 'designer' && canEditDpBrief(true, dpMeta);

    const handleUploadVideo = (file) => {
      if (!canUploadVideo || !window.DesignProjectMock || !dealId) return;
      const baseName = (file.name || 'Видео').replace(/\.[^.]+$/, '');
      const item = {
        id: 'v-' + Date.now(),
        title: baseName,
        kind: 'video',
        roomId: null,
        thumb: (assets.videos || []).length,
        duration: '—',
        fileName: file.name,
        videoUrl: URL.createObjectURL(file),
      };
      const nextVideos = [...(assets.videos || []), item];
      const nextAssets = { ...assets, videos: nextVideos };
      setAssets(nextAssets);
      const current = window.DesignProjectMock.load(dealId) || dp;
      window.DesignProjectMock.save(dealId, {
        ...current,
        assets: { ...(current.assets || {}), videos: nextVideos },
        updatedAt: new Date().toISOString(),
      });
    };

    if (!intake.requiresDesign) {
      return <EmptyCard title="Дизайн-проект не требуется" text="Для этой сделки дизайн-проект не заказан." />;
    }

    const isApproved = window.DesignProjectMock?.isApproved?.(dpMeta?.status) || dpMeta?.status === 'client_approved';
    const briefLocked = !canEditDpBrief(true, dpMeta);
    const canEditBrief = editBrief && !briefLocked;
    const hasBrief = intake.brief && ((intake.brief.style || []).length || intake.brief.colors || intake.brief.budgetFinish);
    const openLightbox = (item, items, kind) => {
      setLightbox(item);
      setLightboxItems(items);
      setLightboxKind(kind || 'viz');
    };
    const closeLightbox = () => { setLightbox(null); setLightboxItems([]); setLightboxKind('viz'); };

    if (!dp || !dpMeta || !dpMeta.pageCount) {
      return (
        <div className="cc-ir-dp">
          <div className="cc-ir-dp-toolbar">
            <Badge tone="neutral" dot>ДП не создан</Badge>
          </div>
          {(hasBrief || canEditBrief) && (
            <div className="cc-ir-dp-panel cc-ir-dp-panel-single">
              <DpBriefSection intake={intake} canEditBrief={canEditBrief} briefLocked={briefLocked} patch={patch} />
            </div>
          )}
          {!hasBrief && !canEditBrief && (
            <EmptyCard title="Альбом не загружен" text="После загрузки и согласования здесь появятся PDF, визуализации и листы альбома." />
          )}
        </div>
      );
    }

    const pages = window.DesignProjectMock ? window.DesignProjectMock.flattenPages(dp) : [];
    const instructions = pages.filter((p) => p.type === 'work_instruction');
    const statusLabel = DP_STATUS[dpMeta.status] || dpMeta.status;
    const sections = {};
    pages.forEach((p) => {
      const key = p.sectionTitle || 'Прочее';
      (sections[key] = sections[key] || []).push(p);
    });
    const sectionKeys = Object.keys(sections);
    const ackPages = instructions.filter((p) => p.requiresAck);
    const pdfFiles = isApproved && assets ? [
      assets.albumPdf && { key: 'album', label: 'Альбом', ...assets.albumPdf },
      assets.texturesPdf && { key: 'tex', label: 'Фактуры', ...assets.texturesPdf },
      assets.specificationPdf && { key: 'spec', label: 'Спецификация', ...assets.specificationPdf },
    ].filter(Boolean) : [];

    return (
      <div className="cc-ir-dp">
        <div className="cc-ir-dp-toolbar">
          <Badge tone={dpStatusTone(dpMeta.status)} dot>{statusLabel}</Badge>
          <span className="cc-ir-dp-chip t-num">v{dpMeta.version}</span>
          {(dpMeta.designerName || dp.designerName) && (
            <span className="cc-ir-dp-chip">{dpMeta.designerName || dp.designerName}</span>
          )}
          <span className="cc-ir-dp-chip t-num">{dpMeta.pageCount} листов</span>
          {kitStatus && <span className="cc-ir-dp-chip">Заготовка · {kitStatus}</span>}
          {dpMeta.approvedAt && <span className="cc-ir-dp-chip">Утверждён {fmtDate(dpMeta.approvedAt)}</span>}
        </div>

        <div className="cc-ir-dp-panel cc-ir-dp-panel-stack">
          {(hasBrief || canEditBrief) && (
            <DpBriefSection intake={intake} canEditBrief={canEditBrief} briefLocked={briefLocked} patch={patch} />
          )}
          {pdfFiles.length > 0 && (
            <section className="cc-ir-dp-section">
              <h4 className="cc-ir-dp-label">Файлы</h4>
              <div className="cc-ir-dp-files">
                {pdfFiles.map((f) => (
                  <button key={f.key} type="button" className="cc-ir-dp-file-row" title={f.name}>
                    <Badge tone="neutral">{f.label}</Badge>
                    <span className="cc-ir-dp-file-name">{f.name}</span>
                    <span className="cc-ir-dp-file-meta t-num">{f.size}{f.pages ? ' · ' + f.pages + ' л.' : ''}</span>
                  </button>
                ))}
              </div>
            </section>
          )}
        </div>

        <DpGalleryBlock
          gallery={assets.gallery}
          videos={assets.videos}
          intake={intake}
          onOpen={openLightbox}
          approved={isApproved}
          dpStatus={dpMeta.status}
          canUpload={canUploadVideo}
          onUploadVideo={handleUploadVideo}
        />

        <section className="cc-ir-dp-section cc-ir-dp-section-full">
          <div className="cc-ir-dp-label-row">
            <h4 className="cc-ir-dp-label">Листы альбома</h4>
            <span className="cc-ir-muted t-num">{pages.length}</span>
            {ackPages.length > 0 && (
              <span className="cc-ir-dp-ack-hint t-num">ack · {ackPages.length}</span>
            )}
          </div>
          <div className="cc-ir-dp-pages">
            {sectionKeys.map((sec) => (
              <React.Fragment key={sec}>
                <div className="cc-ir-dp-sec-row">{sec}</div>
                {sections[sec].map((p) => (
                  <div key={p.id} className="cc-ir-dp-page-row">
                    <span className="cc-ir-dp-page-main">
                      <span className="t-num cc-ir-doc-num">л.{p.pageNumber}</span>
                      <span className="cc-ir-dp-page-title">{p.title}</span>
                    </span>
                    <span className="cc-ir-dp-page-meta">
                      {roomLabel(intake, p.roomId) && <span className="cc-ir-dp-page-room">{roomLabel(intake, p.roomId)}</span>}
                      <Badge tone={p.requiresAck ? 'warning' : (p.type === 'work_instruction' ? 'warning' : 'neutral')}>
                        {p.requiresAck ? 'ack' : (PAGE_TYPES[p.type] || p.type)}
                      </Badge>
                    </span>
                  </div>
                ))}
              </React.Fragment>
            ))}
          </div>
        </section>

        <DpLightbox item={lightbox} items={lightboxItems} intake={intake} kind={lightboxKind} onClose={closeLightbox} onChange={setLightbox} />
      </div>
    );
  }

  function MediaLightbox({ item, items, intake, onClose, onChange }) {
    const dlgRef = useRef(null);
    useEffect(() => {
      const dlg = dlgRef.current;
      if (!dlg) return;
      if (item) { if (!dlg.open) dlg.showModal(); }
      else if (dlg.open) dlg.close();
    }, [item]);

    if (!item) return null;
    const idx = items.findIndex((x) => x.id === item.id);
    const go = (delta) => { const next = items[idx + delta]; if (next) onChange(next); };
    const roomName = (rid) => rid === 'engineering' ? 'Инженерия' : (intake.rooms.find((r) => r.id === rid) || {}).name || rid;

    return (
      <dialog ref={dlgRef} className="cc-ir-dp-lightbox cc-ir-media-lightbox" onClose={onClose}>
        <div className="cc-ir-dp-lightbox-panel">
          <button type="button" className="cc-ir-dp-lightbox-x" onClick={onClose} aria-label="Закрыть">
            <Ic n="x" s={18} />
          </button>
          <div className="cc-ir-dp-lightbox-stage" style={mediaThumbStyle(item, idx)}>
            {item.kind === 'video' && (
              <span className="cc-ir-media-play-lg" aria-hidden="true"><Ic n="play" s={28} /></span>
            )}
            {!item.imageUrl && <span className="cc-ir-dp-lightbox-preview">{item.label}</span>}
          </div>
          <div className="cc-ir-dp-lightbox-meta">
            <strong>{item.label}</strong>
            {item.room && <span className="cc-ir-muted">{roomName(item.room)}</span>}
            {item.kind === 'video' && item.duration && <span className="cc-ir-muted t-num">{item.duration}</span>}
            <span className="cc-ir-muted t-num">{idx + 1} / {items.length}</span>
          </div>
          <div className="cc-ir-dp-lightbox-nav">
            <button type="button" disabled={idx <= 0} onClick={() => go(-1)} aria-label="Предыдущее">
              <Ic n="chevron-left" s={16} /> Назад
            </button>
            <button type="button" disabled={idx >= items.length - 1} onClick={() => go(1)} aria-label="Следующее">
              Вперёд <Ic n="chevron-right" s={16} />
            </button>
          </div>
        </div>
      </dialog>
    );
  }

  function MediaTab({ intake, dealId, edit, patch }) {
    const [filter, setFilter] = useState('all');
    const [lightbox, setLightbox] = useState(null);
    const [lightboxItems, setLightboxItems] = useState([]);
    const media = resolveIntakeMedia(intake, dealId);
    const roomName = (rid) => {
      if (rid === 'engineering') return 'Инженерия';
      if (rid === 'plan') return 'План';
      return (intake.rooms.find((r) => r.id === rid) || {}).name || rid;
    };

    if (!media.length && !edit) {
      return <EmptyCard title="Нет медиа" text="Фото и видео с объекта появятся после загрузки в карточке объекта." />;
    }

    const photos = media.filter((m) => m.kind !== 'video');
    const videos = media.filter((m) => m.kind === 'video');
    const filtered = filter === 'photo' ? photos : filter === 'video' ? videos : media;

    const groups = {};
    filtered.forEach((m) => { (groups[m.room] = groups[m.room] || []).push(m); });
    const groupKeys = Object.keys(groups).sort((a, b) => {
      const order = ['r1', 'r2', 'r3', 'engineering', 'plan'];
      return (order.indexOf(a) === -1 ? 99 : order.indexOf(a)) - (order.indexOf(b) === -1 ? 99 : order.indexOf(b));
    });

    const setMediaLabel = (id, label) => patch({ media: media.map((m) => (m.id === id ? { ...m, label } : m)) });
    const openLightbox = (item) => { setLightbox(item); setLightboxItems(filtered); };

    const roomPhotoFlags = (rid) => {
      const room = (intake.rooms || []).find((r) => r.id === rid);
      if (!room?.photos) return null;
      const p = room.photos;
      const labels = [
        p.plan && 'план', p.walls && 'стены', p.floor && 'пол', p.ceiling && 'потолок', p.nodes && 'узлы',
      ].filter(Boolean);
      return labels.length ? labels.join(', ') : null;
    };

    return (
      <div className="cc-ir-media cc-ir-media-compact">
        <dl className="cc-ir-kv-strip cc-ir-media-summary">
          <div className="cc-ir-kv"><dt>Фото</dt><dd className="t-num">{photos.length}</dd></div>
          <div className="cc-ir-kv"><dt>Видео</dt><dd className="t-num">{videos.length}</dd></div>
          <div className="cc-ir-kv"><dt>Всего</dt><dd className="t-num">{media.length}</dd></div>
          {intake.plan?.file && (
            <div className="cc-ir-kv"><dt>План БТИ</dt><dd>{intake.plan.file}</dd></div>
          )}
        </dl>

        <div className="cc-ir-media-toolbar">
          <div className="cc-ir-dp-seg" role="tablist" aria-label="Фильтр медиа">
            <button type="button" role="tab" aria-selected={filter === 'all'} className={filter === 'all' ? 'on' : ''}
              onClick={() => setFilter('all')}>Все <span className="t-num">{media.length}</span></button>
            <button type="button" role="tab" aria-selected={filter === 'photo'} className={filter === 'photo' ? 'on' : ''}
              onClick={() => setFilter('photo')}>Фото <span className="t-num">{photos.length}</span></button>
            <button type="button" role="tab" aria-selected={filter === 'video'} className={filter === 'video' ? 'on' : ''}
              onClick={() => setFilter('video')}>Видео <span className="t-num">{videos.length}</span></button>
          </div>
        </div>

        {filtered.length === 0 ? (
          <div className="cc-ir-dp-gallery-empty">Нет файлов в этой группе</div>
        ) : (
          <div className="cc-ir-media-board">
            {groupKeys.map((rid) => (
              <section key={rid} className="cc-ir-media-group-card">
                <div className="cc-ir-media-group-head">
                  <span className="cc-ir-media-room">{roomName(rid)}</span>
                  <span className="cc-ir-muted t-num">{groups[rid].length}</span>
                  {roomPhotoFlags(rid) && (
                    <span className="cc-ir-media-flags">{roomPhotoFlags(rid)}</span>
                  )}
                </div>
                <div className="cc-ir-media-grid">
                  {groups[rid].map((m, index) => (
                    edit ? (
                      <div key={m.id} className="cc-ir-media-edit-cell">
                        <button type="button" className="cc-ir-media-cell-btn" style={mediaThumbStyle(m, index)}
                          onClick={() => openLightbox(m)} aria-label={'Открыть: ' + m.label}>
                          {m.kind === 'video' && <span className="cc-ir-media-play" aria-hidden="true"><Ic n="play" s={14} /></span>}
                          {m.duration && <span className="cc-ir-media-dur t-num">{m.duration}</span>}
                        </button>
                        <input className="cc-ir-media-caption-in" value={m.label}
                          onChange={(e) => setMediaLabel(m.id, e.target.value)} aria-label={'Подпись: ' + m.label} />
                      </div>
                    ) : (
                      <button key={m.id} type="button" className="cc-ir-media-cell-btn" style={mediaThumbStyle(m, index)}
                        onClick={() => openLightbox(m)} aria-label={'Открыть: ' + m.label}>
                        {m.kind === 'video' && <span className="cc-ir-media-play" aria-hidden="true"><Ic n="play" s={14} /></span>}
                        <span className="cc-ir-media-cap">{m.label}</span>
                        {m.duration && <span className="cc-ir-media-dur t-num">{m.duration}</span>}
                      </button>
                    )
                  ))}
                </div>
              </section>
            ))}
          </div>
        )}

        {intake.mediaSkipped && (
          <div className="cc-ir-media-skipped">
            <Ic n="check" s={14} /> Медиа отмечены как достаточные
          </div>
        )}

        <MediaLightbox item={lightbox} items={lightboxItems} intake={intake}
          onClose={() => setLightbox(null)} onChange={setLightbox} />
      </div>
    );
  }

  function DocsTab({ intake, dp, dpMeta }) {
    const planFile = intake.plan && intake.plan.file;
    const pages = dp && window.DesignProjectMock ? window.DesignProjectMock.flattenPages(dp) : [];

    if (!planFile && !intake.requiresDesign) {
      return <EmptyCard title="Нет документов" text="Документы появятся после загрузки плана или альбома дизайн-проекта." />;
    }
    if (intake.requiresDesign && !planFile && !pages.length) {
      return <EmptyCard title="Альбом не загружен" text="Листы дизайн-проекта будут доступны после загрузки дизайнером." />;
    }

    const groups = {};
    pages.forEach((p) => {
      const key = p.sectionTitle || 'Прочее';
      (groups[key] = groups[key] || []).push(p);
    });

    return (
      <div className="cc-ir-docs cc-ir-docs-compact">
        {planFile && (
          <CompactList title="План БТИ">
            <CompactRow main={planFile} badge={<Badge tone="neutral">план</Badge>} />
          </CompactList>
        )}
        {intake.requiresDesign && pages.length > 0 && (
          <>
            <div className="cc-ir-block-h cc-ir-block-h-inline">
              <span>Альбом ДП</span>
              {dpMeta && dpMeta.version ? <Badge tone="info">v{dpMeta.version}</Badge> : null}
              <span className="cc-ir-muted t-num">{pages.length} листов</span>
            </div>
            {Object.keys(groups).map((sec) => (
              <CompactList key={sec} title={sec} count={groups[sec].length}>
                {groups[sec].map((p) => (
                  <CompactRow
                    key={p.id}
                    main={<><span className="t-num cc-ir-doc-num">л.{p.pageNumber}</span> {p.title}</>}
                    meta={roomLabel(intake, p.roomId) || null}
                    badge={<Badge tone={p.type === 'work_instruction' ? 'warning' : 'neutral'}>{PAGE_TYPES[p.type] || p.type}</Badge>}
                  />
                ))}
              </CompactList>
            ))}
          </>
        )}
      </div>
    );
  }

  function loadDesignKitStatus(dealId) {
    try {
      const raw = localStorage.getItem('remontpro_design_kit_' + dealId);
      if (!raw) return null;
      const kit = JSON.parse(raw);
      const map = { unavailable: 'Недоступна', draft: 'Черновик', ready: 'Готова к применению', needs_review: 'Требует проверки', needs_mapping: 'Требует привязки', applied: 'Применена', archived: 'Архив' };
      return map[kit.status] || kit.status;
    } catch (e) { return null; }
  }

  function SiteIntakeReadonlyPanel({ intake, dealId, role, onChange }) {
    const [tab, setTab] = useState('basic');
    const [data, setData] = useState(intake);
    const perms = intakePerms(role || 'manager');

    useEffect(() => { setData(intake); }, [intake, dealId]);

    useEffect(() => {
      const reload = () => {
        if (window.loadSiteIntake && dealId) {
          const fresh = window.loadSiteIntake(dealId);
          if (fresh) setData(fresh);
        }
      };
      window.addEventListener('remontpro:intake-updated', reload);
      window.addEventListener('storage', reload);
      return () => {
        window.removeEventListener('remontpro:intake-updated', reload);
        window.removeEventListener('storage', reload);
      };
    }, [dealId]);

    if (!data) {
      return <EmptyCard title="Объект не заведён" text="Заведите объект в CRM, чтобы увидеть данные замера и анкеты." />;
    }

    const patch = (p) => {
      const next = { ...data, ...p };
      if (p.prefs) next.prefs = { ...(data.prefs || {}), ...p.prefs };
      if (p.brief) next.brief = { ...(data.brief || {}), ...p.brief };
      setData(next);
      if (onChange) onChange(next);
    };

    const dp = R.loadDesignProject(dealId);
    const dpMeta = R.loadDesignProjectMeta(dealId);
    const readiness = R.calcReadiness(data, dpMeta);
    const kitStatus = loadDesignKitStatus(dealId);
    const edit = tabCanEdit(tab, perms, dpMeta);

    return (
      <div className="cc-ir">
        <div className="cc-ir-tabs">
          {TABS.map(([k, l]) => {
            const locked = tabIsLocked(k, dpMeta);
            return (
              <button
                key={k}
                type="button"
                className={'cc-ir-tab' + (tab === k ? ' on' : '') + (locked ? ' cc-ir-tab-locked' : '')}
                onClick={() => setTab(k)}
                title={locked ? 'Редактирование брифа недоступно' : undefined}
                aria-label={locked ? `${l}, только просмотр` : l}
              >
                {l}
                {locked && <span className="cc-ir-tab-lock" aria-hidden="true"><Ic n="lock" s={11} /></span>}
              </button>
            );
          })}
        </div>
        <EditBanner show={edit} />
        <div className="cc-ir-body">
          {tab === 'basic' && (
            <BasicTab intake={data} readiness={readiness} edit={perms.editBasic} patch={patch} hideInternal={perms.hideClientInternals} />
          )}
          {tab === 'measure' && <MeasureTab intake={data} dealId={dealId} edit={perms.editMeasure} patch={patch} />}
          {tab === 'wishes' && <WishesTab intake={data} dealId={dealId} edit={perms.editWishes} patch={patch} />}
          {tab === 'dp' && (
            <DpTab intake={data} dp={dp} dpMeta={dpMeta} kitStatus={kitStatus} editBrief={perms.editBrief} patch={patch} dealId={dealId} role={role} />
          )}
          {tab === 'docs' && <DocsTab intake={data} dp={dp} dpMeta={dpMeta} />}
          {perms.hideClientInternals && tab === 'basic' && (
            <div className="cc-ir-hint"><Ic n="eye-off" s={13} />Внутренние поля команды скрыты для клиента</div>
          )}
        </div>
      </div>
    );
  }

  window.SiteIntakeReadonlyPanel = SiteIntakeReadonlyPanel;
})();
