
// panel-core.js — core helpers + validation for standalone judge panels
(function(){
  function roundToStep(val, step){
    const n = Math.max(0, (String(step).split('.')[1]||'').length);
    return +(Math.round(val/step)*step).toFixed(n);
  }
  function bindScorepads(onChange, scope=document){
    const ranges = scope.querySelectorAll('[data-bind$="range"]');
    ranges.forEach(range => {
      const step = parseFloat(range.step || '1');
      const readout = range.closest('.score-row')?.querySelector('[data-bind]:not([data-bind$="range"])') 
                   || range.closest('.score-row')?.querySelector('.score-val');
      const update = ()=>{
        if(readout){
          readout.textContent = roundToStep(parseFloat(range.value || '0'), step);
        }
        if(typeof onChange === 'function') onChange();
      };
      range.addEventListener('input', update, {passive:true});
      update();
      const card = range.closest('.card');
      if(card){
        card.querySelectorAll('[data-nudge]').forEach(btn => btn.addEventListener('click', ()=>{
          range.value = roundToStep(parseFloat(range.value||'0') + parseFloat(btn.dataset.nudge||'0'), step);
          range.dispatchEvent(new Event('input'));
        }));
        card.querySelectorAll('[data-set]').forEach(btn => btn.addEventListener('click', ()=>{
          range.value = btn.dataset.set; range.dispatchEvent(new Event('input'));
        }));
      }
    });
    // Hold-to-submit visual (demo only)
    document.querySelectorAll('.hold').forEach(btn => {
      if(!(btn instanceof HTMLElement)) return;
      btn.addEventListener('mousedown', ()=>btn.classList.add('is-holding'));
      ['mouseup','mouseleave','touchend','touchcancel','touchmove'].forEach(ev => btn.addEventListener(ev, ()=>btn.classList.remove('is-holding')));
    });
  }

  // Read config injected from DB (if present). Two options:
  // 1) <script type="application/json" id="panel-config">{...}</script>
  // 2) data-* attributes on the .judge-panel element
  function readConfig(panel, defaults){
    let cfg = {...(defaults||{})};
    const script = document.getElementById('panel-config');
    if(script && script.textContent.trim()){
      try { const j = JSON.parse(script.textContent); cfg = {...cfg, ...j}; } catch(e){ console.warn('Invalid panel-config JSON', e); }
    }
    // data-* overrides
    const ds = panel.dataset || {};
    Object.keys(ds).forEach(k => {
      // Convert numeric-like
      const v = ds[k];
      let val = v;
      if(/^(\d+(\.\d+)?)$/.test(v)) val = parseFloat(v);
      if(v === 'true') val = true; else if(v==='false') val = false;
      cfg[k] = val;
    });
    return cfg;
  }

  function renderValidation(panel, result){
    const box = panel.querySelector('[data-role="alerts"]');
    const btn = panel.querySelector('.panel-footer .btn-primary');
    if(!box || !btn) return;
    box.innerHTML = '';
    result.errors.forEach(msg => {
      const d = document.createElement('div'); d.className = 'alert error'; d.textContent = msg; box.appendChild(d);
    });
    result.warnings.forEach(msg => {
      const d = document.createElement('div'); d.className = 'alert warn'; d.textContent = msg; box.appendChild(d);
    });
    btn.disabled = result.errors.length > 0;
    btn.title = result.errors.length ? 'Fix errors before submitting' : '';
  }

  // Diversity check helper: rules = [{group:'Direction', minDistinct:2, scope:'attempts'}]
  function diversityCheck(attemptCards, rules){
    const warnings = [];
    if(!Array.isArray(rules) || rules.length===0) return warnings;
    rules.forEach(rule => {
      const set = new Set();
      attemptCards.forEach(card => {
        // expect data-group-<GroupName> attribute or data-tags='{"GroupName":"Value"}'
        const attr = card.getAttribute('data-group-'+(rule.group||'').toLowerCase()) || '';
        if(attr) set.add(attr);
        const tagJson = card.getAttribute('data-tags');
        if(tagJson){
          try{ const obj = JSON.parse(tagJson); if(obj && obj[rule.group]) set.add(obj[rule.group]); }catch(_){}
        }
      });
      const distinct = set.size;
      if(distinct < (rule.minDistinct||0)){
        warnings.push(`Diversity: need ≥${rule.minDistinct} distinct ${rule.group} (have ${distinct}).`);
      }
    });
    return warnings;
  }

  window.PanelCore = { roundToStep, bindScorepads, readConfig, renderValidation, diversityCheck };
})();
