const _this = {};

export const init_module = (e) => {
  _this.func = e.func;
  _this.glb = e.glb;
  _this.SESSION_OBJ = e.SESSION_OBJ;
  _this.APP_OBJ = e.APP_OBJ;
  _this.IS_DOCKER = e.IS_DOCKER;
  _this.IS_API_SERVER = e.IS_API_SERVER;
  _this.IS_PROCESS_SERVER = e.IS_PROCESS_SERVER;
};

export const get_doc_from_studio = async function (SESSION_ID, app_id, idP) {
  return new Promise(function (resolve, reject) {
    var _session = _this.SESSION_OBJ[SESSION_ID];
    if (glb.IS_WORKER) {
      func.utils.post_back_to_client(SESSION_ID, 'get_doc_from_studio', _session.worker_id, { doc_id: idP });

      self.addEventListener('live_preview_get_obj_response_worker_' + idP, (event) => {
        // console.log("Custom event triggered:", event);
        resolve(event.detail.data);
      });
    } else {
      STUDIO_PEER_CONN_SEND_METHOD({
        service: 'get_doc_obj',
        data: { doc_id: idP },
        session_id: SESSION_ID,
        id: STUDIO_PEER.id,
        source: 'runtime',
        app_id,
      });

      $('body').on('live_preview_get_obj_response_' + idP, function (e, data) {
        resolve(data.data);
        $('body').off('live_preview_get_obj_response_' + idP);
      });
    }
  });
};

export const get_doc_from_websocket = async function (SESSION_ID, app_id, idP) {
  var _session = _this.SESSION_OBJ[SESSION_ID];
  return new Promise(function (resolve, reject) {
    if (glb.IS_WORKER) {
      // throw new Error("fail to fetch from ws");
      func.utils.post_back_to_client(SESSION_ID, 'get_doc_from_websocket', _session.worker_id, { doc_id: idP });

      self.addEventListener('get_doc_obj_from_build_worker_' + idP, (event) => {
        resolve(event.detail.data);
      });
    } else {
      if (RUNTIME_SERVER_WEBSOCKET && RUNTIME_SERVER_WEBSOCKET_CONNECTED) {
        RUNTIME_SERVER_WEBSOCKET.emit('message', {
          service: 'get_doc_obj_from_build',
          data: { doc_id: idP },
        });
        $('body').on('get_doc_obj_from_build_response_' + idP, (e, data) => {
          // views_ret = data.data;
          resolve(data.data);
          $('body').off('get_doc_obj_from_build_response_' + idP);
        });
      } else {
        throw new Error('fail to fetch from ws websocket inactive');
      }
    }
  });
};

export const DOCS_OBJ_get = async function (SESSION_ID, idP) {
  if (!idP) return;

  if (idP === '_empty_panel_program') {
    return {
      _id: '_empty_panel_program',

      properties: {
        menuName: '_empty_panel_program',
        menuTitle: '_empty_panel_program',
        menuType: 'component',
        // uiFramework: "@xuda.io/xuda-framework-plugin-tailwind",
        renderType: 'form',
      },
      progUi: [
        {
          id: 'node-empty_panel_program',
          tagName: 'xu-single-view',
          children: [
            {
              id: 'node-empty_panel_program-span',
              tagName: 'span',
              children: [],
              content: '',
              type: 'element',
              attributes: {},
            },
          ],
          content: '',
          type: 'element',
          attributes: {},
        },
      ],
      progDataSource: {},
      progFields: [],
      progEvents: [],
    };
  }

  var _session = _this.SESSION_OBJ[SESSION_ID];
  const app_id = _session.app_id;
  var views_ret;

  if (_session.engine_mode === 'live_preview') {
    return await get_doc_from_studio(SESSION_ID, app_id, idP);
  }

  if (glb.register_startup_programs) {
    func.common.db(SESSION_ID, 'register_startup_programs', {
      prog_id: idP,
      build_id: _session?.build_info?.build || 0,
    });
  }

  views_ret = await read_objects_cache(SESSION_ID, idP, 'DOCS_OBJ');

  if (!views_ret) {
    if (typeof _this.IS_DOCKER === 'undefined' && typeof _this.IS_PROCESS_SERVER === 'undefined') {
      let url = _this.func.common.get_url(SESSION_ID, 'rpi', '');

      // Jul 7,25 build condition for master need to be added
      if (['master'].includes(_this.APP_OBJ[app_id].app_type)) {
        url += 'get_doc_obj_raw';
      } else {
        url += 'get_doc_obj_from_build';
      }

      let app_id_reference = _this.APP_OBJ[app_id].app_id_reference;

      /////////////////

      const http = async function () {
        const response = await fetch(url, {
          method: 'POST',
          headers: {
            Accept: 'application/json',
            'Content-Type': 'application/json',
            'xu-gtp-token': _session.gtp_token,
            'xu-app-token': _session.app_token,
          },
          body: JSON.stringify({
            app_id: app_id,
            doc_id: idP,
            build: _session.build_info.instance_build || _session.build_info.build || _session.opt.app_build_id,
            app_id_reference: app_id_reference,
            engine_mode: _session.engine_mode,
          }),
        });
        const json = await response.json();
        if (response) {
          if (response && response.status === 400) {
            return _this.func.utils.request_error(SESSION_ID, 'ajax', response.statusText);
          }

          views_ret = json.data;
        }
      };

      if (_session.engine_mode === 'miniapp') {
        await http();
      } else {
        views_ret = await get_doc_from_websocket(SESSION_ID, app_id, idP);
      }

      // // Jul 7,25 replaced ^^
      // try {
      //   if (SESSION_OBJ?.[SESSION_ID]?.rpi_http_methods?.includes('get_doc_obj_from_build')) {
      //     views_ret = await get_doc_from_websocket(SESSION_ID, app_id, idP);
      //   } else {
      //     throw new Error('not a get_doc_obj_from_build method');
      //   }
      // } catch (err) {
      //   await http();
      // }
    }

    if (typeof _this.IS_DOCKER !== 'undefined' || typeof _this.IS_PROCESS_SERVER !== 'undefined') {
      var ret = await __.rpi.get_prog(app_id, idP);

      if (ret.data) {
        views_ret = ret.data;
      }
    }

    if (views_ret) {
      if (views_ret.error) {
        console.error(views_ret);
        views_ret = '';
        return;
      }
      await save_objects_cache(SESSION_ID, idP, 'DOCS_OBJ', views_ret);
    }
  }

  return views_ret;
};

export const save_objects_cache = async function (SESSION_ID, id, obj_type, data) {
  var _session = _this.SESSION_OBJ[SESSION_ID];
  if (typeof _this.IS_DOCKER !== 'undefined' || typeof _this.IS_PROCESS_SERVER !== 'undefined' || _session.worker_type === 'Dev') {
    return;
  }

  var build_id = _session?.build_info?.build || 0;

  const db = await _this.func.utils.connect_pouchdb(SESSION_ID);
  var doc = {
    _id: `cache_${build_id}_${obj_type}_${id}`,
    id: id,
    docType: 'cache_objects',
    build_id: build_id.toString(),
    obj_type: obj_type,
    data: data,
  };
  setTimeout(async function () {
    try {
      await db.get(doc_id);
      return;
    } catch (e) {
      if (await read_objects_cache(SESSION_ID, id, obj_type)) {
        return;
      }
      if (!doc.data || (doc.data && typeof doc.data === 'string' && doc.data.indexOf('error') > -1)) {
        return;
      }

      try {
        return await db.put(doc);
      } catch (err) {
        return;
      }
    }
  }, 1000);
};
export const read_objects_cache = async function (SESSION_ID, id, obj_type) {
  if (typeof _this.IS_DOCKER !== 'undefined' || typeof _this.IS_PROCESS_SERVER !== 'undefined') {
    try {
      const data = fs.readFileSync('/var/xuda/progs/' + id + '.json', 'utf8');
      return JSON.parse(data);
    } catch (err) {
      console.error('read_objects_cache', err);
      return;
    }
  }
  var _session = _this.SESSION_OBJ[SESSION_ID];

  var build_id = _session?.build_info?.build || 0;

  const db = await _this.func.utils.connect_pouchdb(SESSION_ID);
  var ret;
  try {
    ret = await db.get(`cache_${build_id}_${obj_type}_${id}`);

    if (ret.data && typeof ret.data === 'string' && ret.data.indexOf('error') > -1) {
      return '';
    }

    return ret.data;
  } catch (err) {
    return ret;
  }
};
export const delete_objects_cache = async function (SESSION_ID, id, obj_type) {
  const app_id = _this.SESSION_OBJ[SESSION_ID].app_id;

  var build_id = _session?.build_info?.build || 0;
  const db = await _this.func.utils.connect_pouchdb(SESSION_ID);

  try {
    var doc = await db.get(`cache_${build_id}_${obj_type}_${id}`);
    if (!doc) return;
    var ret = await db.remove(doc);
  } catch (err) {
    //
    return;
  }

  return ret;
};
export const load_objects_cache = async function (SESSION_ID) {
  var _session = _this.SESSION_OBJ[SESSION_ID];
  if (typeof _this.IS_DOCKER !== 'undefined' || typeof _this.IS_PROCESS_SERVER !== 'undefined') {
    return;
  }

  const app_id = _session.app_id;

  const db = await _this.func.utils.connect_pouchdb(SESSION_ID);
  const build_id = _this.APP_OBJ[app_id].app_build_id;
  let ret = await db.find({
    selector: { docType: 'cache_objects', build_id },
  });

  for (let val of ret.docs) {
    eval(val.obj_type)[_session.app_id][val.id] = val.data;
  }
};
