#!/usr/bin/env node
// Генератор скелета лабораторного практикума Физики 7. Phase 0: только инфраструктура.

const fs = require('fs');
const path = require('path');

const VER = '20260530';
const OUT = path.join(__dirname, '..', '..', 'frontend', 'textbooks', 'physics_7_lab.html');

const LABS = [
  { id:'lr1', num:'ЛР 1', title:'Определение цены деления шкалы измерительного прибора', wm:'1', tag:'§ 7' },
  { id:'lr2', num:'ЛР 2', title:'Измерение длины', wm:'2', tag:'§ 4 · § 7' },
  { id:'lr3', num:'ЛР 3', title:'Измерение объёма', wm:'3', tag:'§ 4' },
  { id:'lr4', num:'ЛР 4', title:'Изучение неравномерного движения', wm:'4', tag:'§ 18' },
  { id:'lr5', num:'ЛР 5', title:'Измерение плотности вещества', wm:'5', tag:'§ 20' },
  { id:'lr6', num:'ЛР 6', title:'Изучение силы трения', wm:'6', tag:'§ 27' },
];

const labsJs = LABS.map(l => `{id:'${l.id}',num:'${l.num}',title:${JSON.stringify(l.title)},wm:'${l.wm}',tag:'${l.tag}'}`).join(',');
const sections = LABS.map(l =>
  `    <section id="sec-${l.id}" class="sec" data-watermark="${l.wm}">
      <div class="sec-header">
        <span class="sec-num">${l.num}</span>
        <h2 class="sec-h">${l.title}</h2>
        <span class="sec-tag">${l.tag}</span>
      </div>
      <div id="${l.id}-body"><div class="placeholder">Виртуальная лабораторная работа появится в Phase 7 (после контента глав).</div></div>
    </section>`).join('\n');

const html = `<!doctype html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="0">
<title>Физика 7 · Лабораторный практикум</title>
<meta name="viewport" content="width=device-width,initial-scale=1">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.css">
<link rel="stylesheet" href="/css/phys-textbook-widgets.css">
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.js"></script>
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/contrib/auto-render.min.js"
  onload="renderMathInElement(document.body,{delimiters:[{left:'$$',right:'$$',display:true},{left:'$',right:'$',display:false}],throwOnError:false})"></script>
<script src="/js/api.js" defer></script>
<script src="/js/xp.js" defer></script>
<script src="/js/phys.js?v=${VER}" defer></script>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=Manrope:wght@600;700;800;900&family=Unbounded:wght@700;800;900&family=JetBrains+Mono:wght@500;700&display=swap" rel="stylesheet">
<style>
:root{
  --bg:#ecfeff; --card:#fff; --card-soft:#f8fafc; --text:#0f172a; --muted:#475569;
  --border:#a5f3fc; --pri:#0891b2; --pri2:#0e7490; --pri-soft:#cffafe;
  --acc:#06b6d4; --acc-d:#0e7490; --acc-soft:#cffafe;
  --ok:#10b981; --ok-bg:#d1fae5; --fail:#dc2626; --fail-bg:#fee2e2; --warn:#f59e0b; --warn-bg:#fef3c7;
  --sh:0 4px 16px rgba(8,145,178,.08); --sh-h:0 12px 36px rgba(8,145,178,.16);
}
html.dark{--bg:#0c2030;--card:#0e2436;--card-soft:#0b1a28;--text:#cffafe;--muted:#67e8f9;--border:#155e75;--pri-soft:rgba(8,145,178,.18)}
*{margin:0;padding:0;box-sizing:border-box}
html,body{min-height:100vh}
body{font-family:'Inter',system-ui,sans-serif;background:var(--bg);color:var(--text);line-height:1.6;transition:background .25s,color .25s}

.hdr{position:relative;background:linear-gradient(135deg,#164e63,#0891b2 60%,#22d3ee);color:#fff;padding:24px 22px 22px;overflow:hidden;border-bottom:2px solid rgba(255,255,255,.18)}
.hdr-inner{position:relative;z-index:1;max-width:1240px;margin:0 auto;display:flex;align-items:center;gap:14px;flex-wrap:wrap}
.hdr h1{font-family:'Unbounded',sans-serif;font-size:1.55rem;font-weight:800;letter-spacing:-.01em}
.hdr-sub{font-size:.88rem;opacity:.9;margin-top:3px}
.hdr-side{margin-left:auto;display:flex;gap:8px;flex-wrap:wrap}
.hdr-btn{padding:8px 12px;background:rgba(255,255,255,.16);border:none;color:#fff;border-radius:9px;cursor:pointer;font-weight:600;font-size:.82rem;display:inline-flex;align-items:center;gap:6px;transition:background .15s;font-family:inherit;text-decoration:none}
.hdr-btn:hover{background:rgba(255,255,255,.26)}
.ic{width:16px;height:16px;stroke:currentColor;fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}

.main{max-width:1240px;margin:0 auto;padding:22px;width:100%;display:grid;grid-template-columns:1fr 280px;gap:24px}
@media(max-width:980px){.main{grid-template-columns:1fr;padding:14px}}

.col-main{min-width:0}
.psel{background:var(--card);border:1.5px solid var(--border);border-radius:14px;padding:16px;margin-bottom:18px;box-shadow:var(--sh)}
.psel-head{font-family:'Unbounded',sans-serif;font-size:.78rem;font-weight:800;color:var(--pri2);text-transform:uppercase;letter-spacing:.07em;margin-bottom:10px}
.psel-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(190px,1fr));gap:10px}
.psel-card{padding:12px;background:var(--card-soft);border:1.5px solid var(--border);border-radius:10px;cursor:pointer;transition:transform .15s,border-color .15s,box-shadow .15s;text-align:left}
.psel-card:hover{border-color:var(--acc);transform:translateY(-2px);box-shadow:0 4px 14px rgba(0,0,0,.06)}
.psel-card.active{border-color:var(--acc);background:var(--acc-soft)}
.psel-num{font-size:.7rem;font-weight:800;color:var(--acc-d);letter-spacing:.04em;text-transform:uppercase;margin-bottom:3px}
.psel-title{font-size:.86rem;font-weight:700;line-height:1.35}
.psel-prog{height:4px;background:rgba(0,0,0,.07);border-radius:3px;overflow:hidden;margin-top:7px}
.psel-prog-fill{height:100%;background:linear-gradient(90deg,var(--acc),var(--acc-d));border-radius:3px;transition:width .4s}

.sec{display:none;background:var(--card);border:1.5px solid var(--border);border-radius:14px;padding:22px;box-shadow:var(--sh);position:relative}
.sec.active{display:block}
.sec[data-watermark]::before{content:attr(data-watermark);position:absolute;right:18px;top:-8px;font-family:'Unbounded',sans-serif;font-size:5.6rem;font-weight:900;color:var(--acc-soft);pointer-events:none;line-height:1;user-select:none}
.sec-header{display:flex;align-items:baseline;gap:14px;margin-bottom:18px;padding-bottom:14px;border-bottom:1.5px solid var(--border);position:relative;z-index:1;flex-wrap:wrap}
.sec-num{background:linear-gradient(135deg,var(--acc),var(--acc-d));color:#fff;padding:5px 12px;border-radius:9px;font-family:'Unbounded',sans-serif;font-weight:800;font-size:.86rem;letter-spacing:.04em}
.sec-h{font-family:'Unbounded',sans-serif;font-size:1.3rem;font-weight:800;color:var(--text);flex:1;min-width:0}
.sec-tag{font-size:.74rem;font-weight:700;color:var(--pri2);background:var(--pri-soft);padding:3px 9px;border-radius:99px;text-transform:uppercase;letter-spacing:.04em}
.placeholder{padding:32px 20px;text-align:center;color:var(--muted);font-size:.95rem;background:var(--card-soft);border:1.5px dashed var(--border);border-radius:10px}

.col-side{position:sticky;top:14px;align-self:start;height:fit-content;max-height:calc(100vh - 28px);overflow-y:auto}
.sidecard{background:var(--card);border:1px solid var(--border);border-radius:14px;padding:16px;margin-bottom:14px;box-shadow:var(--sh)}
.sidecard h4{font-family:'Unbounded',sans-serif;font-size:.74rem;font-weight:800;color:var(--pri2);text-transform:uppercase;letter-spacing:.07em;margin-bottom:10px;padding-bottom:8px;border-bottom:1px solid var(--border)}
.sidecard-row{margin-bottom:8px;font-size:.86rem;line-height:1.6}
.sidecard-row b{color:var(--pri);font-weight:700}
@media(max-width:980px){.col-side{position:static;max-height:none}}

.col-side-backdrop{position:fixed;inset:0;background:rgba(0,0,0,.42);z-index:9990;display:none}
.col-side-backdrop.show{display:block}
@media(min-width:981px){#sidebar-btn{display:none}.col-side-backdrop.show{display:none}}
@media(max-width:980px){
  .col-side{position:fixed;top:0;right:0;height:100vh;width:300px;max-width:88vw;background:var(--bg);box-shadow:-12px 0 24px rgba(0,0,0,.18);padding:18px 16px;overflow-y:auto;transform:translateX(100%);transition:transform .25s ease;z-index:9991;max-height:none}
  .col-side.open{transform:none}
}

.ach-popup{position:fixed;top:80px;right:18px;background:linear-gradient(135deg,var(--acc-d),var(--acc));color:#fff;padding:12px 18px;border-radius:11px;font-weight:700;font-size:.9rem;box-shadow:0 8px 28px rgba(0,0,0,.25);z-index:1002;display:none;align-items:center;gap:8px;max-width:340px}
.ach-popup.show{display:flex}

.foot{text-align:center;padding:30px 16px;color:var(--muted);font-size:.78rem;border-top:1px solid var(--border);margin-top:30px}
</style>
</head>
<body>

<header class="hdr">
  <div class="hdr-inner">
    <div>
      <a href="/textbook/physics-7" class="hdr-btn"><svg class="ic" viewBox="0 0 24 24"><polyline points="15 18 9 12 15 6"/></svg> К физике 7</a>
    </div>
    <div>
      <h1>Физика 7 &middot; Лабораторный практикум</h1>
      <div class="hdr-sub">6 виртуальных лабораторных работ</div>
    </div>
    <div class="hdr-side">
      <button id="sidebar-btn" class="hdr-btn"><svg class="ic" viewBox="0 0 24 24"><line x1="4" y1="6" x2="20" y2="6"/><line x1="4" y1="12" x2="20" y2="12"/><line x1="4" y1="18" x2="14" y2="18"/></svg> Шпаргалка</button>
      <button id="theme-btn" class="hdr-btn"><svg class="ic" viewBox="0 0 24 24"><path d="M21 12.8A9 9 0 1 1 11.2 3a7 7 0 0 0 9.8 9.8z"/></svg><span id="theme-lab">Тёмная</span></button>
    </div>
  </div>
</header>

<main class="main">
  <div class="col-main">
    <div class="psel">
      <div class="psel-head">Лабораторные работы</div>
      <div class="psel-grid" id="psel-grid"></div>
    </div>

${sections}
  </div>

  <aside class="col-side" id="col-side"><div id="sidebar-content"></div></aside>
  <div class="col-side-backdrop" id="col-side-backdrop"></div>
</main>

<div class="ach-popup" id="ach-popup"><svg class="ic" viewBox="0 0 24 24"><polygon points="12,2 15,9 22,9.3 17,14 18.5,21 12,17 5.5,21 7,14 2,9.3 9,9"/></svg><span id="ach-text"></span></div>

<footer class="foot">Интерактивный учебник «Физика 7 класс» &middot; Лабораторный практикум &middot; LearnSpace</footer>

<script>
'use strict';

const LS_PREFIX = 'physics7_lab';
const _TB_SLUG = 'physics-7-lab';

const LABS = [${labsJs}];
const TOTAL_LABS = LABS.length;

const SIDEBARS = {};
LABS.forEach(l => { SIDEBARS[l.id] = { title: 'Шпаргалка ' + l.num, rows: [['В разработке','симуляция и таблицы измерений появятся в Phase 7']] }; });
const ACH_LABELS = { start: 'Начало практикума', all_labs: 'Лаборант 7 класса' };

const STATE = { current: null, progress: {}, xp: 0, level: 1, achievements: new Map() };

function _xpForLevel(lv){ return Math.round(100 * Math.pow(lv-1, 1.6)); }
function calcLevel(xp){ let lv = 1; while(_xpForLevel(lv+1) <= xp) lv++; return lv; }

function loadProgress(){
  try{
    const s = localStorage.getItem(LS_PREFIX + '_progress'); if(s) Object.assign(STATE.progress, JSON.parse(s));
    const a = localStorage.getItem(LS_PREFIX + '_achievements');
    if(a){ const p = JSON.parse(a); if(p && typeof p === 'object') for(const [id,t] of Object.entries(p)) STATE.achievements.set(id, (t && t !== id) ? t : (ACH_LABELS[id] || id)); }
    STATE.xp = +(localStorage.getItem('physics7_xp') || 0); STATE.level = calcLevel(STATE.xp);
  }catch(e){}
}
function saveProgress(){
  try{
    localStorage.setItem(LS_PREFIX + '_progress', JSON.stringify(STATE.progress));
    localStorage.setItem(LS_PREFIX + '_achievements', JSON.stringify(Object.fromEntries(STATE.achievements)));
    localStorage.setItem('physics7_xp', String(STATE.xp));
  }catch(e){}
}
function bumpProgress(key, delta){
  STATE.progress[key] = Math.max(0, Math.min(100, (STATE.progress[key]||0) + delta));
  saveProgress(); refreshProgressUI();
  const done = LABS.every(l => (STATE.progress[l.id]||0) >= 100);
  if(done && !STATE.achievements.has('all_labs')) achievement('all_labs');
}
function addXp(n, src){
  if(!n) return;
  STATE.xp = Math.max(0, (STATE.xp||0) + n); STATE.level = calcLevel(STATE.xp);
  saveProgress(); refreshProgressUI();
  if(window.LS && window.LS.xp) window.LS.xp.add(n, 'physics7-lab-' + (src||'misc'));
}
function achievement(id, label){
  if(STATE.achievements.has(id)) return;
  STATE.achievements.set(id, label || ACH_LABELS[id] || id);
  saveProgress();
  const pop = document.getElementById('ach-popup');
  if(pop){ document.getElementById('ach-text').textContent = 'Ачивка: ' + (label || ACH_LABELS[id] || id); pop.classList.add('show'); setTimeout(()=>pop.classList.remove('show'), 3000); }
  addXp(id === 'all_labs' ? 80 : 20, 'ach-' + id);
}

function refreshProgressUI(){
  document.querySelectorAll('[data-prog-card]').forEach(el => {
    const k = el.dataset.progCard;
    const fl = el.querySelector('.psel-prog-fill');
    if(fl) fl.style.width = (STATE.progress[k]||0) + '%';
  });
  if(STATE.current && document.getElementById('sidebar-content')){ try{ buildSidebar(STATE.current); }catch(e){} }
}

function buildSelector(){
  const grid = document.getElementById('psel-grid');
  if(!grid) return;
  grid.innerHTML = LABS.map(l =>
    '<button class="psel-card" data-id="' + l.id + '" data-prog-card="' + l.id + '">'
    + '<div class="psel-num">' + l.num + ' &middot; ' + l.tag + '</div>'
    + '<div class="psel-title">' + l.title + '</div>'
    + '<div class="psel-prog"><div class="psel-prog-fill" style="width:' + (STATE.progress[l.id]||0) + '%"></div></div>'
    + '</button>'
  ).join('');
  grid.querySelectorAll('.psel-card').forEach(c => c.addEventListener('click', () => goTo(c.dataset.id)));
}

function goTo(id){
  STATE.current = id;
  document.querySelectorAll('.sec').forEach(s => s.classList.remove('active'));
  const el = document.getElementById('sec-' + id); if(el) el.classList.add('active');
  document.querySelectorAll('.psel-card').forEach(c => c.classList.toggle('active', c.dataset.id === id));
  buildSidebar(id);
  window.scrollTo({ top: 0, behavior: 'smooth' });
  if((STATE.progress[id]||0) < 10) bumpProgress(id, 10);
}

function buildSidebar(id){
  const box = document.getElementById('sidebar-content');
  if(!box) return;
  const sb = SIDEBARS[id] || SIDEBARS[LABS[0].id];
  const xpForLv = _xpForLevel(STATE.level), xpNext = _xpForLevel(STATE.level+1);
  const xpPct = (xpNext - xpForLv) > 0 ? Math.round((STATE.xp - xpForLv) / (xpNext - xpForLv) * 100) : 100;
  let html = '';
  html += '<div class="sidecard" style="background:linear-gradient(135deg,var(--pri-soft),var(--acc-soft));border-color:var(--acc)"><h4>XP-прогресс <span style="float:right">Ур. ' + STATE.level + '</span></h4><div class="sidecard-row"><div style="height:8px;background:rgba(0,0,0,.07);border-radius:5px;overflow:hidden"><div style="height:100%;background:linear-gradient(90deg,var(--acc),var(--pri));width:' + xpPct + '%"></div></div><div style="display:flex;justify-content:space-between;font-size:.78rem;color:var(--muted);margin-top:5px"><span>' + STATE.xp + ' XP</span><span>' + xpNext + ' XP</span></div></div></div>';
  html += '<div class="sidecard"><h4>' + sb.title + '</h4>';
  sb.rows.forEach(([k,v]) => { html += '<div class="sidecard-row"><b>' + k + '</b>' + (v ? ' &mdash; ' + v : '') + '</div>'; });
  html += '</div>';
  if(STATE.achievements.size > 0){
    html += '<div class="sidecard"><h4>Достижения <span style="color:var(--warn);float:right">' + STATE.achievements.size + '</span></h4>';
    [...STATE.achievements.values()].slice(-4).forEach(t => { html += '<div class="sidecard-row" style="font-size:.78rem;color:var(--ok)">&#10003; ' + t + '</div>'; });
    html += '</div>';
  }
  box.innerHTML = html;
}

function initTheme(){
  const t = localStorage.getItem(LS_PREFIX + '_theme') || localStorage.getItem('physics7_theme') || 'light';
  if(t === 'dark') document.documentElement.classList.add('dark');
  document.getElementById('theme-lab').textContent = t === 'dark' ? 'Светлая' : 'Тёмная';
  document.getElementById('theme-btn').addEventListener('click', () => {
    document.documentElement.classList.toggle('dark');
    const dark = document.documentElement.classList.contains('dark');
    localStorage.setItem(LS_PREFIX + '_theme', dark ? 'dark' : 'light');
    localStorage.setItem('physics7_theme', dark ? 'dark' : 'light');
    document.getElementById('theme-lab').textContent = dark ? 'Светлая' : 'Тёмная';
  });
}

function initSidebarToggle(){
  const side = document.getElementById('col-side'), back = document.getElementById('col-side-backdrop'), btn = document.getElementById('sidebar-btn');
  if(!side || !btn) return;
  function open(){ side.classList.add('open'); back.classList.add('show'); }
  function close(){ side.classList.remove('open'); back.classList.remove('show'); }
  btn.addEventListener('click', () => { if(side.classList.contains('open')) close(); else open(); });
  back.addEventListener('click', close);
  document.addEventListener('keydown', e => { if(e.key === 'Escape') close(); });
}

function init(){
  loadProgress(); initTheme(); initSidebarToggle();
  buildSelector(); refreshProgressUI(); goTo(LABS[0].id);
  setTimeout(() => achievement('start'), 600);
}
document.addEventListener('DOMContentLoaded', init);
</script>
</body>
</html>
`;

fs.writeFileSync(OUT, html, 'utf8');
console.log(`[gen_phys7_lab] ${OUT} — ${html.split('\n').length} lines`);
