// phys9_flag_base.js — общая инфраструктура для всех флагман-интерактивов Физики 9.
// Экспорт: window.PHYS9_FLAG_BASE = { register, unmount, ... }.
(function(){
'use strict';

const C = () => window.PHYS9_COLORS || {};
const _flags = {};            /* id → { init, cleanup, _raf, _mounted, _io } */

/* === Регистрация флагмана === */
function register(id, def){
  _flags[id] = Object.assign({ _raf: 0, _mounted: false, _io: null }, def);
}

/* === Размонтировать (вызывается при goTo другого §) === */
function unmount(id){
  const f = _flags[id]; if (!f) return;
  if (f._raf) { cancelAnimationFrame(f._raf); f._raf = 0; }
  if (f._io) { try { f._io.disconnect(); } catch(e){} f._io = null; }
  if (f.cleanup) try { f.cleanup(); } catch(e){}
  f._mounted = false;
}

/* === Размонтировать все === */
function unmountAll(){
  for (const id in _flags) unmount(id);
}

/* === Загрузка флагмана для секции pN === */
function mount(id, secId){
  const f = _flags[id]; if (!f) return false;
  if (f._mounted) return true;
  const ok = f.init(secId);
  if (ok !== false) f._mounted = true;
  return ok !== false;
}

/* === Обёртка SVG/canvas вставки в pN-body === */
function makeCard(secId, title, desc, body){
  const flagBox = document.createElement('div');
  flagBox.className = 'flag-card phys9-flag-' + secId;
  flagBox.innerHTML =
    '<div class="flag-title">' + title + '</div>'
    + '<div class="flag-desc">' + desc + '</div>'
    + body;
  const host = document.getElementById(secId + '-body');
  if (!host) return null;
  if (host.querySelector('.phys9-flag-' + secId)) return null;
  host.appendChild(flagBox);
  try { if(window.renderMathInElement) window.renderMathInElement(flagBox, { delimiters: [{left:'$$',right:'$$',display:true},{left:'$',right:'$',display:false}], throwOnError:false }); } catch(e){}
  return flagBox;
}

/* === Анимационный цикл с IntersectionObserver для авто-паузы === */
function startLoop(id, canvas, tick){
  const f = _flags[id]; if (!f) return;
  let visible = true;
  /* IntersectionObserver — если canvas вне экрана, паузим */
  try {
    f._io = new IntersectionObserver(entries => {
      visible = entries[0].isIntersecting;
    }, { threshold: 0.05 });
    f._io.observe(canvas);
  } catch(e){}

  let lastT = performance.now();
  function loop(now){
    const dt = Math.min(50, now - lastT) / 1000;
    lastT = now;
    if (visible) {
      try { tick(dt); } catch(e){ console.warn('phys9 flag tick:', e.message); }
    }
    f._raf = requestAnimationFrame(loop);
  }
  f._raf = requestAnimationFrame(loop);
}

/* === Высокий-DPI canvas init === */
function initCanvas(id){
  const cv = document.getElementById(id);
  if (!cv) return null;
  const dpr = window.devicePixelRatio || 1;
  const W = cv.offsetWidth || 600;
  const H = cv.offsetHeight || 400;
  cv.width = Math.round(W * dpr);
  cv.height = Math.round(H * dpr);
  const ctx = cv.getContext('2d');
  ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
  return { cv, ctx, W, H };
}

/* === Стрелка на canvas === */
function arrow(ctx, x1, y1, x2, y2, color, width){
  ctx.strokeStyle = color;
  ctx.fillStyle = color;
  ctx.lineWidth = width || 2.5;
  ctx.lineCap = 'round';
  const dx = x2 - x1, dy = y2 - y1, len = Math.hypot(dx, dy);
  if (len < 1e-3) return;
  const ux = dx/len, uy = dy/len, h = 10, hw = 6;
  const bx = x2 - ux*h, by = y2 - uy*h;
  ctx.beginPath();
  ctx.moveTo(x1, y1); ctx.lineTo(bx, by);
  ctx.stroke();
  ctx.beginPath();
  ctx.moveTo(x2, y2);
  ctx.lineTo(bx - uy*hw, by + ux*hw);
  ctx.lineTo(bx + uy*hw, by - ux*hw);
  ctx.closePath();
  ctx.fill();
}

/* === Сохранение рекорда === */
function saveRecord(key, value){
  try {
    const cur = +(localStorage.getItem('phys9_record_' + key) || -Infinity);
    if (value > cur) localStorage.setItem('phys9_record_' + key, String(value));
    return Math.max(cur, value);
  } catch(e){ return value; }
}
function getRecord(key, def){
  try { return +(localStorage.getItem('phys9_record_' + key) || (def || 0)); }
  catch(e){ return def || 0; }
}

window.PHYS9_FLAG_BASE = {
  register: register,
  mount: mount,
  unmount: unmount,
  unmountAll: unmountAll,
  makeCard: makeCard,
  initCanvas: initCanvas,
  startLoop: startLoop,
  arrow: arrow,
  saveRecord: saveRecord,
  getRecord: getRecord,
  C: C
};

/* === Хук на goTo: отменять анимации при переключении секций === */
const _origGoTo = window.goTo;
if (typeof _origGoTo === 'function') {
  window.goTo = function(id){
    unmountAll();
    return _origGoTo.apply(this, arguments);
  };
}

})();
