// Copyright (c) 2023 Tencent. All rights reserved.
// Author: felixyyan

#include "bindings/sebind/sebind.h"
#include "plugins/Plugins.h"
#include "tmg_audio_ctrl_bindings.h"
#include "tmg_audio_effect_ctrl_bindings.h"
#include "tmg_context_bindings.h"
#include "tmg_ptt_bindings.h"
#include "tmg_room_bindings.h"

// export c++ methods to JS
bool RegisterTMGContextBridge(se::Object* ns);
bool RegisterTMGAudioCtrlBridge(se::Object* ns);
bool RegisterTMGAudioEffectCtrlBridge(se::Object* ns);
bool RegisterTMGRoomBridge(se::Object* ns);
bool RegisterTMGPTTBridge(se::Object* ns);

void load_gme_plugin() {
  using namespace cc::plugin;
  static Listener listener(BusType::SCRIPT_ENGINE);
  listener.receive([](ScriptEngineEvent event) {
    if (event == ScriptEngineEvent::POST_INIT) {
      se::ScriptEngine::getInstance()->addRegisterCallback(RegisterTMGContextBridge);
      se::ScriptEngine::getInstance()->addRegisterCallback(RegisterTMGAudioCtrlBridge);
      se::ScriptEngine::getInstance()->addRegisterCallback(RegisterTMGAudioEffectCtrlBridge);
      se::ScriptEngine::getInstance()->addRegisterCallback(RegisterTMGRoomBridge);
      se::ScriptEngine::getInstance()->addRegisterCallback(RegisterTMGPTTBridge);
    }
  });
}

CC_PLUGIN_ENTRY(gme_plugin, load_gme_plugin);

bool RegisterTMGContextBridge(se::Object* ns) {
  sebind::class_<TMGContextBindings> bridge("TMGContextBindings");
  bridge.constructor<>();

  bridge.finalizer([](TMGContextBindings* bridge) {
    CC_LOG_INFO("[TMGContextBindings] finalizer:%p\n", bridge);
  });

  bridge.function("setTMGDelegate", &TMGContextBindings::setTMGDelegate);
  bridge.function("setRegion", &TMGContextBindings::setRegion);
  bridge.function("getAuthBuffer", &TMGContextBindings::getAuthBuffer);
  bridge.function("init", &TMGContextBindings::init);
  bridge.function("poll", &TMGContextBindings::poll);
  bridge.function("pause", &TMGContextBindings::pause);
  bridge.function("resume", &TMGContextBindings::resume);
  bridge.function("uninit", &TMGContextBindings::uninit);
  bridge.function("setScene", &TMGContextBindings::setScene);
  bridge.function("setAudioRole", &TMGContextBindings::setAudioRole);
  bridge.function("setRangeAudioMode", &TMGContextBindings::setRangeAudioMode);
  bridge.function("setRangeAudioTeamID", &TMGContextBindings::setRangeAudioTeamID);
  bridge.function("enterRoom", &TMGContextBindings::enterRoom);
  bridge.function("exitRoom", &TMGContextBindings::exitRoom);
  bridge.function("isRoomEntered", &TMGContextBindings::isRoomEntered);
  bridge.function("setLogLevel", &TMGContextBindings::setLogLevel);
  bridge.function("setLogPath", &TMGContextBindings::setLogPath);
  bridge.function("getLogPath", &TMGContextBindings::getLogPath);
  bridge.function("getSDKVersion", &TMGContextBindings::getSDKVersion);
  bridge.function("setAppVersion", &TMGContextBindings::setAppVersion);
  bridge.function("showDebugView", &TMGContextBindings::showDebugView);
  bridge.function("setRecvMixStreamCount", &TMGContextBindings::setRecvMixStreamCount);
  bridge.function("setAdvanceParams", &TMGContextBindings::setAdvanceParams);
  bridge.function("getAdvanceParams", &TMGContextBindings::getAdvanceParams);
  bridge.function("checkMicPermission", &TMGContextBindings::checkMicPermission);

  bridge.install(ns);

  return true;
}

bool RegisterTMGAudioCtrlBridge(se::Object* ns) {
  sebind::class_<TMGAudioCtrlBindings> bridge("TMGAudioCtrlBindings");

  bridge.constructor<std::shared_ptr<TMGContextBindings>>();

  bridge.finalizer([](TMGAudioCtrlBindings* bridge) {
    CC_LOG_INFO("[TMGAudioCtrlBindings] finalizer:%p\n", bridge);
  });

  bridge.function("enableMic", &TMGAudioCtrlBindings::enableMic);
  bridge.function("getMicState", &TMGAudioCtrlBindings::getMicState);
  bridge.function("enableSpeaker", &TMGAudioCtrlBindings::enableSpeaker);
  bridge.function("getSpeakerState", &TMGAudioCtrlBindings::getSpeakerState);
  bridge.function("enableAudioCaptureDevice", &TMGAudioCtrlBindings::enableAudioCaptureDevice);
  bridge.function("isAudioCaptureDeviceEnabled",
                  &TMGAudioCtrlBindings::isAudioCaptureDeviceEnabled);
  bridge.function("enableAudioPlayDevice", &TMGAudioCtrlBindings::enableAudioPlayDevice);
  bridge.function("isAudioPlayDeviceEnabled", &TMGAudioCtrlBindings::isAudioPlayDeviceEnabled);
  bridge.function("enableAudioSend", &TMGAudioCtrlBindings::enableAudioSend);
  bridge.function("isAudioSendEnabled", &TMGAudioCtrlBindings::isAudioSendEnabled);
  bridge.function("enableAudioRecv", &TMGAudioCtrlBindings::enableAudioRecv);
  bridge.function("isAudioRecvEnabled", &TMGAudioCtrlBindings::isAudioRecvEnabled);
  bridge.function("setMicVolume", &TMGAudioCtrlBindings::setMicVolume);
  bridge.function("getMicVolume", &TMGAudioCtrlBindings::getMicVolume);
  bridge.function("setSpeakerVolume", &TMGAudioCtrlBindings::setSpeakerVolume);
  bridge.function("getSpeakerVolume", &TMGAudioCtrlBindings::getSpeakerVolume);
  bridge.function("setSpeakerVolumeByUserID", &TMGAudioCtrlBindings::setSpeakerVolumeByUserID);
  bridge.function("getSpeakerVolumeByUserID", &TMGAudioCtrlBindings::getSpeakerVolumeByUserID);
  bridge.function("enableLoopBack", &TMGAudioCtrlBindings::enableLoopBack);
  bridge.function("addAudioBlackList", &TMGAudioCtrlBindings::addAudioBlackList);
  bridge.function("removeAudioBlackList", &TMGAudioCtrlBindings::removeAudioBlackList);
  bridge.function("isUserIDInAudioBlackList", &TMGAudioCtrlBindings::isUserIDInAudioBlackList);
  bridge.function("enableSpatializer", &TMGAudioCtrlBindings::enableSpatializer);
  bridge.function("isEnableSpatializer", &TMGAudioCtrlBindings::isEnableSpatializer);
  bridge.function("getMicListCount", &TMGAudioCtrlBindings::getMicListCount);
  bridge.function("getMicList", &TMGAudioCtrlBindings::getMicList);
  bridge.function("selectMic", &TMGAudioCtrlBindings::selectMic);
  bridge.function("getCurrentMic", &TMGAudioCtrlBindings::getCurrentMic);
  bridge.function("getSpeakerListCount", &TMGAudioCtrlBindings::getSpeakerListCount);
  bridge.function("getSpeakerList", &TMGAudioCtrlBindings::getSpeakerList);
  bridge.function("selectSpeaker", &TMGAudioCtrlBindings::selectSpeaker);
  bridge.function("getCurrentSpeaker", &TMGAudioCtrlBindings::getCurrentSpeaker);
  bridge.function("setAudioRoute", &TMGAudioCtrlBindings::setAudioRoute);
  bridge.function("trackingVolume", &TMGAudioCtrlBindings::trackingVolume);
  bridge.function("stopTrackingVolume", &TMGAudioCtrlBindings::stopTrackingVolume);
  bridge.function("getMicLevel", &TMGAudioCtrlBindings::getMicLevel);
  bridge.function("getSpeakerLevel", &TMGAudioCtrlBindings::getSpeakerLevel);
  bridge.function("getSendStreamLevel", &TMGAudioCtrlBindings::getSendStreamLevel);
  bridge.function("getRecvStreamLevel", &TMGAudioCtrlBindings::getRecvStreamLevel);
  bridge.function("startMicDeviceTest", &TMGAudioCtrlBindings::startMicDeviceTest);
  bridge.function("stopMicDeviceTest", &TMGAudioCtrlBindings::stopMicDeviceTest);
  bridge.function("startSpeakerDeviceTest", &TMGAudioCtrlBindings::startSpeakerDeviceTest);
  bridge.function("stopSpeakerDeviceTest", &TMGAudioCtrlBindings::stopSpeakerDeviceTest);
  bridge.install(ns);
  return true;
}

bool RegisterTMGAudioEffectCtrlBridge(se::Object* ns) {
  sebind::class_<TMGAudioEffectCtrlBindings> bridge("TMGAudioEffectCtrlBindings");
  bridge.constructor<std::shared_ptr<TMGContextBindings>>();

  bridge.finalizer([](TMGAudioEffectCtrlBindings* bridge) {
    CC_LOG_INFO("[TMGAudioEffectCtrlBindings] finalizer:%p\n", bridge);
  });

  bridge.function("startPlayMusic", &TMGAudioEffectCtrlBindings::startPlayMusic);
  bridge.function("stopPlayMusic", &TMGAudioEffectCtrlBindings::stopPlayMusic);
  bridge.function("pausePlayMusic", &TMGAudioEffectCtrlBindings::pausePlayMusic);
  bridge.function("resumePlayMusic", &TMGAudioEffectCtrlBindings::resumePlayMusic);
  bridge.function("isMusicPlayEnd", &TMGAudioEffectCtrlBindings::isMusicPlayEnd);
  bridge.function("setAllMusicVolume", &TMGAudioEffectCtrlBindings::setAllMusicVolume);
  bridge.function("setMusicPublishVolume", &TMGAudioEffectCtrlBindings::setMusicPublishVolume);
  bridge.function("getMusicPublishVolume", &TMGAudioEffectCtrlBindings::getMusicPublishVolume);
  bridge.function("setMusicPlayoutVolume", &TMGAudioEffectCtrlBindings::setMusicPlayoutVolume);
  bridge.function("getMusicPlayoutVolume", &TMGAudioEffectCtrlBindings::getMusicPlayoutVolume);
  bridge.function("setMusicPitch", &TMGAudioEffectCtrlBindings::setMusicPitch);
  bridge.function("getMusicDurationInMS", &TMGAudioEffectCtrlBindings::getMusicDurationInMS);
  bridge.function("getMusicCurrentPosInMS", &TMGAudioEffectCtrlBindings::getMusicCurrentPosInMS);
  bridge.function("seekMusicToPosInTime", &TMGAudioEffectCtrlBindings::seekMusicToPosInTime);
  bridge.function("enableMusicPublish", &TMGAudioEffectCtrlBindings::enableMusicPublish);
  bridge.function("enableMusicPlayout", &TMGAudioEffectCtrlBindings::enableMusicPlayout);
  bridge.function("setVoiceType", &TMGAudioEffectCtrlBindings::setVoiceType);
  bridge.function("setKaraokeType", &TMGAudioEffectCtrlBindings::setKaraokeType);
  bridge.function("startRecord", &TMGAudioEffectCtrlBindings::startRecord);
  bridge.function("stopRecord", &TMGAudioEffectCtrlBindings::stopRecord);
  bridge.function("startSystemAudioLoopback",
                  &TMGAudioEffectCtrlBindings::startSystemAudioLoopback);
  bridge.function("stopSystemAudioLoopback", &TMGAudioEffectCtrlBindings::stopSystemAudioLoopback);
  bridge.function("setSystemAudioLoopbackVolume",
                  &TMGAudioEffectCtrlBindings::setSystemAudioLoopbackVolume);

  bridge.install(ns);
  return true;
}

bool RegisterTMGRoomBridge(se::Object* ns) {
  sebind::class_<TMGRoomBindings> bridge("TMGRoomBindings");
  bridge.constructor<std::shared_ptr<TMGContextBindings>>();

  bridge.finalizer(
      [](TMGRoomBindings* bridge) { CC_LOG_INFO("[TMGRoomBindings] finalizer:%p\n", bridge); });

  bridge.function("getRoomID", &TMGRoomBindings::getRoomID);
  bridge.function("changeRoomType", &TMGRoomBindings::changeRoomType);
  bridge.function("getRoomType", &TMGRoomBindings::getRoomType);
  bridge.function("startRoomSharing", &TMGRoomBindings::startRoomSharing);
  bridge.function("stopRoomSharing", &TMGRoomBindings::stopRoomSharing);
  bridge.function("switchRoom", &TMGRoomBindings::switchRoom);
  bridge.function("sendCustomData", &TMGRoomBindings::sendCustomData);
  bridge.function("stopSendCustomData", &TMGRoomBindings::stopSendCustomData);
  bridge.function("updateAudioRecvRange", &TMGRoomBindings::updateAudioRecvRange);
  bridge.function("updateSpatializerRecvRange", &TMGRoomBindings::updateSpatializerRecvRange);
  bridge.function("updateSelfPosition", &TMGRoomBindings::updateSelfPosition);
  bridge.function("updateOtherPosition", &TMGRoomBindings::updateOtherPosition);
  bridge.function("sendSEIMsg", &TMGRoomBindings::sendSEIMsg);

  bridge.install(ns);

  return true;
}

bool RegisterTMGPTTBridge(se::Object* ns) {
  sebind::class_<TMGPTTBindings> bridge("TMGPTTBindings");
  bridge.constructor<std::shared_ptr<TMGContextBindings>>();

  bridge.finalizer(
      [](TMGPTTBindings* bridge) { CC_LOG_INFO("[TMGPTTBindings] finalizer:%p\n", bridge); });

  bridge.function("applyPTTAuthbuffer", &TMGPTTBindings::applyPTTAuthbuffer);
  bridge.function("setMaxMessageLength", &TMGPTTBindings::setMaxMessageLength);
  bridge.function("startRecording", &TMGPTTBindings::startRecording);
  bridge.function("stopRecording", &TMGPTTBindings::stopRecording);
  bridge.function("cancelRecording", &TMGPTTBindings::cancelRecording);
  bridge.function("uploadRecordedFile", &TMGPTTBindings::uploadRecordedFile);
  bridge.function("downloadRecordedFile", &TMGPTTBindings::downloadRecordedFile);
  bridge.function("playRecordedFile", &TMGPTTBindings::playRecordedFile);
  bridge.function("stopPlayFile", &TMGPTTBindings::stopPlayFile);
  bridge.function("speechToText", &TMGPTTBindings::speechToText);
  bridge.function("translateText", &TMGPTTBindings::translateText);
  bridge.function("getFileSize", &TMGPTTBindings::getFileSize);
  bridge.function("getVoiceFileDuration", &TMGPTTBindings::getVoiceFileDuration);
  bridge.function("startRecordingWithStreamingRecognition",
                  &TMGPTTBindings::startRecordingWithStreamingRecognition);
  bridge.function("setPTTSourceLanguage", &TMGPTTBindings::setPTTSourceLanguage);
  bridge.function("textToSpeech", &TMGPTTBindings::textToSpeech);

  bridge.install(ns);

  return true;
}
