/* EireneEduCloud — HTML5 learning games engine
   Eirene Technologies Limited
   Data-driven interactive games (pure JS/HTML — offline, no external files):
     match  : match terms to definitions
     sort   : drag/tap items into the correct category
     order  : arrange items into the correct sequence
     fill   : tap word-bank words into the blanks
     flash  : flip flashcards
   A lesson references a game by a { type, ... } object. */
(function (w, d) {
  function esc(s){ return (s==null?'':String(s)).replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;'); }
  function shuffle(a){ a=a.slice(); for(var i=a.length-1;i>0;i--){ var j=Math.floor(((i*9301+49297)%233280)/233280*(i+1)); var t=a[i];a[i]=a[j];a[j]=t;} return a; }
  function el(tag,cls,html){ var e=d.createElement(tag); if(cls)e.className=cls; if(html!=null)e.innerHTML=html; return e; }

  var Games = {
    mount: function(host, game){
      if(!host||!game) return;
      host.innerHTML='';
      var head=el('div','game-head','<span class="game-ic">🎮</span><strong>'+esc(game.title||'Learning game')+'</strong>');
      host.appendChild(head);
      if(game.instructions) host.appendChild(el('p','muted game-instr',esc(game.instructions)));
      var board=el('div','game-board'); host.appendChild(board);
      var result=el('div','game-result'); host.appendChild(result);
      var fn=this['_'+(game.type||'match')]||this._match;
      fn.call(this, board, result, game);
    },

    _done:function(result,msg,ok){ result.className='game-result show '+(ok?'ok':'no'); result.innerHTML=msg; },

    // ---- MATCH: click a term then its definition ----
    _match:function(board,result,game){
      var pairs=(game.pairs||[]).slice(0,8);
      var left=pairs.map(function(p,i){return {t:p.a,i:i};});
      var right=shuffle(pairs.map(function(p,i){return {t:p.b,i:i};}));
      var sel=null, matched=0;
      var cols=el('div','match-cols'); board.appendChild(cols);
      var lc=el('div','match-col'), rc=el('div','match-col'); cols.appendChild(lc); cols.appendChild(rc);
      left.forEach(function(o){ var b=el('button','match-item','<span class="bullet">'+String.fromCharCode(65+o.i)+'</span>'+esc(o.t)); b.type='button'; b.dataset.i=o.i; b.dataset.side='l'; lc.appendChild(b); });
      right.forEach(function(o){ var b=el('button','match-item','<span class="bullet">•</span>'+esc(o.t)); b.type='button'; b.dataset.i=o.i; b.dataset.side='r'; rc.appendChild(b); });
      board.addEventListener('click',function(e){
        var b=e.target.closest('.match-item'); if(!b||b.classList.contains('done')) return;
        if(!sel){ if(b.dataset.side!=='l'){return;} sel=b; b.classList.add('sel'); return; }
        if(b.dataset.side!=='r'){ sel.classList.remove('sel'); sel=b.dataset.side==='l'?b:null; if(sel)sel.classList.add('sel'); return; }
        if(b.dataset.i===sel.dataset.i){ b.classList.add('done'); sel.classList.add('done'); sel.classList.remove('sel'); sel=null; matched++;
          if(matched===pairs.length) Games._done(result,'✓ All matched — well done! 🌟',true);
        } else { var s=sel; b.classList.add('wrong'); s.classList.add('wrong'); setTimeout(function(){b.classList.remove('wrong','sel');s.classList.remove('wrong','sel');},500); sel=null; }
      });
    },

    // ---- SORT: tap an item, then a category bucket ----
    _sort:function(board,result,game){
      var cats=(game.categories||[]); var items=[];
      cats.forEach(function(c,ci){ (c.items||[]).forEach(function(it){ items.push({t:it,c:ci}); }); });
      items=shuffle(items); var placed=0, total=items.length, sel=null;
      var pool=el('div','sort-pool'); board.appendChild(pool);
      items.forEach(function(o,idx){ var b=el('button','sort-item',esc(o.t)); b.type='button'; b.dataset.c=o.c; b.dataset.idx=idx; pool.appendChild(b); });
      var buckets=el('div','sort-buckets'); board.appendChild(buckets);
      cats.forEach(function(c,ci){ var bk=el('div','sort-bucket','<div class="sb-name">'+esc(c.name)+'</div>'); bk.dataset.c=ci; buckets.appendChild(bk); });
      pool.addEventListener('click',function(e){ var b=e.target.closest('.sort-item'); if(!b)return; if(sel)sel.classList.remove('sel'); sel=b; b.classList.add('sel'); });
      buckets.addEventListener('click',function(e){ var bk=e.target.closest('.sort-bucket'); if(!bk||!sel)return;
        if(bk.dataset.c===sel.dataset.c){ sel.classList.remove('sel'); sel.classList.add('done'); bk.appendChild(sel); sel=null; placed++; if(placed===total) Games._done(result,'✓ Everything sorted correctly! 🎯',true); }
        else { var s=sel; bk.classList.add('wrong'); setTimeout(function(){bk.classList.remove('wrong');},450); s.classList.remove('sel'); sel=null; }
      });
    },

    // ---- ORDER: tap items in the correct sequence ----
    _order:function(board,result,game){
      var correct=(game.items||[]); var shuffled=shuffle(correct.map(function(t,i){return {t:t,i:i};}));
      var next=0;
      var pool=el('div','order-pool'); board.appendChild(pool);
      var seq=el('div','order-seq'); board.appendChild(seq);
      shuffled.forEach(function(o){ var b=el('button','order-item',esc(o.t)); b.type='button'; b.dataset.i=o.i; pool.appendChild(b); });
      pool.addEventListener('click',function(e){ var b=e.target.closest('.order-item'); if(!b||b.classList.contains('done'))return;
        if(parseInt(b.dataset.i,10)===next){ b.classList.add('done'); var step=el('div','order-step','<b>'+(next+1)+'.</b> '+b.textContent); seq.appendChild(step); next++; if(next===correct.length) Games._done(result,'✓ Correct order! 🪜',true); }
        else { b.classList.add('wrong'); setTimeout(function(){b.classList.remove('wrong');},450); }
      });
    },

    // ---- FILL: tap word-bank words into the blanks ----
    _fill:function(board,result,game){
      var answers=(game.answers||[]); var bank=shuffle((game.bank||answers).slice());
      var parts=String(game.text||'').split('___'); var blanks=[]; var html='';
      for(var i=0;i<parts.length;i++){ html+=esc(parts[i]); if(i<parts.length-1){ html+='<span class="fill-blank" data-b="'+i+'"></span>'; } }
      var sent=el('div','fill-sentence',html); board.appendChild(sent);
      var bankEl=el('div','fill-bank'); board.appendChild(bankEl);
      bank.forEach(function(wd){ var b=el('button','fill-word',esc(wd)); b.type='button'; b.dataset.w=wd; bankEl.appendChild(b); });
      var filled=0, sel=null;
      bankEl.addEventListener('click',function(e){ var b=e.target.closest('.fill-word'); if(!b||b.classList.contains('used'))return; if(sel)sel.classList.remove('sel'); sel=b; b.classList.add('sel'); });
      sent.addEventListener('click',function(e){ var bl=e.target.closest('.fill-blank'); if(!bl||!sel||bl.classList.contains('done'))return;
        var bi=parseInt(bl.dataset.b,10);
        if(sel.dataset.w===answers[bi]){ bl.textContent=sel.dataset.w; bl.classList.add('done'); sel.classList.add('used'); sel.classList.remove('sel'); sel=null; filled++; if(filled===answers.length) Games._done(result,'✓ Sentence complete! ✍️',true); }
        else { bl.classList.add('wrong'); setTimeout(function(){bl.classList.remove('wrong');},450); }
      });
    },

    // ---- FLASH: flip flashcards ----
    _flash:function(board,result,game){
      var cards=(game.cards||[]); var idx=0;
      var card=el('div','flash-card'); board.appendChild(card);
      var ctr=el('div','flash-ctr'); board.appendChild(ctr);
      function render(){ var c=cards[idx]||{}; card.className='flash-card'; card.innerHTML='<div class="flash-face front">'+esc(c.front||'')+'</div><div class="flash-face back" hidden>'+esc(c.back||'')+'</div>';
        ctr.innerHTML='<button class="btn btn-ghost btn-sm" data-a="prev">‹ Prev</button><span class="muted">Card '+(idx+1)+' / '+cards.length+'</span><button class="btn btn-ghost btn-sm" data-a="next">Next ›</button>'; }
      card.addEventListener('click',function(){ var f=card.querySelector('.front'),b=card.querySelector('.back'); var showBack=!f.hasAttribute('hidden'); if(showBack){f.setAttribute('hidden','');b.removeAttribute('hidden');card.classList.add('flipped');} else {b.setAttribute('hidden','');f.removeAttribute('hidden');card.classList.remove('flipped');} });
      ctr.addEventListener('click',function(e){ var btn=e.target.closest('button'); if(!btn)return; if(btn.dataset.a==='next')idx=(idx+1)%cards.length; else idx=(idx-1+cards.length)%cards.length; render(); });
      render(); Games._done(result,'Tap a card to flip it. 🔁',true);
    }
  };
  w.EireneGames=Games;
})(window, document);
