
/*
@param moduleName — Module name or path.
@param exportName
@param retType
@param argTypes
@param abiOrOptions
*/
function EZ生成NativeFunction(exportName: string, 
    retType: NativeFunctionReturnType, 
    argTypes: [] | NativeFunctionArgumentType[], 
    abiOrOptions: NativeABI | NativeFunctionOptions = "default",
    moduleName: string = "User32.dll",
  ) {
  let address = Module.findExportByName(moduleName, exportName);
  return new NativeFunction(address!, retType, argTypes, abiOrOptions);
}

export default class User32 {
  static Const = {
    SW_RESTORE: 9,
    HWND_TOPMOST: -1,
    HWND_NOTOPMOST: -2,
    SWP_NOSIZE: 0x0001,
    SWP_NOMOVE: 0x0002,

    MOUSEEVENTF_LEFTDOWN: 0x0002,
    MOUSEEVENTF_LEFTUP: 0x0004,
    MOUSEEVENTF_RIGHTDOWN: 0x0008,
    MOUSEEVENTF_RIGHTUP: 0x0010,

    MB_OK: 0x00000000,
    MB_OKCANCEL: 0x00000001,
  }

  // BOOL GetClientRect(
  //     [in]  HWND   hWnd,
  //     [out] LPRECT lpRect
  // );
  private static address_GetClientRect: NativePointerValue | null;
  static GetClientRect(hWnd: NativePointerValue, lpRect: NativePointerValue): number {
    if (this.address_GetClientRect == null) {
      this.address_GetClientRect = Module.findExportByName("User32.dll", "GetClientRect");
    }
    return new NativeFunction(this.address_GetClientRect!, "bool", ["pointer", "pointer"])(hWnd, lpRect);
  }

  // BOOL InvalidateRect(
  //     [in] HWND       hWnd,
  //     [in] const RECT * lpRect,
  //     [in] BOOL       bErase
  // );
  private static address_InvalidateRect: NativePointerValue | null;
  static InvalidateRect(hWnd: NativePointerValue, lpRect: NativePointerValue, bErase: number): number {
    if (this.address_InvalidateRect == null) {
      this.address_InvalidateRect = Module.findExportByName("User32.dll", "InvalidateRect");
    }
    return new NativeFunction(this.address_InvalidateRect!, "bool", ["pointer", "pointer", 'bool'])(hWnd, lpRect, bErase);
  }

  
  // BOOL SetForegroundWindow(
  //     [in] HWND hWnd
  // );
  private static func_SetForegroundWindow: AnyFunction;
  static SetForegroundWindow(hWnd: NativePointerValue): number {
    if (this.func_SetForegroundWindow == null) {
      this.func_SetForegroundWindow = EZ生成NativeFunction("SetForegroundWindow", "bool", ["pointer"]);
    }
    return this.func_SetForegroundWindow(hWnd);
  }

  // BOOL ShowWindow(
  //     [in] HWND hWnd,
  //     [in] int  nCmdShow
  // );
  private static address_ShowWindow: NativePointerValue | null;
  static ShowWindow(hWnd: NativePointerValue, nCmdShow: number): number {
      if (this.address_ShowWindow == null) {
          this.address_ShowWindow = Module.findExportByName("User32.dll", "ShowWindow");
      }
      return new NativeFunction(this.address_ShowWindow!, "bool", ["pointer", "int"])(hWnd, nCmdShow);
  }

  // BOOL SetWindowPos(
  //     [in]           HWND hWnd,
  //     [in, optional] HWND hWndInsertAfter,
  //     [in]           int  X,
  //     [in]           int  Y,
  //     [in]           int  cx,
  //     [in]           int  cy,
  //     [in]           UINT uFlags
  // );
  private static address_SetWindowPos: NativePointerValue | null;
  static SetWindowPos(hWnd: NativePointerValue, hWndInsertAfter: number, X: number, Y: number, cx: number, cy: number, uFlags: number): number {
      if (this.address_SetWindowPos == null) {
          this.address_SetWindowPos = Module.findExportByName("User32.dll", "SetWindowPos");
      }
      return new NativeFunction(this.address_SetWindowPos!, "bool", ["pointer", "int", "int", "int", "int", "int", "int"])(hWnd, hWndInsertAfter, X, Y, cx, cy, uFlags);
  }

  private static address_GetForegroundWindow: NativePointerValue | null;
  static GetForegroundWindow(): NativePointerValue {
      // HWND GetForegroundWindow();
      if (this.address_GetForegroundWindow == null) {
          this.address_GetForegroundWindow = Module.findExportByName("User32.dll", "GetForegroundWindow");
      }
      return new NativeFunction(this.address_GetForegroundWindow!, "pointer", [])();
  }
  
  // DWORD GetWindowThreadProcessId(
  //     [in]            HWND    hWnd,
  //     [out, optional] LPDWORD lpdwProcessId
  // );
  private static func_GetWindowThreadProcessId: AnyFunction;
  static GetWindowThreadProcessId(hWnd: NativePointerValue, lpdwProcessId: NativePointerValue): number {
      if (this.func_GetWindowThreadProcessId == undefined) {
          let address = Module.findExportByName("User32.dll", "GetWindowThreadProcessId");
          this.func_GetWindowThreadProcessId = new NativeFunction(address!, "int", ["pointer", "pointer"]);
      }
      return this.func_GetWindowThreadProcessId(hWnd, lpdwProcessId);
  }

  // BOOL AttachThreadInput(
  //     [in] DWORD idAttach,
  //     [in] DWORD idAttachTo,
  //     [in] BOOL  fAttach
  // );
  private static func_AttachThreadInput: AnyFunction;
  static AttachThreadInput(idAttach: number, idAttachTo: number, fAttach: number): number {
    if (this.func_AttachThreadInput == null) {
      let address_AttachThreadInput = Module.findExportByName("User32.dll", "AttachThreadInput");
      this.func_AttachThreadInput = new NativeFunction(address_AttachThreadInput!, "int", ["int", "int", "int"]);
    }
    return this.func_AttachThreadInput(idAttach, idAttachTo, fAttach);
  }

  // 获取软件窗口位置_设置鼠标指针位置()
    private static func_GetWindowRect: AnyFunction;
    static GetWindowRect(hWnd: NativePointerValue, lpRect: NativePointerValue): number {
        //    BOOL GetWindowRect(
        //        [in]  HWND   hWnd,
        //        [out] LPRECT lpRect
        //    );
        if (this.func_GetWindowRect == null) {
            let address = Module.findExportByName("User32.dll", "GetWindowRect");
            this.func_GetWindowRect = new NativeFunction(address!, "bool", ["pointer", "pointer"]);
        }
        return this.func_GetWindowRect(hWnd, lpRect);
    }

    private static func_SetCursorPos: AnyFunction;
    static SetCursorPos(X: number, Y: number): number {
        // BOOL SetCursorPos(
        //     [in] int X,
        //     [in] int Y
        // );
        if (this.func_SetCursorPos == null) {
            let address = Module.findExportByName("User32.dll", "SetCursorPos");
            this.func_SetCursorPos = new NativeFunction(address!, "bool", ["int", "int"]);
        }
        return this.func_SetCursorPos(X, Y);
    }

    private static func_GetCursorPos: AnyFunction;
    static GetCursorPos(lpPoint: NativePointerValue): number {
        // BOOL GetCursorPos(
        //     [out] LPPOINT lpPoint
        // );
        if (this.func_GetCursorPos == null) {
            let address = Module.findExportByName("User32.dll", "GetCursorPos");
            this.func_GetCursorPos = new NativeFunction(address!, "bool", ["pointer"]);
        }
        return this.func_GetCursorPos(lpPoint);
    }

    //mouse_event
    private static func_MouseEvent: AnyFunction;
    static MouseEvent(dwFlags: number, dx: number, dy: number, dwData: number, dwExtraInfo: NativePointerValue): void {
        // void mouse_event(
        //     [in] DWORD     dwFlags,
        //     [in] DWORD     dx,
        //     [in] DWORD     dy,
        //     [in] DWORD     dwData,
        //     [in] ULONG_PTR dwExtraInfo
        // );
        if (this.func_MouseEvent == null) {
            let address = Module.findExportByName("User32.dll", "mouse_event");
            this.func_MouseEvent = new NativeFunction(address!, "void", ["int", "int", "int", "int", "pointer"]);
        }
        return this.func_MouseEvent(dwFlags, dx, dy, dwData, dwExtraInfo);
    }

    //GetMessageExtraInfo 
    private static func_GetMessageExtraInfo: AnyFunction;
    static GetMessageExtraInfo(): NativePointerValue {
        // LPARAM GetMessageExtraInfo();
        if (this.func_GetMessageExtraInfo == null) {
            let address = Module.findExportByName("User32.dll", "GetMessageExtraInfo");
            this.func_GetMessageExtraInfo = new NativeFunction(address!, "pointer", []);
        }
        return this.func_GetMessageExtraInfo();
    }

    //    int MessageBox(
    //        [in, optional] HWND    hWnd,
    //        [in, optional] LPCTSTR lpText,
    //        [in, optional] LPCTSTR lpCaption,
    //        [in]           UINT    uType
    //    );
    private static func_MessageBox: AnyFunction;
    static MessageBox(hWnd: NativePointerValue, lpText: NativePointerValue, lpCaption: NativePointerValue, uType: number): number {
      if (this.func_MessageBox == null) {
        this.func_MessageBox = EZ生成NativeFunction("MessageBoxW", "int", ["pointer", "pointer", "pointer", 'int']);
      }
      return this.func_MessageBox(hWnd, lpText, lpCaption, uType);
    }
}