function applyTheme(){
  const saved=localStorage.getItem('qr-theme')||'auto';
  document.documentElement.dataset.theme=saved;
  document.querySelectorAll('[data-theme-toggle]').forEach(b=>b.textContent=saved==='dark'?'Light Mode':'Dark Mode');
}
function loadImage(src){return new Promise((resolve,reject)=>{if(!src) return resolve(null); const img=new Image(); img.onload=()=>resolve(img); img.onerror=reject; img.src=src;});}
function drawLogo(canvas,img){
  if(!img) return;
  const ctx=canvas.getContext('2d');
  const size=canvas.width;
  const box=Math.round(size*0.22);
  const pad=Math.round(size*0.025);
  const x=Math.round((size-box)/2), y=x;
  ctx.fillStyle='#ffffff';
  ctx.beginPath(); ctx.roundRect(x-pad,y-pad,box+pad*2,box+pad*2,Math.round(size*0.035)); ctx.fill();
  const scale=Math.min(box/img.width,box/img.height);
  const w=Math.round(img.width*scale), h=Math.round(img.height*scale);
  ctx.drawImage(img,Math.round((size-w)/2),Math.round((size-h)/2),w,h);
}
async function renderQr(el){
  if(typeof QRCode==='undefined'){
    const msg=document.createElement('p'); msg.className='notice'; msg.textContent='QR-Bibliothek konnte nicht geladen werden. Bitte Internetverbindung/CDN-Zugriff pruefen oder die Bibliothek lokal einbinden.'; el.replaceWith(msg); return;
  }
  const text=el.dataset.text; const fg=el.dataset.fg||'#000000'; const bg=el.dataset.transparent==='1'?'#00000000':(el.dataset.bg||'#ffffff'); const size=parseInt(el.getAttribute('width')||el.clientWidth||256,10);
  QRCode.toCanvas(el, text, {width:size,margin:2,color:{dark:fg,light:bg},errorCorrectionLevel:el.dataset.logo?'H':'M'}, async err=>{
    if(err){const msg=document.createElement('p'); msg.className='notice'; msg.textContent='QR-Code konnte nicht erzeugt werden: '+err.message; el.replaceWith(msg); return;}
    try{drawLogo(el, await loadImage(el.dataset.logo));}catch(e){console.warn('Logo konnte nicht geladen werden',e);}
  });
}
async function canvasSvgWithLogo(canvas, baseSvg){
  if(!canvas.dataset.logo) return baseSvg;
  const dataUrl = await imageToDataUrl(canvas.dataset.logo);
  const size=parseInt(canvas.getAttribute('width')||256,10);
  const box=Math.round(size*0.22); const pad=Math.round(size*0.025); const x=Math.round((size-box)/2); const y=x;
  const insert=`<rect x="${x-pad}" y="${y-pad}" width="${box+pad*2}" height="${box+pad*2}" rx="${Math.round(size*0.035)}" fill="#ffffff"/><image href="${dataUrl}" x="${x}" y="${y}" width="${box}" height="${box}" preserveAspectRatio="xMidYMid meet"/>`;
  return baseSvg.replace('</svg>',insert+'</svg>');
}
function imageToDataUrl(src){return new Promise((resolve,reject)=>{const img=new Image(); img.onload=()=>{const c=document.createElement('canvas'); c.width=img.width; c.height=img.height; c.getContext('2d').drawImage(img,0,0); resolve(c.toDataURL('image/png'));}; img.onerror=reject; img.src=src;});}
async function makeDownload(canvas, type, name){
  if(!canvas || canvas.tagName.toLowerCase()!=='canvas') return alert('QR-Code ist noch nicht bereit.');
  if(typeof QRCode==='undefined') return alert('QR-Bibliothek konnte nicht geladen werden.');
  if(type==='svg'){
    QRCode.toString(canvas.dataset.text,{type:'svg',margin:2,color:{dark:canvas.dataset.fg||'#000',light:canvas.dataset.transparent==='1'?'#00000000':(canvas.dataset.bg||'#fff')},errorCorrectionLevel:canvas.dataset.logo?'H':'M'},async (err,svg)=>{
      if(err) return alert(err.message||err); try{svg=await canvasSvgWithLogo(canvas,svg);}catch(e){} const blob=new Blob([svg],{type:'image/svg+xml'}); saveBlob(blob,name+'.svg');
    }); return;
  }
  const mime=type==='jpg'?'image/jpeg':'image/png'; canvas.toBlob(blob=>saveBlob(blob,name+'.'+(type==='jpg'?'jpg':'png')),mime,0.95);
}
function saveBlob(blob, filename){const a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=filename;document.body.appendChild(a);a.click();a.remove();setTimeout(()=>URL.revokeObjectURL(a.href),1000)}
document.addEventListener('DOMContentLoaded',()=>{
  applyTheme();
  document.querySelectorAll('[data-theme-toggle]').forEach(btn=>btn.addEventListener('click',()=>{const cur=localStorage.getItem('qr-theme')||'auto';localStorage.setItem('qr-theme',cur==='dark'?'light':'dark');applyTheme();}));
  document.querySelectorAll('canvas.qr').forEach(renderQr);
  document.querySelectorAll('[data-download]').forEach(btn=>btn.addEventListener('click',()=>{const c=document.querySelector(btn.dataset.target);makeDownload(c,btn.dataset.download,btn.dataset.name||'qr-code')}));
});

// v8.5: mobile sidebar, live QR preview and nicer colour controls
function debounce(fn, wait){let t; return (...args)=>{clearTimeout(t); t=setTimeout(()=>fn(...args),wait);};}
function normaliseHex(v){v=(v||'').trim(); if(!v.startsWith('#')) v='#'+v; return /^#[0-9a-fA-F]{6}$/.test(v)?v.toUpperCase():null;}
async function renderLivePreview(form){
  const canvas=document.getElementById('qr-live'); if(!canvas || typeof QRCode==='undefined') return;
  const base=form.dataset.baseUrl||'';
  const slug=(form.querySelector('[name="custom_slug"]')?.value||'').trim() || form.dataset.currentCode || 'vorschau';
  const fg=form.querySelector('[name="foreground_color"]')?.value || '#000000';
  const bg=form.querySelector('[name="background_color"]')?.value || '#FFFFFF';
  const transparent=form.querySelector('[name="transparent_background"]')?.checked;
  const removeLogo=form.querySelector('[name="remove_logo"]')?.checked;
  const file=form.querySelector('[name="logo"]')?.files?.[0];
  const text=base+slug;
  canvas.dataset.text=text; canvas.dataset.fg=fg; canvas.dataset.bg=bg; canvas.dataset.transparent=transparent?'1':'0';
  let logoSrc='';
  if(file){logoSrc=URL.createObjectURL(file);} else if(!removeLogo && form.dataset.logoCurrent){logoSrc=form.dataset.logoCurrent;}
  canvas.dataset.logo=logoSrc;
  const out=document.querySelector('[data-live-url]'); if(out) out.textContent=text;
  await new Promise(resolve=>QRCode.toCanvas(canvas,text,{width:320,margin:2,color:{dark:fg,light:transparent?'#00000000':bg},errorCorrectionLevel:logoSrc?'H':'M'},()=>resolve()));
  try{drawLogo(canvas, await loadImage(logoSrc));}catch(e){}
  if(file && logoSrc) setTimeout(()=>URL.revokeObjectURL(logoSrc),2000);
}
document.addEventListener('DOMContentLoaded',()=>{
  const toggle=document.querySelector('[data-menu-toggle]');
  const overlay=document.querySelector('[data-menu-overlay]');
  const closeMenu=()=>{document.body.classList.remove('menu-open'); if(toggle) toggle.setAttribute('aria-expanded','false');};
  if(toggle){toggle.addEventListener('click',()=>{const open=!document.body.classList.contains('menu-open');document.body.classList.toggle('menu-open',open);toggle.setAttribute('aria-expanded',open?'true':'false');});}
  if(overlay) overlay.addEventListener('click',closeMenu);
  document.querySelectorAll('.side-nav a,.logout-link').forEach(a=>a.addEventListener('click',closeMenu));

  document.querySelectorAll('[data-color-hex]').forEach(hex=>{
    const color=document.querySelector('[name="'+hex.dataset.colorHex+'"]');
    if(!color) return;
    color.addEventListener('input',()=>{hex.value=color.value.toUpperCase();});
    hex.addEventListener('change',()=>{const v=normaliseHex(hex.value); if(v){color.value=v; hex.value=v; color.dispatchEvent(new Event('input',{bubbles:true}));} else {hex.value=color.value.toUpperCase();}});
  });
  document.querySelectorAll('[data-qr-editor]').forEach(form=>{
    const update=debounce(()=>renderLivePreview(form),120);
    form.querySelectorAll('input,select').forEach(el=>el.addEventListener('input',update));
    form.querySelectorAll('input,select').forEach(el=>el.addEventListener('change',update));
    renderLivePreview(form);
  });
});

// v11: statistics selection helpers
// Keeps the statistics screen usable without losing form state.
document.addEventListener('DOMContentLoaded',()=>{
  document.querySelectorAll('[data-check-all]').forEach(master=>{
    const selector=master.dataset.checkAll;
    const items=()=>Array.from(document.querySelectorAll(selector));
    master.addEventListener('change',()=>items().forEach(cb=>{cb.checked=master.checked;}));
    items().forEach(cb=>cb.addEventListener('change',()=>{
      const all=items();
      master.checked=all.length>0 && all.every(x=>x.checked);
      master.indeterminate=all.some(x=>x.checked) && !master.checked;
    }));
  });
  document.querySelectorAll('[data-uncheck-all]').forEach(btn=>{
    btn.addEventListener('click',()=>{
      document.querySelectorAll(btn.dataset.uncheckAll).forEach(cb=>{cb.checked=false;});
      document.querySelectorAll('[data-check-all]').forEach(cb=>{cb.checked=false;cb.indeterminate=false;});
    });
  });
});

// v14: password visibility toggle
// Handles multiple password fields on one form.
document.addEventListener('DOMContentLoaded',()=>{
  document.querySelectorAll('[data-password-toggle-button]').forEach(btn=>{
    const wrap=btn.closest('.password-field');
    const input=wrap ? wrap.querySelector('[data-password-toggle]') : null;
    if(!input) return;
    btn.addEventListener('click',()=>{
      const show=input.type==='password';
      input.type=show?'text':'password';
      btn.classList.toggle("is-visible", show);
      btn.setAttribute("aria-pressed",show?"true":"false");
      btn.setAttribute("aria-label",show?"Passwort verbergen":"Passwort anzeigen");
      input.focus();
    });
  });
});

// v18: show logo preloader while forms and normal navigation process
(function(){
  const showLoader=()=>{const p=document.querySelector('[data-preloader]'); if(p){p.classList.add('is-active'); p.setAttribute('aria-hidden','false');}};
  const hideLoader=()=>{const p=document.querySelector('[data-preloader]'); if(p){p.classList.remove('is-active'); p.setAttribute('aria-hidden','true');}};
  window.addEventListener('pageshow',hideLoader);
  document.addEventListener('DOMContentLoaded',()=>{
    document.querySelectorAll('form').forEach(form=>form.addEventListener('submit',()=>showLoader()));
    document.addEventListener('click',(event)=>{
      const link=event.target.closest('a');
      if(!link) return;
      const href=link.getAttribute('href')||'';
      if(!href || href.startsWith('#') || href.startsWith('mailto:') || href.startsWith('tel:') || link.target==='_blank' || link.hasAttribute('download')) return;
      showLoader();
    });
  });
})();

// v19.1: CSP-friendly form actions
// Replaces inline onchange/onsubmit handlers with data attributes.
document.addEventListener('DOMContentLoaded',()=>{
  document.querySelectorAll('[data-submit-on-change]').forEach(el=>{
    el.addEventListener('change',()=>{ if(el.form) el.form.submit(); });
  });
  document.querySelectorAll('form[data-confirm]').forEach(form=>{
    form.addEventListener('submit',(event)=>{
      const message=form.getAttribute('data-confirm') || 'Aktion wirklich ausführen?';
      if(!window.confirm(message)) event.preventDefault();
    });
  });
  document.querySelectorAll('.chart-bar span[data-height]').forEach(el=>{
    const h=parseInt(el.getAttribute('data-height')||'0',10);
    if(h>0) el.style.height=h+'px';
  });
});


// v19.2: show password confirmation on account profile changes
// Name and e-mail changes must be confirmed with the current password.
document.addEventListener('DOMContentLoaded',()=>{
  document.querySelectorAll('[data-account-form]').forEach(form=>{
    const box=form.querySelector('[data-account-password]');
    const password=box ? box.querySelector('input[name="current_password"]') : null;
    const watched=Array.from(form.querySelectorAll('input[data-original-value]'));
    if(!box || !password || !watched.length) return;
    const sync=()=>{
      const changed=watched.some(input=>(input.value||'').trim() !== (input.dataset.originalValue||'').trim());
      box.hidden=!changed;
      password.required=changed;
      if(!changed) password.value='';
    };
    watched.forEach(input=>input.addEventListener('input',sync));
    watched.forEach(input=>input.addEventListener('change',sync));
    sync();
  });
});

// v20: dashboard live full-text filtering within the server-side access scope.
// The server renders only QR codes the current user may see; this client-side filter never broadens access.
document.addEventListener('DOMContentLoaded',()=>{
  document.querySelectorAll('[data-dashboard-filter]').forEach(form=>{
    const input=form.querySelector('[data-dashboard-search]');
    const table=document.querySelector('[data-dashboard-table]');
    if(!input || !table) return;
    const rows=Array.from(table.querySelectorAll('[data-dashboard-row]'));
    const empty=table.querySelector('[data-dashboard-empty]');
    const normalise=(value)=>(value||'').toString().trim().toLocaleLowerCase('de-CH');
    const filter=()=>{
      const terms=normalise(input.value).split(/\s+/).filter(Boolean);
      let visible=0;
      rows.forEach(row=>{
        const haystack=row.getAttribute('data-search')||'';
        const show=terms.every(term=>haystack.includes(term));
        row.hidden=!show;
        if(show) visible++;
      });
      if(empty) empty.hidden=visible!==0 || rows.length===0;
    };
    input.addEventListener('input',filter);
    filter();
  });
});
