const fs = require('fs');
const vm = require('vm');
const assert = require('assert');
const source = fs.readFileSync(require('path').join(__dirname, '../src/package-mixins.js'),'utf8').replace(/^import .*;\r?\n/gm,'');
async function test(name, events, size, fail=false, throwing=false) {
  let listener, removed=0; const seen=[];
  const native = {downloadUpdate: async () => {for(const p of events) listener?.(p); if(fail) throw Error('network'); return {packageSize:size};}};
  const box = {module:{exports:{}},NativeEventEmitter:class {addListener(_,fn) {listener=fn;return {remove(){removed++;listener=null;}};}},log:()=>{}};
  vm.runInNewContext(source,box);
  const pkg={downloadUrl:'fixture',...box.module.exports(native).remote()};
  let rejected=false;
  try {await pkg.download(p=>{seen.push(p);if(throwing) throw Error('callback');});} catch {rejected=true;}
  assert.equal(removed,1,name+' release');
  assert.equal(rejected,fail||throwing,name+' propagation');
  if(!fail) assert.equal(seen.filter(p=>p.receivedBytes===p.totalBytes).length,1,name+' terminal once');
  console.log('PASS',name);
}
(async()=>{
 await test('native terminal plus JS fallback',[{receivedBytes:0,totalBytes:10},{receivedBytes:10,totalBytes:10}],10);
 await test('duplicate native terminal',[{receivedBytes:10,totalBytes:10},{receivedBytes:10,totalBytes:10}],10);
 await test('native terminal absent',[],10);
 await test('empty download',[],0);
 await test('download rejected',[],10,true);
 await test('callback throws',[],10,false,true);
})().catch(e=>{console.error(e);process.exitCode=1;});