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;});