// require nodejs v24.0 or later(to load wasm)
import { TinyUSDZLoader } from 'tinyusdz/TinyUSDZLoader.js';
import { TinyUSDZLoaderUtils } from 'tinyusdz/TinyUSDZLoaderUtils.js';
import { TinyUSDZComposer } from 'tinyusdz/TinyUSDZComposer.js';

import fs from 'node:fs';
import { pipeline } from 'node:stream/promises';

function reportMemUsage() {
 const used = process.memoryUsage()
 const messages = []
 for (let key in used) {
    console.log(`${key}: ${Math.round(used[key] / 1024 / 1024 * 100) / 100} MB`)
  }
}

function loadFile(filename) {
  try {
    const data = fs.readFileSync(filename);
    const mimeType = 'application/octet-stream';
    const blob = new Blob([data], { type: mimeType });

    const f = new File([blob], filename, { type: blob.type });

    return f;
    //const base64 = data.toString('base64');
    //data = null;
    //return `data:${mimeType};base64,${base64}`;
    //console.log(data);
  } catch (err) {
    console.error(err);
  }
  return null;
}

// Stream file reading and set to Asset using streaming API
async function streamFileToAsset(filename, loader, assetName) {
  return new Promise((resolve, reject) => {
    const stats = fs.statSync(filename);
    const fileSize = stats.size;
    const chunkSize = 65536; // 64KB chunks
    
    console.log(`Starting streaming asset: ${assetName}, size: ${fileSize} bytes`);
    
    // Start the streaming asset
    if (!loader.native_ || !loader.native_.TinyUSDZLoaderNative) {
      reject(new Error('Native module not initialized'));
      return;
    }
    
    const usd = new loader.native_.TinyUSDZLoaderNative();
    
    // Initialize streaming for this asset
    if (!usd.startStreamingAsset(assetName, fileSize)) {
      reject(new Error('Failed to start streaming asset'));
      return;
    }
    
    const stream = fs.createReadStream(filename, {
      highWaterMark: chunkSize
    });
    
    let bytesRead = 0;
    
    stream.on('data', (chunk) => {
      // Convert chunk to Uint8Array then to string for the API
      const uint8Array = new Uint8Array(chunk);
      
      // Append the chunk to the streaming asset
      if (!usd.appendAssetChunk(assetName, uint8Array)) {
        stream.destroy();
        reject(new Error('Failed to append asset chunk'));
        return;
      }
      
      bytesRead += chunk.length;
      
      // Check progress
      const progress = usd.getStreamingProgress(assetName);
      if (progress && progress.exists) {
        // Use fileSize if expected is not provided
        const expectedBytes = progress.expected || fileSize;
        const percentage = expectedBytes > 0 ? Math.round(progress.current/expectedBytes * 100) : 0;
        console.log(`Progress: ${progress.current}/${expectedBytes} bytes (${percentage}%)`);
      }
    });
    
    stream.on('end', () => {
      console.log(`Stream ended, finalizing asset: ${assetName}`);
      
      // Finalize the streaming asset
      if (!usd.finalizeStreamingAsset(assetName)) {
        reject(new Error('Failed to finalize streaming asset'));
        return;
      }
      
      console.log(`Asset ${assetName} successfully loaded via streaming`);
      resolve(usd);
    });
    
    stream.on('error', (err) => {
      console.error('Stream error:', err);
      reject(err);
    });
  });
}

console.log(process.versions.node);

function checkMemory64Support() {
    try {
        // Try creating a 64-bit memory
        const memory = new WebAssembly.Memory({
            initial: 1,
            maximum: 65536,
            index: 'i64'  // This specifies 64-bit indexing
        });
        return true;
    } catch (e) {
        return false;
    }
}

console.log("memory64:", checkMemory64Support());

const usd_filename = "../../models/suzanne-subd-lv4.usdc";

async function initScene() {

  const loader = new TinyUSDZLoader();
  const memory64 = false; //checkMemory64Support();
  await loader.init({useMemory64: false});
  loader.setMaxMemoryLimitMB(200);

  // Option 1: Use traditional file loading (existing method)
  console.log("\n=== Traditional file loading ===");
  const f = loadFile(usd_filename);
  const url = URL.createObjectURL(f);
  //const usd = await loader.loadTestAsync(url);
  const usd = await loader.loadAsync(url);
  //console.log("Traditional loading completed");
  reportMemUsage();

  /*
  // Option 2: Use streaming API to load asset
  console.log("\n=== Streaming file loading ===");
  try {
    // Stream the file content to the asset cache
    const assetName = "streamed_model.usdc";
    const streamedUsd = await streamFileToAsset(usd_filename, loader, assetName);
    
    // Now the asset is in the cache and can be used
    if (streamedUsd.hasAsset(assetName)) {
      console.log(`Asset ${assetName} is now available in cache`);
      
      // Get UUID of the streamed asset
      const uuid = streamedUsd.getAssetUUID(assetName);
      console.log(`Asset UUID: ${uuid}`);
      
      // You can now load from the cached asset
      // The asset is already in memory and can be accessed via the resolver
      // Skip loadTest for now - just verify streaming worked
      // const testResult = streamedUsd.loadTest(assetName, assetData);
      // console.log(`Load test result: ${testResult}`);
    }
    
    console.log("Streaming loading completed");
    reportMemUsage();
  } catch (err) {
    console.error("Streaming failed:", err);
  }
  */

}

console.log(WebAssembly);
/*
Object [WebAssembly] {
  compile: [Function: compile],
  validate: [Function: validate],
  instantiate: [Function: instantiate]
}
*/


initScene();
