import 'dart:ffi';
import 'package:ffi/ffi.dart';
import 'dart:convert';
import 'tmg_load_dynamic.dart';
import 'dart:typed_data';

typedef AVEnterRoomCompleteCallback_CSharp = Void Function(
    Int32 result, Pointer<Int8> error_info);

typedef AVExitRoomCompleteCallback_CSharp = Void Function();

typedef AVRoomDisconnect_CSharp = Void Function(
    Int32 result, Pointer<Int8> error_info);

typedef AVEndpointsUpdateInfo_CSharp = Void Function(
    Int32 eventID, Int32 count, Pointer<Pointer<Int8>> identifier);

typedef AVOnRoomEvent_CSharp = Void Function(Int32 roomType);

typedef AVOnDeviceStateChangedEvent_CSharp = Void Function(
    Int32 deviceType, Pointer<Int8> deviceId, Int32 openOrClose);

typedef AVAudioPlayerReadyCallback_CSharp = Void Function();

typedef AVRoomChangeQualityCallback_CSharp = Void Function(
    Int32 nQualityEVA, Float fLostRate, Int32 nDealy);

typedef AVCommonEventCallback_CSharp = Void Function(
    Int32 type, Int32 param0, Int32 param1);

typedef AVOnEventCallback_CSharp = Void Function(
    Int32 type, Int32 subtype, Pointer<Int8> data);

typedef SetDelegateNative = Void Function(
  Pointer<NativeFunction<AVEnterRoomCompleteCallback_CSharp>>
      enterRoomCompleteCallback,
  Pointer<NativeFunction<AVExitRoomCompleteCallback_CSharp>>
      exitRoomCompleteCallback,
  Pointer<NativeFunction<AVRoomDisconnect_CSharp>> roomDisconnectCallback,
  Pointer<NativeFunction<AVEndpointsUpdateInfo_CSharp>>
      endpointsUpdateInfoCallback,
  Pointer<NativeFunction<AVOnRoomEvent_CSharp>> onRoomEvent,
  Pointer<NativeFunction<AVOnDeviceStateChangedEvent_CSharp>>
      onDeviceStateChangedEvent,
  Pointer<NativeFunction<AVAudioPlayerReadyCallback_CSharp>> audioReadyCallback,
  Pointer<NativeFunction<AVRoomChangeQualityCallback_CSharp>>
      roomChangeQualityCallBack,
  Pointer<NativeFunction<AVCommonEventCallback_CSharp>> commonCallback,
  Pointer<NativeFunction<AVOnEventCallback_CSharp>> onEventCallback,
);

typedef SetDelegateDart = void Function(
  Pointer<NativeFunction<AVEnterRoomCompleteCallback_CSharp>>
      enterRoomCompleteCallback,
  Pointer<NativeFunction<AVExitRoomCompleteCallback_CSharp>>
      exitRoomCompleteCallback,
  Pointer<NativeFunction<AVRoomDisconnect_CSharp>> roomDisconnectCallback,
  Pointer<NativeFunction<AVEndpointsUpdateInfo_CSharp>>
      endpointsUpdateInfoCallback,
  Pointer<NativeFunction<AVOnRoomEvent_CSharp>> onRoomEvent,
  Pointer<NativeFunction<AVOnDeviceStateChangedEvent_CSharp>>
      onDeviceStateChangedEvent,
  Pointer<NativeFunction<AVAudioPlayerReadyCallback_CSharp>> audioReadyCallback,
  Pointer<NativeFunction<AVRoomChangeQualityCallback_CSharp>>
      roomChangeQualityCallBack,
  Pointer<NativeFunction<AVCommonEventCallback_CSharp>> commonCallback,
  Pointer<NativeFunction<AVOnEventCallback_CSharp>> onEventCallback,
);

typedef GMEInitNative = Int32 Function(
  Pointer<Int8> sdk_versin,
  Pointer<Int8> sdk_app_id,
  Pointer<Int8> user_id,
);
typedef GMEInitDart = int Function(
  Pointer<Int8> sdk_versin,
  Pointer<Int8> sdk_app_id,
  Pointer<Int8> user_id,
);

typedef GMEPollNative = Int32 Function();
typedef GMEPollDart = int Function();

typedef GMEPauseNative = Int32 Function();
typedef GMEPauseDart = int Function();

typedef GMEResumeNative = Int32 Function();
typedef GMEResumeDart = int Function();

typedef GMEUninitNative = Int32 Function();
typedef GMEUninitDart = int Function();

typedef GenAuthBufferNative = Int32 Function(
    Int32 appId,
    Pointer<Int8> roomId,
    Pointer<Int8> userId,
    Pointer<Int8> key,
    Pointer<Int8> authBuffer,
    Int32 authBufferLen);
typedef GenAuthBufferDart = int Function(
    int appId,
    Pointer<Int8> roomId,
    Pointer<Int8> userId,
    Pointer<Int8> key,
    Pointer<Int8> authBuffer,
    int authBufferLen);

typedef GMEEnterRoomNative = Int32 Function(Pointer<Int8> roomId,
    Pointer<Int8> authBuffer, Int32 authBufferCount, Int32 roomType);
typedef GMEEnterRoomDart = int Function(Pointer<Int8> roomId,
    Pointer<Int8> authBuffer, int authBufferCount, int roomType);

typedef GMEExitRoomNative = Int32 Function();
typedef GMEExitRoomDart = int Function();

typedef SetRecvMixStreamCountNative = Int32 Function(Int32 count);
typedef SetRecvMixStreamCountDart = int Function(int count);

typedef GMEIsRoomEnteredNative = Int8 Function();
typedef GMEIsRoomEnteredDart = int Function();

typedef SetLogLevelNative = Int32 Function(Int32 levelWrite, Int32 levelPrint);
typedef SetLogLevelDart = int Function(int levelWrite, int levelPrint);

typedef SetLogPathNative = Int32 Function(Pointer<Int8> logDir);
typedef SetLogPathDart = int Function(Pointer<Int8> logDir);

typedef SetAdvanceParamsNative = Int32 Function(
    Pointer<Int8> key, Pointer<Int8> value);
typedef SetAdvanceParamsDart = int Function(
    Pointer<Int8> key, Pointer<Int8> value);

class TmgSdkBindings {
  TMGLoadDynamic _tmgDynamicInstance = TMGLoadDynamic.GetInstance();
  DynamicLibrary? _gmeSdkLib = null;
  String _sdk_version = '2_9_14_81221e13';

  TmgSdkBindings() {
    _gmeSdkLib = _tmgDynamicInstance.GetGmeSdkLib();
  }

  late final SetDelegateDart SetDelegatePtr = _gmeSdkLib!
      .lookup<NativeFunction<SetDelegateNative>>('QAVSDK_AVContext_SetDelegate')
      .asFunction<SetDelegateDart>();

  int SetDelegate(
      Pointer<NativeFunction<AVEnterRoomCompleteCallback_CSharp>>
          enterRoomCompleteCallback,
      Pointer<NativeFunction<AVExitRoomCompleteCallback_CSharp>>
          exitRoomCompleteCallback,
      Pointer<NativeFunction<AVRoomDisconnect_CSharp>> roomDisconnectCallback,
      Pointer<NativeFunction<AVEndpointsUpdateInfo_CSharp>>
          endpointsUpdateInfoCallback,
      Pointer<NativeFunction<AVOnRoomEvent_CSharp>> onRoomEvent,
      Pointer<NativeFunction<AVRoomChangeQualityCallback_CSharp>>
          roomChangeQualityCallBack,
      Pointer<NativeFunction<AVOnEventCallback_CSharp>> onEventCallback) {
        
    Pointer<NativeFunction<AVAudioPlayerReadyCallback_CSharp>>
        audioReadyCallback = nullptr;
    Pointer<NativeFunction<AVOnDeviceStateChangedEvent_CSharp>>
        onDeviceStateChangedEvent = nullptr;
    Pointer<NativeFunction<AVCommonEventCallback_CSharp>> commonCallback =
        nullptr;

    SetDelegatePtr(
        enterRoomCompleteCallback,
        exitRoomCompleteCallback,
        roomDisconnectCallback,
        endpointsUpdateInfoCallback,
        onRoomEvent,
        onDeviceStateChangedEvent,
        audioReadyCallback,
        roomChangeQualityCallBack,
        commonCallback,
        onEventCallback);
    return 0;
  }

  late final GMEInitDart InitPtr = _gmeSdkLib!
      .lookup<NativeFunction<GMEInitNative>>('QAVSDK_AVContext_Start')
      .asFunction<GMEInitDart>();

  int Init(String sdk_app_id, String user_id) {
    return InitPtr(
      _sdk_version.toNativeUtf8().cast<Int8>(),
      sdk_app_id.toNativeUtf8().cast<Int8>(),
      user_id.toNativeUtf8().cast<Int8>(),
    );
  }

  late final GMEPollDart PollPtr = _gmeSdkLib!
      .lookup<NativeFunction<GMEPollNative>>('QAVSDK_Poll')
      .asFunction<GMEPollDart>();

  int Poll() {
    return PollPtr();
  }

  late final GMEPauseDart PausePtr = _gmeSdkLib!
      .lookup<NativeFunction<GMEPauseNative>>('QAVSDK_AVContext_Pause')
      .asFunction<GMEPauseDart>();

  int Pause() {
    return PausePtr();
  }

  late final GMEResumeDart ResumePtr = _gmeSdkLib!
      .lookup<NativeFunction<GMEResumeNative>>('QAVSDK_AVContext_Resume')
      .asFunction<GMEResumeDart>();

  int Resume() {
    return ResumePtr();
  }

  late final GMEUninitDart UninitPtr = _gmeSdkLib!
      .lookup<NativeFunction<GMEUninitNative>>('QAVSDK_AVContext_Stop')
      .asFunction<GMEUninitDart>();

  int Uninit() {
    return UninitPtr();
  }

  late final GenAuthBufferDart GenAuthBufferPtr = _gmeSdkLib!
      .lookup<NativeFunction<GenAuthBufferNative>>(
        'QAVSDK_AuthBuffer_GenAuthBufferV2',
      )
      .asFunction<GenAuthBufferDart>();

  String GenAuthBuffer(int appId, String roomId, String userId, String key) {
    final int authBufferSize = 1024;
    final authBuffer = calloc<Int8>(authBufferSize);
    int ret = GenAuthBufferPtr(
      appId,
      roomId.toNativeUtf8().cast<Int8>(),
      userId.toNativeUtf8().cast<Int8>(),
      key.toNativeUtf8().cast<Int8>(),
      authBuffer,
      authBufferSize,
    );

    Uint8List currentBuffer = Uint8List.fromList(authBuffer.asTypedList(ret));
    String result = base64Encode(currentBuffer);
    calloc.free(authBuffer);
    return result;
  }

  late final GMEEnterRoomDart EnterRoomPtr = _gmeSdkLib!
      .lookup<NativeFunction<GMEEnterRoomNative>>('QAVSDK_AVContext_EnterRoom')
      .asFunction<GMEEnterRoomDart>();

  int EnterRoom(String roomId, int roomType, String userSig) {
    Uint8List authBuffer = Uint8List.fromList(base64Decode(userSig));
    final authBufferPtr = calloc<Int8>(authBuffer.length);
    for (int i = 0; i < authBuffer.length; i++) {
      authBufferPtr[i] = authBuffer[i];
    }
    int result = EnterRoomPtr(
      roomId.toNativeUtf8().cast<Int8>(),
      authBufferPtr,
      authBuffer.length,
      roomType,
    );
    calloc.free(authBufferPtr);
    return result;
  }

  late final GMEExitRoomDart ExitRoomPtr = _gmeSdkLib!
      .lookup<NativeFunction<GMEExitRoomNative>>('QAVSDK_AVContext_ExitRoom')
      .asFunction<GMEExitRoomDart>();

  int ExitRoom() {
    return ExitRoomPtr();
  }

  late final SetRecvMixStreamCountDart SetRecvMixStreamCountPtr = _gmeSdkLib!
      .lookup<NativeFunction<SetRecvMixStreamCountNative>>(
          'QAVSDK_AVContext_SetRecvMixStreamCount')
      .asFunction<SetRecvMixStreamCountDart>();

  int SetRecvMixStreamCount(int count) {
    return SetRecvMixStreamCountPtr(count);
  }

  late final GMEIsRoomEnteredDart IsRoomEnteredPtr = _gmeSdkLib!
      .lookup<NativeFunction<GMEIsRoomEnteredNative>>(
        'QAVSDK_AVContext_IsRoomEntered',
      )
      .asFunction<GMEIsRoomEnteredDart>();

  bool IsRoomEntered() {
    return (IsRoomEnteredPtr() == 1);
  }

  late final SetLogLevelDart SetLogLevelPtr = _gmeSdkLib!
      .lookup<NativeFunction<SetLogLevelNative>>('QAVSDK_AVContext_SetLogLevel')
      .asFunction<SetLogLevelDart>();

  int SetLogLevel(int levelWrite, int levelPrint) {
    return SetLogLevelPtr(levelWrite, levelPrint);
  }

  late final SetLogPathDart SetLogPathPtr = _gmeSdkLib!
      .lookup<NativeFunction<SetLogPathNative>>('QAVSDK_AVContext_SetLogPath')
      .asFunction<SetLogPathDart>();

  int SetLogPath(String logDir) {
    return SetLogPathPtr(logDir.toNativeUtf8().cast<Int8>());
  }

  late final SetAdvanceParamsDart SetAdvanceParamsPtr = _gmeSdkLib!
      .lookup<NativeFunction<SetAdvanceParamsNative>>(
          'QAVSDK_AVContext_SetAdvanceParams')
      .asFunction<SetAdvanceParamsDart>();

  int SetAdvanceParams(String key, String value) {
    return SetAdvanceParamsPtr(
        key.toNativeUtf8().cast<Int8>(), value.toNativeUtf8().cast<Int8>());
  }
}
