function PoraBackupPanel() {
  const [busy, setBusy] = React.useState(false);
  const [error, setError] = React.useState('');
  const [exported, setExported] = React.useState(null);
  const [plan, setPlan] = React.useState(null);
  const [replacementBackup, setReplacementBackup] = React.useState(null);
  const fileRef = React.useRef(null);
  const statusRef = React.useRef(null);
  const run = async (action) => {
    if (window.poraBackupBusy) return;
    window.poraBackupBusy = true; setBusy(true); setError('');
    try { await action(); } catch (e) { setError(e.message || 'Не удалось завершить действие. Попробуй ещё раз.'); }
    finally { window.poraBackupBusy = false; setBusy(false); }
  };
  React.useEffect(() => { statusRef.current?.focus(); }, [plan, exported, error, replacementBackup]);
  const describe = (counts) => <dl className="pora-backup-counts">
    {[['recipes', 'Рецепты'], ['starters', 'Закваски'], ['feedings', 'Кормления'], ['journal', 'Записи дневника'], ['photos', 'Фотографии'], ['pendingJournal', 'Черновик дневника'], ['activeBake', 'Активная выпечка'], ['plan', 'План']].filter(([key]) => counts[key] || ['recipes', 'journal', 'photos'].includes(key)).map(([key, label]) => <div key={key}><dt>{label}</dt><dd>{counts[key]}</dd></div>)}
  </dl>;
  const readFile = (event) => {
    const file = event.target.files?.[0]; event.target.value = '';
    if (!file) return;
    run(async () => { setExported(null); setReplacementBackup(null); setPlan(null); const archive = await window.PoraBackup.inspect(file); setPlan(await window.PoraBackup.prepare(archive)); });
  };
  const restore = () => run(async () => {
    await window.PoraBackup.commit(plan, { replacementBackup, confirmed: Boolean(replacementBackup) });
    window.location.reload();
  });
  return <div className="pora-backup" aria-busy={busy}>
    <style>{`
      .pora-backup p { font-size:16px; line-height:1.5; }
      .pora-backup-counts { margin:16px 0; border-radius:16px; padding:16px; background:#E9E7E4; display:grid; gap:8px; }
      .pora-backup-counts div { display:flex; justify-content:space-between; gap:16px; font-size:14px; line-height:1.4; }
      .pora-backup-counts dt { margin:0; } .pora-backup-counts dd { margin:0; font-weight:600; font-variant-numeric:tabular-nums; }
      .pora-backup-notice { margin:12px 0 0; padding:14px; background:#FAF2E7; border-radius:16px; }
      .pora-backup-notice p { margin:0; color:#353535; font-size:14px; }
      .pora-backup-notice p + p { margin-top:8px; }
      .pora-backup [role="alert"] { color:#353535; border-left:3px solid #D95122; padding-left:12px; }
      .pora-backup button { padding-top:12px; padding-bottom:12px; }
      .pora-backup button:active { transform:scale(.985); }
      .pora-backup button:focus-visible { outline:2px solid #353535; outline-offset:3px; }
      .pora-backup-status { margin-top:12px; }
    `}</style>
    <input ref={fileRef} type="file" accept=".zip,application/zip" hidden onChange={readFile} aria-label="Выбрать архив для восстановления" />
    {!exported && !plan && <>
      <h3>Резервная копия</h3>
      <p>Рецепты, дневник, фотографии и ход выпечки — в одном архиве. Сохрани его, чтобы восстановить данные в другом браузере.</p>
      <button className="pora-profile-button" type="button" disabled={busy} onClick={() => run(async () => setExported(await window.PoraBackup.create()))}>Создать архив с фото</button>
      <button className="pora-profile-button secondary" type="button" disabled={busy} onClick={() => fileRef.current?.click()}>Восстановить из архива</button>
    </>}
    {exported && <>
      <h3 ref={statusRef} tabIndex={-1}>Архив подготовлен</h3>
      <p>{new Date(exported.manifest.createdAt).toLocaleDateString('ru-RU')} · {(exported.blob.size / 1024 / 1024).toLocaleString('ru-RU', { maximumFractionDigits: 1 })} МБ</p>
      {describe(exported.manifest.counts)}
      {!!exported.manifest.warnings.length && <div className="pora-backup-notice"><p><strong>Обрати внимание</strong></p>{exported.manifest.warnings.map((w, i) => <p key={i}>{w}</p>)}</div>}
      <p>Архив содержит личные данные. Telegram подключается отдельно.</p>
      <button className="pora-profile-button" type="button" onClick={() => window.PoraBackup.download(exported)}>Скачать архив</button>
      <button className="pora-profile-button secondary" type="button" onClick={() => setExported(null)}>Готово</button>
    </>}
    {plan && <>
      <h3 ref={statusRef} tabIndex={-1}>{replacementBackup ? 'Копия перед заменой' : 'Проверим перед восстановлением'}</h3>
      {!replacementBackup ? <>
        <p>Архив от {new Date(plan.archive.manifest.createdAt).toLocaleDateString('ru-RU')}. Все файлы проверены.</p>
        {describe(plan.archive.manifest.counts)}
        <label className="pora-profile-field-label" htmlFor="backup-mode">Как восстановить</label>
        <select id="backup-mode" className="pora-profile-select" value={plan.mode} disabled={busy} onChange={(e) => { const mode = e.target.value; run(async () => setPlan(await window.PoraBackup.prepare(plan.archive, mode))); }}>
          <option value="merge">Добавить без дублей</option><option value="replace">Заменить локальные данные</option>
        </select>
        <p>{plan.mode === 'merge' ? 'Совпадающие записи и фото не добавятся повторно. Отличающиеся версии истории сохранятся отдельно.' : 'Текущие данные заменятся содержимым архива. Сначала сохраним резервную копию этого устройства.'}</p>
        {!![...plan.archive.manifest.warnings, ...plan.warnings, ...plan.changes, ...plan.conflicts].length && <div className="pora-backup-notice">{[...plan.archive.manifest.warnings, ...plan.warnings, ...plan.changes, ...plan.conflicts].map((w, i) => <p key={i}>{w}</p>)}</div>}
        <button className="pora-profile-button" type="button" disabled={busy || !!plan.conflicts.length} onClick={plan.mode === 'merge' ? restore : () => run(async () => {
          const backup = await window.PoraBackup.create();
          if (backup.raw !== plan.raw) throw new Error('Данные изменились. Выбери архив ещё раз.');
          if (backup.manifest.warnings.some((w) => w.startsWith('Не найдено'))) throw new Error('Копия текущих данных неполная: отсутствуют фотографии. Замена остановлена.');
          window.PoraBackup.download(backup, 'before-restore-'); setReplacementBackup(backup);
        })}>{plan.mode === 'merge' ? 'Добавить данные' : 'Сохранить копию и продолжить'}</button>
      </> : <>
        <p>Резервная копия подготовлена к скачиванию. Убедись, что файл сохранён, прежде чем заменить данные.</p>
        <button className="pora-profile-button secondary" type="button" disabled={busy} onClick={() => window.PoraBackup.download(replacementBackup, 'before-restore-')}>Скачать копию ещё раз</button>
        <button className="pora-profile-button danger" type="button" disabled={busy} onClick={restore}>Копия сохранена — заменить данные</button>
      </>}
      <button className="pora-profile-button secondary" type="button" disabled={busy} onClick={() => { setPlan(null); setReplacementBackup(null); setError(''); }}>Отмена</button>
    </>}
    {busy && <p className="pora-backup-status" role="status">Проверяем и сохраняем данные…</p>}
    {error && <p ref={statusRef} tabIndex={-1} role="alert">{error}</p>}
  </div>;
}
window.PoraBackupPanel = PoraBackupPanel;

function PoraStorageNotice() {
  const [failed, setFailed] = React.useState(Boolean(window.poraStorageError));
  React.useEffect(() => {
    const update = () => setFailed(Boolean(window.poraStorageError));
    window.addEventListener('pora-storage-error', update);
    update();
    return () => window.removeEventListener('pora-storage-error', update);
  }, []);
  if (!failed) return null;
  return <div role="alert" style={{ position: 'sticky', top: 0, zIndex: 90, padding: 16, background: '#FAF2E7', color: '#353535', font: '14px/1.5 Onest,sans-serif', borderBottom: '2px solid #D95122' }}>
    {window.poraStorageConflict ? 'Данные восстановлены в другой вкладке. Обнови приложение, чтобы увидеть их.' : 'Последние изменения не сохранились на устройстве. Освободи место и повтори. Пока не закрывай приложение.'}
    <button type="button" onClick={() => window.retryPoraStateSave()} style={{ display: 'block', minHeight: 44, marginTop: 8, border: 0, borderRadius: 12, padding: '0 16px', background: '#E9E7E4', color: '#353535', font: '600 14px Onest,sans-serif' }}>{window.poraStorageConflict ? 'Обновить приложение' : 'Повторить сохранение'}</button>
  </div>;
}
window.PoraStorageNotice = PoraStorageNotice;
