/* EDEN CAMPUS – game runner (no inline JS; CSP friendly) */
(function () {
  function H(h){const t=document.createElement('template');t.innerHTML=h.trim();return t.content.firstChild}
  function esc(s){return String(s).replace(/[&<>"']/g,m=>({ '&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[m]))}
  const dataNode=document.getElementById('game-data');
  const payload = dataNode ? JSON.parse(dataNode.textContent||'{}') : {};
  const type=payload.type||'fill', data=payload.data||{};

  const app=document.getElementById('app'), scoreBox=document.getElementById('score');
  const tbar=document.getElementById('tbar'), tleft=document.getElementById('tleft');
  const btnCheck=document.getElementById('btnCheck'), btnReset=document.getElementById('btnReset');

  function clean(){app.innerHTML=''; scoreBox.textContent='';}
  let build = ()=>({ok:0,tot:0});
  let initialState = null;

  /* -------- Activities (exactly like before, just moved here) -------- */
  function act_fill(){
    const wrap=H('<div style="line-height:2"></div>');
    wrap.innerHTML=String(data.text||'').replace(/\[\[(.+?)\]\]/g,(_,a)=>'<input class="slot" data-ans="'+String(a).replace(/"/g,'&quot;')+'">');
    app.append(wrap);
    return {
      check(){ let ok=0,tot=0; wrap.querySelectorAll('input').forEach(i=>{tot++; const w=(i.dataset.ans||'').trim().toLowerCase(); const g=i.value.trim().toLowerCase(); i.classList.remove('ok','bad'); if(w && g===w){ok++; i.classList.add('ok')} else i.classList.add('bad')}); scoreBox.textContent='Score '+ok+' / '+tot; return {ok,tot}; },
      reset(){ wrap.querySelectorAll('input').forEach(i=>{i.value=''; i.classList.remove('ok','bad')}); scoreBox.textContent=''; }
    }
  }
  function act_match(){
    const pairs=Array.isArray(data.pairs)?data.pairs:[]; if(!pairs.length){ app.textContent='No pairs.'; return {check(){return{ok:0,tot:0}},reset(){}}; }
    const box=H('<div></div>');
    pairs.forEach(p=>{const row=H('<div style="display:flex;gap:8px;align-items:center;margin:6px 0"></div>'); row.append(H('<div>'+String(p.left||'')+'</div>')); const s=H('<select class="slot"><option value=""></option></select>'); pairs.map(x=>x.right).forEach(r=>s.append(H('<option>'+String(r||'')+'</option>'))); s.dataset.want=String(p.right||''); row.append(s); box.append(row);});
    app.append(box);
    return {
      check(){let ok=0,tot=0; box.querySelectorAll('select').forEach(s=>{tot++; s.classList.remove('ok','bad'); if(s.value===s.dataset.want){ok++; s.classList.add('ok')} else s.classList.add('bad')}); scoreBox.textContent='Score '+ok+' / '+tot; return {ok,tot};},
      reset(){box.querySelectorAll('select').forEach(s=>{s.value=''; s.classList.remove('ok','bad')}); scoreBox.textContent='';}
    }
  }
  function act_order(){
    const items=Array.isArray(data.items)?data.items:[]; if(!items.length){app.textContent='No items.'; return {check(){return{ok:0,tot:0}},reset(){}};}
    const ul=H('<div></div>'); items.slice().sort(()=>Math.random()-.5).forEach(t=>ul.append(H('<div class="card" style="padding:8px;margin:6px 0;display:flex;align-items:center;gap:8px"><span>☰</span><div>'+esc(t)+'</div></div>'))); app.append(ul);
    let drag=null; ul.querySelectorAll('.card').forEach(li=>{
      li.draggable=true;
      li.addEventListener('dragstart', e=>{drag=li; e.dataTransfer.effectAllowed='move'});
      li.addEventListener('dragover', e=>{e.preventDefault(); const rect=li.getBoundingClientRect(); const after=(e.clientY-rect.top) > rect.height/2; ul.insertBefore(drag, after? li.nextSibling: li);});
    });
    return {
      check(){const got=[...ul.children].map(n=>n.children[1].textContent); let ok=0; for(let i=0;i<items.length;i++) if((items[i]||'')===(got[i]||'')) ok++; scoreBox.textContent='Score '+ok+' / '+items.length; return {ok,tot:items.length};},
      reset(){ ul.innerHTML=''; items.slice().sort(()=>Math.random()-.5).forEach(t=>ul.append(H('<div class="card" style="padding:8px;margin:6px 0;display:flex;align-items:center;gap:8px"><span>☰</span><div>'+esc(t)+'</div></div>'))); scoreBox.textContent='';}
    }
  }
  function act_word(){
    const box=H('<div></div>'); const p=H('<div style="line-height:2"></div>');
    p.innerHTML=String(data.text||'').replace(/\[\[(.+?)\]\]/g,()=>'<input class="slot">');
    const bank=H('<div class="bank"></div>');
    (Array.isArray(data.bank)?data.bank:[]).forEach(w=>bank.append(H('<span class="badge" data-w="'+esc(w)+'">'+esc(w)+'</span>')));
    box.append(p, bank); bank.addEventListener('click', e=>{const b=e.target.closest('.badge'); if(!b) return; const w=b.dataset.w||''; const empty=[...p.querySelectorAll('input')].find(i=>!i.value); if (empty) empty.value=w;});
    app.append(box);
    return {
      check(){ let ok=0,tot=0;
        const answers=(String(data.text||'').match(/\[\[(.+?)\]\]/g)||[]).map(s=>s.slice(2,-2).trim().toLowerCase());
        p.querySelectorAll('input').forEach((i,idx)=>{tot++; const g=i.value.trim().toLowerCase(); i.classList.remove('ok','bad'); if(g && g===answers[idx]){ok++; i.classList.add('ok')} else i.classList.add('bad')});
        scoreBox.textContent='Score '+ok+' / '+tot; return {ok,tot};
      },
      reset(){ p.querySelectorAll('input').forEach(i=>{i.value=''; i.classList.remove('ok','bad')}); scoreBox.textContent='';}
    }
  }
  function act_wordsearch(){
    const rows=+data.rows||12, cols=+data.cols||12; const words=(Array.isArray(data.words)?data.words:[]).map(w=>String(w).toUpperCase());
    const grid = Array.from({length:rows},()=>Array(cols).fill(''));
    let r=0; words.forEach(w=>{ if (r>=rows) r=0; let startCol=Math.max(0, Math.floor((cols - w.length)/2)); const rev = data.reverse && Math.random()>0.5; const S = rev ? w.split('').reverse().join('') : w; for(let i=0;i<S.length && (startCol+i)<cols;i++) grid[r][startCol+i]=S[i]; r++; });
    const ABC='ABCDEFGHIJKLMNOPQRSTUVWXYZ';
    for(let i=0;i<rows;i++) for(let j=0;j<cols;j++) if(!grid[i][j]) grid[i][j]=ABC[Math.floor(Math.random()*ABC.length)];
    const box=H('<div></div>'); const g=H('<div class="ws-grid"></div>'); g.style.gridTemplateColumns=`repeat(${cols},24px)`;
    for(let i=0;i<rows;i++) for(let j=0;j<cols;j++){ g.append(H('<div class="ws-cell" data-i="'+i+'" data-j="'+j+'">'+grid[i][j]+'</div>')); }
    const list=H('<div class="meta" style="margin-top:8px">Find: '+words.join(', ')+'</div>');
    box.append(g,list); app.append(box);
    g.addEventListener('click',e=>{const c=e.target.closest('.ws-cell'); if(!c) return; c.classList.toggle('ok');});
    return { check(){
        let ok=0, tot=words.join('').length; const want = new Set(); r=0;
        words.forEach(w=>{ if (r>=rows) r=0; let startCol=Math.max(0, Math.floor((cols - w.length)/2)); for(let i=0;i<w.length;i++) want.add(r+','+(startCol+i)); r++; });
        g.querySelectorAll('.ws-cell.ok').forEach(c=>{const k=c.dataset.i+','+c.dataset.j; if (want.has(k)) ok++;});
        scoreBox.textContent='Score '+ok+' / '+tot; return {ok,tot};
      },
      reset(){ g.querySelectorAll('.ws-cell').forEach(c=>c.classList.remove('ok')); scoreBox.textContent=''; }
    }
  }
  function act_memory(){
    const pairs=Array.isArray(data.pairs)?data.pairs:[]; if(!pairs.length){app.textContent='No pairs.';return{check(){return{ok:0,tot:0}},reset(){}};}
    const cards = pairs.flatMap(p=>[{txt:String(p.a||'')},{txt:String(p.b||'')}]).sort(()=>Math.random()-.5);
    const box=H('<div class="cardpair"></div>'); app.append(box);
    cards.forEach(c=>box.append(H('<div class="mem" data-t="'+esc(c.txt)+'">?</div>')));
    let first=null, locked=0;
    box.addEventListener('click',e=>{const m=e.target.closest('.mem'); if(!m || m.classList.contains('lock')) return;
      m.classList.add('revealed'); m.textContent=m.dataset.t;
      if (!first) { first=m; return; }
      if (first!==m){
        if (first.dataset.t===m.dataset.t) { first.classList.add('lock'); m.classList.add('lock'); locked+=2; }
        setTimeout(()=>{ if(!first.classList.contains('lock')) {first.classList.remove('revealed'); first.textContent='?'}; if(!m.classList.contains('lock')) {m.classList.remove('revealed'); m.textContent='?'}; first=null; }, 500);
      }
    });
    return { check(){ let ok=locked/2, tot=pairs.length; scoreBox.textContent='Score '+ok+' / '+tot; return {ok,tot}; },
      reset(){ box.innerHTML=''; cards.sort(()=>Math.random()-.5).forEach(c=>box.append(H('<div class="mem" data-t="'+esc(c.txt)+'">?</div>'))); locked=0; first=null; scoreBox.textContent=''; } }
  }
  function act_wheel(){
    const slices=Array.isArray(data.slices)?data.slices:['A','B','C'];
    const wrap=H('<div class="wheelwrap"></div>'); const wheel=H('<div class="wheel"></div>'); const ptr=H('<div class="pointer"></div>');
    wrap.append(ptr,wheel); app.append(wrap);
    const n=slices.length; for(let i=0;i<n;i++){ const a=i*(360/n); const s=H('<div class="slice"></div>'); s.style.transform='rotate('+a+'deg)'; const lbl=H('<div class="label">'+esc(slices[i])+'</div>'); lbl.style.transform='rotate('+(360/n/2)+'deg) translate(60px)'; s.append(lbl); wheel.append(s); }
    let spinning=false, chosen=null;
    document.getElementById('btnCheck').onclick = ()=>{ if (spinning) return; spinning=true; const spin=360*5 + Math.floor(Math.random()*360); wheel.style.transition='transform 3s cubic-bezier(.2,.6,0,1)'; wheel.style.transform='rotate('+spin+'deg)'; setTimeout(()=>{ const deg=(spin%360); const idx=(n - Math.floor((deg)/(360/n)) ) % n; chosen=slices[idx]; scoreBox.textContent='Chosen: '+chosen; spinning=false; }, 3050); };
    return { check(){ return {ok: (chosen?1:0), tot:1}; }, reset(){ wheel.style.transition='none'; wheel.style.transform='rotate(0deg)'; chosen=null; scoreBox.textContent=''; } }
  }
  function act_crossword(){
    const rows=+data.rows||12, cols=+data.cols||12; const words=Array.isArray(data.words)?data.words:[];
    const grid=Array.from({length:rows},()=>Array(cols).fill(null));
    words.forEach(w=>{ const A=String(w.answer||'').toUpperCase(); const r=(+w.row||1)-1, c=(+w.col||1)-1; const d=(String(w.dir||'across').toLowerCase()==='down')?'down':'across';
      for(let i=0;i<A.length;i++){ const rr=r+(d==='down'?i:0), cc=c+(d==='across'?i:0); if(rr<rows && cc<cols){ grid[rr][cc]=A[i]; } }
    });
    const g=H('<div class="cw-grid"></div>'); g.style.gridTemplateColumns=`repeat(${cols},28px)`;
    for(let i=0;i<rows;i++) for(let j=0;j<cols;j++){ if (grid[i][j]){ const cell=H('<div class="cw-cell"><input maxlength="1" data-ans="'+grid[i][j]+'"></div>'); g.append(cell); } else g.append(H('<div class="cw-block"></div>')); }
    const clues=H('<div class="meta" style="margin-top:8px"><b>Clues:</b><br>'+words.map(w=>esc((w.dir||'across').toUpperCase())+': '+esc(w.clue||'')).join('<br>')+'</div>');
    app.append(g, clues);
    return { check(){ let ok=0,tot=0; g.querySelectorAll('input').forEach(i=>{tot++; const w=(i.dataset.ans||'').toUpperCase(); const v=(i.value||'').toUpperCase(); i.classList.remove('ok','bad'); if(w===v){ok++; i.classList.add('ok')} else i.classList.add('bad')}); scoreBox.textContent='Score '+ok+' / '+tot; return {ok,tot}; },
      reset(){ g.querySelectorAll('input').forEach(i=>{i.value=''; i.classList.remove('ok','bad')}); scoreBox.textContent=''; } }
  }

  const map={fill:act_fill, match:act_match, order:act_order, word:act_word, wordsearch:act_wordsearch, memory:act_memory, wheel:act_wheel, crossword:act_crossword};

  function mount(){ clean(); const fn = map[type] || act_fill; const inst = fn(); build = ()=>inst.check(); initialState = ()=>inst.reset(); }
  mount();

  /* -------- Timer -------- */
  const DUR=Math.max(0, parseInt(data.duration||0,10) || 0);
  if (DUR>0){
    let t=DUR; tleft.textContent=t+'s';
    const iv=setInterval(()=>{ t=Math.max(0,t-1); tleft.textContent=t+'s'; tbar.style.width=(t*100/DUR)+'%'; if(t<=0){ clearInterval(iv); btnCheck.click(); } },1000);
  }else{ tleft.textContent='∞'; tbar.style.width='100%'; }

  /* -------- Buttons -------- */
  btnCheck.addEventListener('click', ()=>{ const {ok,tot} = build(); scoreBox.textContent = 'Score '+ok+' / '+tot; });
  btnReset.addEventListener('click', ()=>{ if (initialState) initialState(); });
})();
