(() => {
  "use strict";

  // kir0Method V2 browser engine
  // Clean-room MP4 sample-table transformation.
  // The encoded H.264 payload is preserved; no media re-encoding occurs.

  const E = new TextEncoder();
  const CONTAINER = new Set([
    "moov","trak","mdia","minf","dinf","stbl","edts","udta","meta","ilst"
  ]);

  const u32 = (a,p) => (((a[p]<<24)>>>0)|(a[p+1]<<16)|(a[p+2]<<8)|a[p+3])>>>0;
  const w32 = n => new Uint8Array([(n>>>24)&255,(n>>>16)&255,(n>>>8)&255,n&255]);
  const u64 = (a,p) => (BigInt(u32(a,p))<<32n)|BigInt(u32(a,p+4));
  const w64 = n => {
    const x=BigInt(n);
    return new Uint8Array([
      Number((x>>56n)&255n),Number((x>>48n)&255n),
      Number((x>>40n)&255n),Number((x>>32n)&255n),
      Number((x>>24n)&255n),Number((x>>16n)&255n),
      Number((x>>8n)&255n),Number(x&255n)
    ]);
  };
  const cat = parts => {
    let total=0; for(const p of parts) total+=p.length;
    const out=new Uint8Array(total); let at=0;
    for(const p of parts){out.set(p,at);at+=p.length;}
    return out;
  };
  const makeBox=(type,payload)=>cat([w32(payload.length+8),E.encode(type),payload]);
  const fourcc=(a,p)=>String.fromCharCode(a[p+4],a[p+5],a[p+6],a[p+7]);

  function parseBoxes(bytes,start=0,end=bytes.length){
    const list=[]; let p=start;
    while(p+8<=end){
      let size=u32(bytes,p), header=8;
      if(size===1){
        if(p+16>end) throw new Error("Truncated extended MP4 box");
        size=Number(u64(bytes,p+8)); header=16;
      } else if(size===0) {
        size=end-p;
      }
      if(size<header || p+size>end) throw new Error("Invalid MP4 box boundary");
      const b={type:fourcc(bytes,p),start:p,end:p+size,size,header,children:null};
      let childStart=p+header;
      if(b.type==="meta") childStart+=4;
      if(CONTAINER.has(b.type) && childStart<b.end)
        b.children=parseBoxes(bytes,childStart,b.end);
      list.push(b); p=b.end;
    }
    return list;
  }

  const raw=(a,b)=>a.subarray(b.start,b.end);
  const payload=(a,b)=>a.subarray(b.start+b.header,b.end);
  const findChild=(b,type)=>b && b.children ? b.children.find(x=>x.type===type) : null;

  function findPath(track,parts){
    let b=track;
    for(const part of parts){b=findChild(b,part);if(!b)return null;}
    return b;
  }

  function handlerType(bytes,track){
    const h=findPath(track,["mdia","hdlr"]);
    if(!h)return "";
    const p=payload(bytes,h);
    return p.length>=12?String.fromCharCode(p[8],p[9],p[10],p[11]):"";
  }

  function sampleEntry(bytes,track){
    const s=findPath(track,["mdia","minf","stbl","stsd"]);
    if(!s)return "";
    const p=payload(bytes,s);
    return p.length>=16?String.fromCharCode(p[12],p[13],p[14],p[15]):"";
  }

  function sampleSizeInfo(bytes,box){
    const p=payload(bytes,box);
    if(p.length<12) throw new Error("Malformed stsz");
    const fixed=u32(p,4), count=u32(p,8);
    if(count>5000000) throw new Error("Sample table is too large");
    return {fixed,count,p};
  }

  function sampleCountFromTiming(bytes,box){
    const p=payload(bytes,box);
    if(p.length<8) throw new Error("Malformed stts");
    const n=u32(p,4);
    let total=0;
    for(let i=0,o=8;i<n;i++,o+=8){
      if(o+8>p.length) throw new Error("Malformed stts entry");
      total += u32(p,o);
    }
    return total;
  }

  function readOffsets(bytes,box){
    const p=payload(bytes,box), n=u32(p,4);
    const wide=box.type==="co64", step=wide?8:4, out=[];
    for(let i=0,o=8;i<n;i++,o+=step){
      if(o+step>p.length) throw new Error("Malformed chunk offset table");
      out.push(wide?u64(p,o):u32(p,o));
    }
    return {count:n,wide,out};
  }

  function cloneTree(bytes,box,rewrite){
    if(!box.children) return raw(bytes,box);
    const parts=[];
    if(box.type==="meta") parts.push(payload(bytes,box).subarray(0,4));
    for(const child of box.children){
      const replacement=rewrite(child);
      if(replacement!==null) parts.push(replacement);
    }
    return makeBox(box.type,cat(parts));
  }

  function inspect(bytes){
    const top=parseBoxes(bytes);
    const moov=top.find(b=>b.type==="moov");
    const mdat=top.find(b=>b.type==="mdat");
    if(!moov||!mdat) throw new Error("Input must contain moov and mdat");

    const tracks=(moov.children||[]).filter(b=>b.type==="trak");
    const video=tracks.find(t=>handlerType(bytes,t)==="vide");
    const audio=tracks.find(t=>handlerType(bytes,t)==="soun");
    const audioStbl=audio&&findPath(audio,["mdia","minf","stbl"]);
    const videoStbl=video&&findPath(video,["mdia","minf","stbl"]);
    const audioStsz=audioStbl&&findChild(audioStbl,"stsz");
    const videoStsz=videoStbl&&findChild(videoStbl,"stsz");

    return {
      top,moov,mdat,video,audio,
      audioCodec:audio?sampleEntry(bytes,audio):"",
      videoCodec:video?sampleEntry(bytes,video):"",
      audioStbl,videoStbl,
      audioSamples:audioStsz?sampleSizeInfo(bytes,audioStsz).count:0,
      videoSamples:videoStsz?sampleSizeInfo(bytes,videoStsz).count:0
    };
  }

  // Place moov before mdat while preserving chunk references.
  function normalize(bytes){
    const top=parseBoxes(bytes);
    const ftyp=top.find(b=>b.type==="ftyp");
    const moov=top.find(b=>b.type==="moov");
    const mdat=top.find(b=>b.type==="mdat");
    if(!moov||!mdat) throw new Error("Missing moov/mdat");

    const media=bytes.subarray(mdat.start+mdat.header,mdat.end);
    const f=ftyp?raw(bytes,ftyp):new Uint8Array();
    const oldMediaStart=mdat.start+mdat.header;

    const shiftTree=(box,delta)=>{
      if(box.type==="stco"||box.type==="co64"){
        const p=payload(bytes,box), n=u32(p,4), wide=box.type==="co64", step=wide?8:4;
        const out=new Uint8Array(p);
        for(let i=0,o=8;i<n;i++,o+=step){
          const old=wide?u64(p,o):BigInt(u32(p,o));
          const next=old+BigInt(delta);
          if(next<0n) throw new Error("Normalized chunk offset became negative");
          if(!wide && next>0xffffffffn) throw new Error("Normalized MP4 needs 64-bit chunk offsets");
          out.set(wide?w64(next):w32(Number(next)),o);
        }
        return makeBox(box.type,out);
      }
      return box.children ? cloneTree(bytes,box,c=>shiftTree(c,delta)) : raw(bytes,box);
    };

    const firstMoov=shiftTree(moov,0);
    const newMediaStart=f.length+firstMoov.length+8;
    const delta=newMediaStart-oldMediaStart;
    const finalMoov=shiftTree(moov,delta);

    return cat([f,finalMoov,makeBox("mdat",media)]);
  }

  // Replace the audio sample-count/size/chunk description with an expanded
  // table while keeping the encoded media payload untouched.
  function expandAudio(bytes){
    const info=inspect(bytes);
    if(info.audioCodec!=="mp4a") throw new Error("kir0Method requires an AAC audio track");

    const stbl=info.audioStbl;
    const stts=findChild(stbl,"stts");
    const stsz=findChild(stbl,"stsz");
    const stsc=findChild(stbl,"stsc");
    const offsetBox=findChild(stbl,"stco")||findChild(stbl,"co64");
    if(!stts||!stsz||!stsc||!offsetBox) throw new Error("AAC sample tables are incomplete");

    const sz=sampleSizeInfo(bytes,stsz);
    const timed=sampleCountFromTiming(bytes,stts);
    if(timed!==sz.count) throw new Error("AAC timing table does not match sample table");

    const factor=10;
    const added=sz.count*(factor-1);
    if(added>5000000) throw new Error("Source is too large for this local transformation");

    const chunkInfo=readOffsets(bytes,offsetBox);
    const oldCount=sz.count;

    const newStsz=()=>{
      const p=payload(bytes,stsz);
      const out=new Uint8Array(12+(oldCount+added)*4);
      out.set(p.subarray(0,4),0);
      out.set(w32(0),4);
      out.set(w32(oldCount+added),8);
      for(let i=0;i<oldCount;i++){
        const size=sz.fixed||u32(p,12+i*4);
        out.set(w32(size),12+i*4);
      }
      for(let i=oldCount;i<oldCount+added;i++) out.set(w32(8),12+i*4);
      return makeBox("stsz",out);
    };

    const newStsc=()=>{
      const p=payload(bytes,stsc), n=u32(p,4);
      if(n<1) throw new Error("Empty stsc");
      const lastSamplesPerChunk=u32(p,8+(n-1)*12+4);
      const lastDescription=u32(p,8+(n-1)*12+8);
      const out=new Uint8Array(8+(n+1)*12);
      out.set(p.subarray(0,8+n*12),0);
      out.set(w32(n+1),4);
      const q=8+n*12;
      out.set(w32(chunkInfo.count+1),q);
      out.set(w32(added),q+4);
      out.set(w32(lastDescription),q+8);
      // Keep the original entries' chunk mapping untouched.
      return makeBox("stsc",out);
    };

    const newOffsets=(tailOffset)=>{
      const p=payload(bytes,offsetBox), n=u32(p,4), wide=offsetBox.type==="co64", step=wide?8:4;
      const out=new Uint8Array(8+(n+1)*step);
      out.set(p.subarray(0,8),0);
      out.set(w32(n+1),4);
      for(let i=0;i<n;i++) out.set(p.subarray(8+i*step,8+(i+1)*step),8+i*step);
      out.set(wide?w64(BigInt(tailOffset)):w32(tailOffset>>>0),8+n*step);
      return makeBox(offsetBox.type,out);
    };

    const fakeBytes=new Uint8Array(added*8);
    const build=(tailOffset)=>{
      const rewrite=(box,current)=>{
        const active=box.type==="trak"?box:current;
        if(box.type==="trak" && active!==info.audio) return raw(bytes,box);
        if(active===info.audio && box.type==="edts") return null;
        if(active===info.audio && box.type==="stsz") return newStsz();
        if(active===info.audio && box.type==="stsc") return newStsc();
        if(active===info.audio && (box.type==="stco"||box.type==="co64")) return newOffsets(tailOffset);
        return box.children ? cloneTree(bytes,box,c=>rewrite(c,active)) : raw(bytes,box);
      };
      return rewrite(info.moov,null);
    };

    // Reserve the rebuilt moov first, then place the synthetic tail after it.
    const placeholder=makeBox("free",new Uint8Array(info.moov.size-8));
    const probe=build(0);
    const tailOffset=bytes.length+probe.length;
    const finalMoov=build(tailOffset);

    if(finalMoov.length!==probe.length) throw new Error("Non-deterministic MP4 rebuild");

    const originalTop=parseBoxes(bytes);
    const originalMoov=originalTop.find(b=>b.type==="moov");
    const out=cat([
      bytes.subarray(0,originalMoov.start),
      placeholder,
      bytes.subarray(originalMoov.end),
      finalMoov,
      fakeBytes
    ]);

    return {
      bytes:out,
      originalAudioSamples:oldCount,
      fakeAudioSamples:added,
      tailBytes:fakeBytes.length
    };
  }

  function trackChunkRangesValid(bytes,track,mdatStart,mdatEnd,tailStart,tailEnd){
    const stbl=findPath(track,["mdia","minf","stbl"]);
    if(!stbl) return true;
    const stsz=findChild(stbl,"stsz");
    const stsc=findChild(stbl,"stsc");
    const offbox=findChild(stbl,"stco")||findChild(stbl,"co64");
    if(!stsz||!stsc||!offbox) return true;

    const sz=sampleSizeInfo(bytes,stsz);
    const op=payload(bytes,offbox), chunkCount=u32(op,4);
    const wide=offbox.type==="co64", step=wide?8:4;
    if(8+chunkCount*step>op.length) return false;

    const sp=payload(bytes,stsc), runs=u32(sp,4);
    if(!runs || 8+runs*12>sp.length) return false;
    const map=[];
    for(let i=0,o=8;i<runs;i++,o+=12) map.push([u32(sp,o),u32(sp,o+4)]);

    const sizeAt=i=>sz.fixed?sz.fixed:u32(sz.p,12+i*4);
    let sample=0;
    for(let c=1;c<=chunkCount;c++){
      let per=0;
      for(let r=0;r<map.length;r++){
        if(map[r][0]<=c && (r+1===map.length || map[r+1][0]>c)){per=map[r][1];break;}
      }
      if(per<1) return false;
      let bytesInChunk=0;
      for(let k=0;k<per && sample<sz.count;k++,sample++) bytesInChunk+=sizeAt(sample);
      const pos=wide?u64(op,8+(c-1)*step):BigInt(u32(op,8+(c-1)*step));
      const finish=pos+BigInt(bytesInChunk);
      const inMedia=pos>=BigInt(mdatStart)&&finish<=BigInt(mdatEnd);
      const inTail=pos>=BigInt(tailStart)&&finish<=BigInt(tailEnd);
      if(!inMedia&&!inTail) return false;
    }
    return sample===sz.count;
  }

  function validate(src,out){
    const a=inspect(src), b=inspect(out);
    if(b.videoCodec!==a.videoCodec || b.videoSamples!==a.videoSamples)
      throw new Error("Validation failed: video track changed");
    if(b.audioCodec!=="mp4a") throw new Error("Validation failed: AAC track missing");
    if(b.audioSamples!==a.audioSamples*10) throw new Error("Validation failed: audio table expansion");

    const outTop=parseBoxes(out);
    const moovs=outTop.filter(x=>x.type==="moov"), mdats=outTop.filter(x=>x.type==="mdat");
    if(moovs.length!==1||mdats.length!==1) throw new Error("Validation failed: output MP4 structure");
    const outM=mdats[0], srcM=a.mdat;
    if(srcM.size!==outM.size || srcM.header!==outM.header)
      throw new Error("Validation failed: media box changed");

    const srcMedia=src.subarray(srcM.start+srcM.header,srcM.end);
    const outMedia=out.subarray(outM.start+outM.header,outM.end);
    if(srcMedia.length!==outMedia.length) throw new Error("Validation failed: media length");
    for(let i=0;i<srcMedia.length;i++) if(srcMedia[i]!==outMedia[i])
      throw new Error("Validation failed: encoded media changed");

    const finalMoov=moovs[0];
    const tailStart=finalMoov.end, tailEnd=out.length;
    const mdatDataStart=outM.start+outM.header, mdatEnd=outM.end;
    const tracks=(finalMoov.children||[]).filter(x=>x.type==="trak");
    for(const t of tracks){
      if(!trackChunkRangesValid(out,t,mdatDataStart,mdatEnd,tailStart,tailEnd))
        throw new Error("Validation failed: a track has invalid MP4 chunk ranges");
    }
  }

  window.KQEngine={
    inspect,
    process(input){
      const src=input instanceof Uint8Array?input:new Uint8Array(input);
      const normalized=normalize(src);
      const result=expandAudio(normalized);
      validate(normalized,result.bytes);
      return result;
    }
  };
})();