// phys9_ch3_widgets.js — виджеты для Физики 9, Глава 3 (§25-§30): статика и гидростатика.
(function(){
'use strict';
const C = () => window.PHYS9_COLORS || {};
const PI = Math.PI;

function dndPool(secId, items, cats){
  let p='<div class="dnd-pool" id="'+secId+'-pool" style="display:flex;flex-wrap:wrap;gap:6px;padding:10px;border:1.5px dashed var(--border);border-radius:10px;margin-bottom:10px">';
  items.forEach(it=>{ p += '<div class="dnd-chip" draggable="true" data-id="'+it.id+'" data-cat="'+it.cat+'" style="padding:6px 11px;border:1.5px solid var(--border);border-radius:9px;background:var(--card);cursor:grab;font-size:.92rem">'+it.html+'</div>'; });
  p += '</div><div style="display:grid;grid-template-columns:repeat('+cats.length+',1fr);gap:10px">';
  cats.forEach(c=>{ p += '<div class="drop-box" data-cat="'+c.cat+'" style="border:1.5px dashed var(--border);border-radius:10px;padding:10px;min-height:80px"><h5 style="font-size:.78rem;font-weight:800;margin-bottom:6px;color:var(--sec-acc-d,var(--pri-d))">'+c.label+'</h5><div class="drop-items"></div></div>'; });
  return p + '</div>';
}
function wireDnd(scopeId, items){
  const scope = document.querySelector('#'+scopeId); if(!scope) return;
  scope.querySelectorAll('.dnd-chip').forEach(chip=>{
    chip.addEventListener('dragstart', e=>{ e.dataTransfer.setData('text/plain', chip.dataset.id); chip.style.opacity='0.5'; });
    chip.addEventListener('dragend', e=>{ chip.style.opacity='1'; });
  });
  scope.querySelectorAll('.drop-box').forEach(box=>{
    box.addEventListener('dragover', e=>{ e.preventDefault(); box.style.borderColor=C().force||'#10b981'; });
    box.addEventListener('dragleave', e=>{ box.style.borderColor=''; });
    box.addEventListener('drop', e=>{
      e.preventDefault(); box.style.borderColor='';
      const id = e.dataTransfer.getData('text/plain');
      const chip = scope.querySelector('.dnd-chip[data-id="'+id+'"]');
      if(chip) box.querySelector('.drop-items').appendChild(chip);
    });
  });
  scope.querySelector('.dnd-check').addEventListener('click', ()=>{
    let wrong = 0; const total = items.length;
    scope.querySelectorAll('.drop-box').forEach(box=>{
      const cat = box.dataset.cat;
      box.querySelectorAll('.dnd-chip').forEach(chip=>{ if(chip.dataset.cat !== cat) wrong++; });
    });
    let placed = 0; scope.querySelectorAll('.drop-box .dnd-chip').forEach(()=>placed++);
    const fb = scope.querySelector('.dnd-fb');
    if(placed < total){ fb.className='feedback fail'; fb.innerHTML='Распредели все — осталось '+(total-placed)+'.'; return; }
    if(wrong===0){ fb.className='feedback ok'; fb.innerHTML='&#10003; Идеально!'; }
    else { fb.className='feedback fail'; fb.innerHTML='&#10007; Ошибок: '+wrong+'.'; }
  });
}
function wgWrapper(secId, badge, title, help, body){
  return '<div class="wg" id="'+secId+'"><div class="wg-header"><span class="wg-badge">'+badge+'</span><div class="wg-title">'+title+'</div></div><div class="wg-help">'+help+'</div>'+body+'</div>';
}
function appendTo(secId, html){
  const box = document.getElementById(secId+'-body');
  if(!box) return false;
  if(box.querySelector('.wg-phys9-extra-'+secId)) return false;
  const div = document.createElement('div'); div.className = 'wg-phys9-extra-'+secId; div.innerHTML = html;
  box.appendChild(div);
  try { if(window.renderMathInElement) window.renderMathInElement(box, { delimiters: [{left:'$$',right:'$$',display:true},{left:'$',right:'$',display:false}], throwOnError:false }); } catch(e){}
  return true;
}

/* ====== §25 — Равновесие рычага F₁ l₁ = F₂ l₂ ====== */
function add_p25(){
  const body = '<div class="sliders">'
    +'<label>$m_1$, кг: <b id="p25w-m1">2</b><input type="range" id="p25w-m1-r" min="0.5" max="20" step="0.5" value="2"></label>'
    +'<label>$l_1$, м: <b id="p25w-l1">1.5</b><input type="range" id="p25w-l1-r" min="0.1" max="3" step="0.1" value="1.5"></label>'
    +'<label>$m_2$, кг: <b id="p25w-m2">3</b><input type="range" id="p25w-m2-r" min="0.5" max="20" step="0.5" value="3"></label>'
    +'<label>$l_2$, м: <b id="p25w-l2">1.0</b><input type="range" id="p25w-l2-r" min="0.1" max="3" step="0.1" value="1.0"></label>'
    +'</div>'
    +'<svg id="p25w-svg" viewBox="0 0 460 200" style="width:100%;height:auto;background:var(--bg-subtle,#f8fafc);border:1px solid var(--border);border-radius:9px"></svg>'
    +'<div class="score-display" style="flex-direction:column;align-items:flex-start;gap:5px">'
      +'<span>$M_1 = m_1 g l_1$ = <b id="p25w-M1">29.4</b> Н·м</span>'
      +'<span>$M_2 = m_2 g l_2$ = <b id="p25w-M2">29.4</b> Н·м</span>'
      +'<span><b id="p25w-eq" style="color:var(--ok)">РАВНОВЕСИЕ ✓</b></span>'
    +'</div>';
  if(appendTo('p25', wgWrapper('p25-extra', 'CALC+VIS', 'Равновесие рычага', '$F_1 l_1 = F_2 l_2$ — моменты сил равны.', body))){
    const upd = ()=>{
      const m1 = +document.getElementById('p25w-m1-r').value;
      const l1 = +document.getElementById('p25w-l1-r').value;
      const m2 = +document.getElementById('p25w-m2-r').value;
      const l2 = +document.getElementById('p25w-l2-r').value;
      document.getElementById('p25w-m1').textContent = m1;
      document.getElementById('p25w-l1').textContent = l1.toFixed(1);
      document.getElementById('p25w-m2').textContent = m2;
      document.getElementById('p25w-l2').textContent = l2.toFixed(1);
      const M1 = m1*9.8*l1, M2 = m2*9.8*l2;
      document.getElementById('p25w-M1').textContent = M1.toFixed(1);
      document.getElementById('p25w-M2').textContent = M2.toFixed(1);
      const eq = document.getElementById('p25w-eq');
      if(Math.abs(M1-M2) < 0.5){ eq.innerHTML = 'РАВНОВЕСИЕ ✓'; eq.style.color = 'var(--ok,#10b981)'; }
      else if(M1 > M2){ eq.innerHTML = 'ЛЕВАЯ ПЕРЕВЕШИВАЕТ ⤵'; eq.style.color = 'var(--fail,#dc2626)'; }
      else { eq.innerHTML = 'ПРАВАЯ ПЕРЕВЕШИВАЕТ ⤵'; eq.style.color = 'var(--fail,#dc2626)'; }
      /* SVG */
      const col = C();
      const tilt = Math.max(-15, Math.min(15, (M2-M1)*0.3));
      const cx = 230, cy = 100;
      const len = 180;
      const rad = tilt*PI/180;
      const lx = cx - len*Math.cos(rad), ly = cy + len*Math.sin(rad);
      const rx = cx + len*Math.cos(rad), ry = cy - len*Math.sin(rad);
      let s = '';
      /* опора */
      s += '<polygon points="'+cx+',100 '+(cx-20)+',180 '+(cx+20)+',180" fill="'+(col.body||'#475569')+'" stroke="'+(col.axis||'#1e293b')+'" stroke-width="1.5"/>';
      /* балка */
      s += '<line x1="'+lx.toFixed(1)+'" y1="'+ly.toFixed(1)+'" x2="'+rx.toFixed(1)+'" y2="'+ry.toFixed(1)+'" stroke="'+(col.bodyAccent||'#1e293b')+'" stroke-width="6" stroke-linecap="round"/>';
      /* грузы */
      const r1 = Math.min(20, 5 + m1*2);
      const r2 = Math.min(20, 5 + m2*2);
      s += '<circle cx="'+lx.toFixed(1)+'" cy="'+(ly+r1+3).toFixed(1)+'" r="'+r1+'" fill="'+(col.forceGravity||'#2563eb')+'" stroke="'+(col.axis||'#1e293b')+'" stroke-width="1.4"/>';
      s += '<circle cx="'+rx.toFixed(1)+'" cy="'+(ry+r2+3).toFixed(1)+'" r="'+r2+'" fill="'+(col.forceGravity||'#2563eb')+'" stroke="'+(col.axis||'#1e293b')+'" stroke-width="1.4"/>';
      /* подписи */
      s += '<text x="'+lx.toFixed(1)+'" y="'+(ly-r1-6).toFixed(1)+'" text-anchor="middle" font-size="12" font-weight="700" fill="'+(col.text||'#0f172a')+'">'+m1+' кг</text>';
      s += '<text x="'+rx.toFixed(1)+'" y="'+(ry-r2-6).toFixed(1)+'" text-anchor="middle" font-size="12" font-weight="700" fill="'+(col.text||'#0f172a')+'">'+m2+' кг</text>';
      document.getElementById('p25w-svg').innerHTML = s;
    };
    ['p25w-m1-r','p25w-l1-r','p25w-m2-r','p25w-l2-r'].forEach(id=>document.getElementById(id).addEventListener('input', upd));
    upd();
  }
}

/* ====== §26 — Простые механизмы ====== */
function add_p26(){
  const items = [
    {id:'i1', cat:'force', html:'рычаг с длинным плечом'},
    {id:'i2', cat:'force', html:'наклонная плоскость (длинная)'},
    {id:'i3', cat:'force', html:'неподвижный блок + полиспаст'},
    {id:'i4', cat:'force', html:'клин'},
    {id:'i5', cat:'dist',  html:'рычаг с коротким плечом (метла)'},
    {id:'i6', cat:'dist',  html:'педаль велосипеда'},
    {id:'i7', cat:'none',  html:'неподвижный блок (один)'},
    {id:'i8', cat:'none',  html:'жёсткий стержень'}
  ];
  const body = dndPool('p26ex', items, [
    {cat:'force', label:'Выигрыш в силе'},
    {cat:'dist',  label:'Выигрыш в скор./пути'},
    {cat:'none',  label:'Без выигрыша'}
  ]) + '<div class="actions"><button class="btn primary dnd-check">Проверить</button></div><div class="feedback dnd-fb"></div>';
  if(appendTo('p26', wgWrapper('p26-extra', 'DnD', 'Что даёт выигрыш?', 'Золотое правило: выигрываем в силе — проигрываем в расстоянии. И наоборот.', body))){
    wireDnd('p26-extra', items);
  }
}

/* ====== §27 — КПД наклонной плоскости ====== */
function add_p27(){
  const body = '<div class="sliders">'
    +'<label>$m$ груза, кг: <b id="p27w-m">10</b><input type="range" id="p27w-m-r" min="1" max="50" step="1" value="10"></label>'
    +'<label>$h$ высота, м: <b id="p27w-h">1</b><input type="range" id="p27w-h-r" min="0.2" max="3" step="0.1" value="1"></label>'
    +'<label>$\\alpha$ угол, &#176;: <b id="p27w-an">30</b><input type="range" id="p27w-an-r" min="10" max="60" step="1" value="30"></label>'
    +'<label>$\\mu$ трение: <b id="p27w-mu">0.2</b><input type="range" id="p27w-mu-r" min="0" max="0.6" step="0.05" value="0.2"></label>'
    +'</div>'
    +'<div class="score-display" style="flex-direction:column;align-items:flex-start;gap:5px">'
      +'<span>$A_{пол} = m g h$ = <b id="p27w-Apol">98</b> Дж</span>'
      +'<span>$A_{зат} = F \\cdot l$ = <b id="p27w-Azat">131</b> Дж</span>'
      +'<span>$\\eta$ = <b id="p27w-eta">75</b>%</span>'
    +'</div>';
  if(appendTo('p27', wgWrapper('p27-extra', 'CALC', 'КПД наклонной плоскости', 'Полезная работа = $mgh$. Затраченная = $F \\cdot l$, где $F$ учитывает трение.', body))){
    const upd = ()=>{
      const m = +document.getElementById('p27w-m-r').value;
      const h = +document.getElementById('p27w-h-r').value;
      const a = +document.getElementById('p27w-an-r').value;
      const mu = +document.getElementById('p27w-mu-r').value;
      document.getElementById('p27w-m').textContent = m;
      document.getElementById('p27w-h').textContent = h.toFixed(1);
      document.getElementById('p27w-an').textContent = a;
      document.getElementById('p27w-mu').textContent = mu.toFixed(2);
      const g = 9.8;
      const l = h / Math.sin(a*PI/180);
      const F = m*g*(Math.sin(a*PI/180) + mu*Math.cos(a*PI/180));
      const Apol = m*g*h;
      const Azat = F*l;
      const eta = (Apol/Azat)*100;
      document.getElementById('p27w-Apol').textContent = Apol.toFixed(0);
      document.getElementById('p27w-Azat').textContent = Azat.toFixed(0);
      document.getElementById('p27w-eta').textContent = eta.toFixed(0);
    };
    ['p27w-m-r','p27w-h-r','p27w-an-r','p27w-mu-r'].forEach(id=>document.getElementById(id).addEventListener('input', upd));
    upd();
  }
}

/* ====== §28 — Виды равновесия ====== */
function add_p28(){
  const items = [
    {id:'i1', cat:'st',  html:'шар в углублении'},
    {id:'i2', cat:'st',  html:'маятник в нижней точке'},
    {id:'i3', cat:'st',  html:'столб с широким основанием'},
    {id:'i4', cat:'un',  html:'шар на вершине горы'},
    {id:'i5', cat:'un',  html:'карандаш на остром конце'},
    {id:'i6', cat:'un',  html:'пирамида на вершине'},
    {id:'i7', cat:'in',  html:'шар на горизонтальном столе'},
    {id:'i8', cat:'in',  html:'цилиндр на ровной поверхности'}
  ];
  const body = dndPool('p28ex', items, [
    {cat:'st', label:'Устойчивое'},
    {cat:'un', label:'Неустойчивое'},
    {cat:'in', label:'Безразличное'}
  ]) + '<div class="actions"><button class="btn primary dnd-check">Проверить</button></div><div class="feedback dnd-fb"></div>';
  if(appendTo('p28', wgWrapper('p28-extra', 'DnD', 'Вид равновесия', 'Устойчивое — возврат, неустойчивое — уход, безразличное — без изменений.', body))){
    wireDnd('p28-extra', items);
  }
}

/* ====== §29 — Закон Архимеда ====== */
function add_p29(){
  const body = '<div class="sliders">'
    +'<label>$V$ тела, см³: <b id="p29w-V">100</b><input type="range" id="p29w-V-r" min="10" max="1000" step="10" value="100"></label>'
    +'<label>Жидкость: <select id="p29w-liq" class="tinp" style="width:auto;padding:6px 10px"><option value="1000">вода (1000)</option><option value="800">керосин (800)</option><option value="13600">ртуть (13600)</option><option value="789">спирт (789)</option></select></label>'
    +'<label>$\\rho_{тела}$, кг/м³: <b id="p29w-rt">500</b><input type="range" id="p29w-rt-r" min="100" max="15000" step="100" value="500"></label>'
    +'</div>'
    +'<div class="score-display" style="flex-direction:column;align-items:flex-start;gap:5px">'
      +'<span>$F_A = \\rho g V$ = <b id="p29w-Fa">0.98</b> Н</span>'
      +'<span>Вес тела $P$ = <b id="p29w-P">0.49</b> Н</span>'
      +'<span><b id="p29w-result" style="color:var(--ok)">ПЛАВАЕТ ↑</b></span>'
    +'</div>';
  if(appendTo('p29', wgWrapper('p29-extra', 'CALC', 'Закон Архимеда', '$F_A = \\rho g V$. Сравни с весом тела.', body))){
    const upd = ()=>{
      const V_cm3 = +document.getElementById('p29w-V-r').value;
      const V = V_cm3 * 1e-6;
      const rho_l = +document.getElementById('p29w-liq').value;
      const rho_t = +document.getElementById('p29w-rt-r').value;
      document.getElementById('p29w-V').textContent = V_cm3;
      document.getElementById('p29w-rt').textContent = rho_t;
      const g = 9.8;
      const Fa = rho_l*g*V;
      const P = rho_t*g*V;
      document.getElementById('p29w-Fa').textContent = Fa.toFixed(2);
      document.getElementById('p29w-P').textContent = P.toFixed(2);
      const r = document.getElementById('p29w-result');
      if(Math.abs(Fa-P) < 0.01){ r.innerHTML = 'ВИСИТ В ТОЛЩЕ →'; r.style.color = 'var(--muted)'; }
      else if(Fa > P){ r.innerHTML = 'ПЛАВАЕТ ↑'; r.style.color = 'var(--ok,#10b981)'; }
      else { r.innerHTML = 'ТОНЕТ ↓'; r.style.color = 'var(--fail,#dc2626)'; }
    };
    ['p29w-V-r','p29w-liq','p29w-rt-r'].forEach(id=>document.getElementById(id).addEventListener('input', upd));
    document.getElementById('p29w-liq').addEventListener('change', upd);
    upd();
  }
}

/* ====== §30 — Плотности жидкостей по возрастанию ====== */
function add_p30(){
  const items = [
    {id:'i1', cat:'r1', html:'спирт ($789$)'},
    {id:'i2', cat:'r2', html:'керосин ($800$)'},
    {id:'i3', cat:'r3', html:'вода ($1000$)'},
    {id:'i4', cat:'r4', html:'морская вода ($1030$)'},
    {id:'i5', cat:'r5', html:'ртуть ($13600$)'}
  ];
  const body = dndPool('p30ex', items, [
    {cat:'r1', label:'$<800$'},
    {cat:'r2', label:'$800–999$'},
    {cat:'r3', label:'$1000–1029$'},
    {cat:'r4', label:'$1030–1500$'},
    {cat:'r5', label:'$>10000$'}
  ]) + '<div class="actions"><button class="btn primary dnd-check">Проверить</button></div><div class="feedback dnd-fb"></div>';
  if(appendTo('p30', wgWrapper('p30-extra', 'DnD', 'Плотности жидкостей (кг/м³)', 'Расставь жидкости по группам плотности.', body))){
    wireDnd('p30-extra', items);
  }
}

window.PHYS9_CH3_WIDGETS = { p25:add_p25, p26:add_p26, p27:add_p27, p28:add_p28, p29:add_p29, p30:add_p30 };

})();
