export const run_javascript = async function (SESSION_ID, jobNoP, dsSession, script, evaluate, prog_id, params, evt, $container) {
  const _session = SESSION_OBJ[SESSION_ID];

  const run_native_javascript_program_in_browser = async function () {
    // run in browser

    ///// insert the css
    const path_to_dist = `https://${_session.domain}/studio-drive/${APP_OBJ[_session.app_id].app_replicate || _session.app_id}/scripts/${prog_id}/dist/`;

    const index_mjs = await import(`${path_to_dist}index.mjs`);

    if (index_mjs.css) {
      const css_url = `${path_to_dist}index.css`;
      func.utils.load_css_on_demand(css_url);
    }

    const code = func.utils.replace_studio_drive_url(SESSION_ID, index_mjs.default);

    const api_utils = await func.common.get_module(SESSION_ID, 'xuda-api-library.mjs', {
      func,
      glb,
      SESSION_OBJ,
      SESSION_ID,
      APP_OBJ,
      dsSession,
      jobNoP,
    });

    const xu = api_utils;

    const ret = await code(params, xu, SESSION_ID, SESSION_OBJ, jobNoP, $container);

    if (!code.toString().includes('func.api.callback')) {
      func.events.delete_job(SESSION_ID, jobNoP);
    }
    return ret;
  };

  const run_native_javascript_program_in_server = async function () {
    return new Promise(async (resolve, reject) => {
      const studio_drive_script_folder = path.join(_conf.studio_drive_path, app_id, 'scripts');

      const studio_drive_script_program_folder = path.join(studio_drive_script_folder, prog_id);

      const dist = path.join(studio_drive_script_program_folder, 'dist');
      const index_mjs = path.join(dist, 'index.mjs');

      process.on('uncaughtException', (err) => {
        console.error('Asynchronous error caught.', err);
      });
      const resolve_local = function (e) {
        // resolve({ code: 1, data: e });

        if (!script.toString().includes('func.api.callback')) {
          func.events.delete_job(SESSION_ID, jobNoP);
        }

        resolve(e);
      };

      const reject_local = function (e) {
        // reject({ code: -1, data: e });
        func.events.delete_job(SESSION_ID, jobNoP);
        reject(e);
        // reject(e.message);
      };

      try {
        const script = new VMScript(
          ` 
           const index_mjs = await import(${index_mjs});
          
          try{index_mjs.default(req,params,setup_doc,resolve,reject);}catch(e){ console.error(e); }`,
          { filename: dist, dirname: dist },
        );
        let vm = new NodeVM({
          require: {
            external: true,
          },
          sandbox: {
            resolve: resolve_local,
            reject: reject_local,
          },
          timeout: 60000,
        });
        return await vm.run(script, {
          filename: dist,
          dirname: dist,
        });
      } catch (err) {
        console.error('Failed to execute script.', err);
      }
    });
  };

  if (evaluate) {
    var script_ret = (await func.expression.get(SESSION_ID, script, dsSession, 'javascript', null, null, null, null, null, null, null, () => {}, jobNoP)).result;
  } else {
    if (prog_id) {
      if (typeof IS_API_SERVER !== 'undefined' || typeof IS_DOCKER !== 'undefined' || typeof IS_PROCESS_SERVER !== 'undefined') {
        return await run_native_javascript_program_in_server();
      } else {
        return await run_native_javascript_program_in_browser();
      }
    } else {
      await func.expression.secure_eval(SESSION_ID, 'javascript', func.utils.replace_studio_drive_url(SESSION_ID, script), jobNoP, dsSession, () => {}, evt);
    }
  }

  if (!script.includes('func.api.callback')) {
    func.events.delete_job(SESSION_ID, jobNoP);

    return;
  }
};

export const call_javascript = async function (SESSION_ID, jobNoP, refIdP, dsSession, evaluate, $container) {
  const error_log = async function (msg) {
    let _session = SESSION_OBJ[SESSION_ID];
    func.events.delete_job(SESSION_ID, jobNoP);
    if (typeof IS_API_SERVER !== 'undefined') {
      return __.rpi.write_log(_session.app_id, 'error', 'api', msg);
    }

    if (typeof IS_DOCKER !== 'undefined') {
      return __.rpi.write_log(_session.app_id, 'error', 'worker', msg);
    }

    // client
    await func.common.db(SESSION_ID, 'write_log', {
      msg,
      log_type: 'error',
      source: 'runtime',
    });
  };

  let view_ret = await func.utils.VIEWS_OBJ.get(SESSION_ID, refIdP.prog);

  if (!view_ret) {
    return error_log('program not found');
  }

  if (!view_ret?.scriptData?.value) {
    return error_log('script is empty');
  }
  return await run_javascript(
    SESSION_ID,
    jobNoP,
    dsSession,
    `(async function(${refIdP?.parameters || {}}) {
    ${view_ret.scriptData.value}
    })();`,
    evaluate,
    refIdP.prog,
    refIdP?.parameters,
    null,
    $container,
  );
};
