
// index.js — Obfuscator logic
(function(){
  'use strict';
  // helpers
  function u8ToBase64(u8){ return btoa(String.fromCharCode.apply(null, u8)); }
  function base64ToU8(b64){ return Uint8Array.from(atob(b64), c=>c.charCodeAt(0)); }
  function strToU8(s){ return new TextEncoder().encode(s); }
  function u8ToStr(u){ return new TextDecoder().decode(u); }
  function escapeForTemplateLiteral(s){ return s.replace(/\\/g,'\\\\').replace(/`/g,'\\`').replace(/\$\{/g,'\\${').replace(/<\/script>/gi,'<\\/script>'); }
  function makeNoise(len){ const pool=['･','•','·','⁂','✦','※','▦','—','~','`','°','¤']; let r=''; for(let i=0;i<len;i++) r+=pool[Math.floor(Math.random()*pool.length)]; return r; }

  // build runnable HTML (safe embedding)
  function buildRunnableHtml(originalHtml, opts){
    try{
      const doc = new DOMParser().parseFromString(originalHtml,'text/html');
      const scripts = Array.from(doc.querySelectorAll('script'));
      const inline = [], ext = [];
      scripts.forEach(s=>{ if(s.src && s.src.trim()) ext.push(s.src); else inline.push(s.textContent||''); s.parentNode && s.parentNode.removeChild(s); });
      const bodyHtml = doc.body ? doc.body.innerHTML : originalHtml;
      const bodyB64 = u8ToBase64(strToU8(bodyHtml));
      const inlineB64 = inline.map(s=>u8ToBase64(strToU8(s||'')));
      const safeBody = escapeForTemplateLiteral(bodyB64);
      const safeInline = inlineB64.map(b=>escapeForTemplateLiteral(b));
      const extJson = JSON.stringify(ext);
      let loader = `(function(){try{function b64ToStr(b){return decodeURIComponent(escape(atob(b)));}var body=b64ToStr(\`${safeBody}\`);document.open();document.write(body);document.close();var ext=${extJson};for(var i=0;i<ext.length;i++){var s=document.createElement('script');s.src=ext[i];document.body.appendChild(s);} `;
      for(let i=0;i<safeInline.length;i++){ if(opts.noise) loader += `/*${makeNoise(5)}*/`; loader += `try{var code=atob(\`${safeInline[i]}\`);(new Function(code))();}catch(e){console.error('inline exec err',e);} `; }
      loader += `}catch(e){console.error('loader err', e);} })();`;
      loader = loader.replace(/<\/script>/gi,'<\\/script>');
      const final = '<!doctype html>\n<html>\n<head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Protected (obf)</title></head>\n<body>\n<script>' + loader.replace(/<\\/script>/g,'<\\\\/script>') + '<\\/script>\n</body>\n</html>';
      return final;
    }catch(e){ console.error('buildRunnableHtml failed', e); return null; }
  }

  function obfuscateTextPlain(txt, opts){
    const chunk = 64; const parts = [];
    for(let i=0;i<txt.length;i+=chunk) parts.push(btoa(unescape(encodeURIComponent(txt.slice(i,i+chunk)))));
    const delim = ':::' + Date.now().toString(36) + ':::';
    let out = '';
    for(let i=0;i<parts.length;i++){ out += parts[i]; out += opts.noise ? (delim + makeNoise(6) + delim) : delim; }
    return 'MINZX-OBF-PLAIN\n' + JSON.stringify({chunks:parts.length, noise:!!opts.noise}) + '\n---PAYLOAD---\n' + out;
  }

  // UI wiring with robust attach
  function attachHandlers(){
    const fileInput = document.getElementById('fileInput');
    const textInput = document.getElementById('textInput');
    const outName = document.getElementById('outName');
    const modeSel = document.getElementById('mode');
    const obfBtn = document.getElementById('obfBtn');
    const clearBtn = document.getElementById('clearBtn');
    const status = document.getElementById('status');
    const copyBtn = document.getElementById('copyBtn');
    const downloadBtn = document.getElementById('downloadBtn');
    const previewBtn = document.getElementById('previewBtn');
    const previewBlock = document.getElementById('previewBlock');

    let lastResult = '', lastFilename='';

    obfBtn.addEventListener('click', async ()=>{
      try{
        status.textContent = 'Preparing...'; previewBlock.style.display='none'; lastResult=''; lastFilename='';
        let arrayBuffer = null; let filename = (outName.value||'').trim();
        if(fileInput.files && fileInput.files.length > 0){
          const f = fileInput.files[0]; filename = filename || f.name; arrayBuffer = await f.arrayBuffer();
        } else if(textInput.value && textInput.value.trim().length > 0){
          const txt = textInput.value; arrayBuffer = new TextEncoder().encode(txt).buffer; filename = filename || 'pasted.txt';
        } else { alert('Paste teks atau pilih file dulu'); status.textContent='No input.'; return; }
        const mode = modeSel.value; const opts = {noise:true};
        if(mode === 'html'){
          const ext = (filename.split('.').pop()||'').toLowerCase();
          const isHtml = (ext==='html'||ext==='htm');
          let originalText = '';
          if(isHtml) originalText = new TextDecoder().decode(new Uint8Array(arrayBuffer));
          else {
            const scriptText = new TextDecoder().decode(new Uint8Array(arrayBuffer));
            originalText = '<!doctype html><html><head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width,initial-scale=1\"></head><body><script>' + scriptText.replace(/<\/script>/gi,'<\\/script>') + '<\\/script></body></html>';
          }
          status.textContent = 'Obfuscating HTML...';
          await new Promise(r=>setTimeout(r,20));
          const resultHtml = buildRunnableHtml(originalText, opts);
          if(!resultHtml){ status.textContent = 'Failed to obfuscate HTML.'; return; }
          lastResult = resultHtml;
          lastFilename = (filename ? filename.replace(/\.(html|htm)$/i,'') : 'protected') + '.obf.html';
          status.textContent = 'Done — obfuscated HTML ready.'; previewBlock.style.display='block'; previewBlock.textContent = resultHtml.slice(0,2000) + '\n\n... (truncated)';
        } else {
          const txt = new TextDecoder().decode(new Uint8Array(arrayBuffer));
          status.textContent = 'Obfuscating text...';
          await new Promise(r=>setTimeout(r,20));
          const obf = obfuscateTextPlain(txt, {noise:true});
          lastResult = obf; lastFilename = (filename ? filename + '.obf.txt' : 'text.obf.txt');
          status.textContent = 'Done — obfuscated text ready.'; previewBlock.style.display='block'; previewBlock.textContent = obf.slice(0,2000) + '\n\n... (truncated)';
        }
      }catch(e){
        console.error(e);
        status.textContent = 'Error: ' + (e && e.message ? e.message : String(e));
      }
    });

    clearBtn.addEventListener('click', ()=>{ fileInput.value=''; textInput.value=''; outName.value=''; status.textContent='Cleared.'; previewBlock.style.display='none'; previewBlock.textContent=''; lastResult=''; lastFilename=''; });

    copyBtn.addEventListener('click', async ()=>{ if(!lastResult){ alert('No result'); return; } try{ await navigator.clipboard.writeText(lastResult); status.textContent='Copied.'; }catch(e){ status.textContent='Copy failed.'; } });

    downloadBtn.addEventListener('click', ()=>{ if(!lastResult){ alert('No result'); return; } const blob = new Blob([lastResult], {type:'text/plain;charset=utf-8'}); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = lastFilename || 'result.obf.txt'; document.body.appendChild(a); a.click(); a.remove(); setTimeout(()=>URL.revokeObjectURL(url),2000); status.textContent='Download started.'; });

    previewBtn.addEventListener('click', ()=>{ if(!lastResult){ alert('No result'); return; } const w = window.open(); if(!w){ alert('Popup blocked'); return; } if(lastResult.trim().startsWith('<!doctype') || lastResult.trim().startsWith('<html')){ w.document.open(); w.document.write(lastResult); w.document.close(); } else { w.document.body.style.background='#111'; const pre = w.document.createElement('pre'); pre.style.whiteSpace='pre-wrap'; pre.style.color='#9f9'; pre.style.fontFamily='monospace'; pre.textContent = lastResult; w.document.body.appendChild(pre); } });

    // expose for testing
    window.__MINZX_LAST = { getResult: ()=> lastResult, getFilename: ()=> lastFilename };
  }

  // ensure attach after DOM ready
  if(document.readyState === 'loading') document.addEventListener('DOMContentLoaded', attachHandlers);
  else setTimeout(attachHandlers, 0);
})();
