import User32 from '../winapi/user32'
import Kernel32 from '../winapi/kernel32'

class L07 {
  private module_name_winmine = "winmine.exe";
  private module_winmine: Module;
  private offset地雷数量: number = 0x56a4;
  private offset棋盘高度: number = 0x56a8;
  private offset棋盘宽度: number = 0x56ac;
  private height: number = 0;
  private width: number = 0;
  private mine_count: number = 0;
  private head: NativePointer = ptr(0);
  private hWnd: NativePointer = ptr(0);
  // 设置鼠标位置_自动点击鼠标
  private start_x = 0;
  private start_y = 0;
  private step = 16;

  constructor() {
    console.log(
      "======================",
      new Date().toISOString(),
      "=========================="
    );
    console.log("Frida.version", Frida.version);
    //获取模块基址
    this.module_winmine = Process.getModuleByName(this.module_name_winmine);

    // 初始化游戏相关数据
    this.height = this.module_winmine.base.add(this.offset棋盘高度).readU32();
    this.width = this.module_winmine.base.add(this.offset棋盘宽度).readU32();
    this.mine_count = this.module_winmine.base.add(this.offset地雷数量).readU32();
    this.head = this.module_winmine.base.add(0x5340);
    this.hWnd = this.module_winmine.base.add(0x5B24).readPointer();
  }

  board_repaint() {
    const lpRect = Memory.alloc(4 * 4);
    User32.GetClientRect(this.hWnd, lpRect);
     
    User32.InvalidateRect(this.hWnd, lpRect, 1);
  }

  将目标窗口切换到前台() {
    let hForeWnd = User32.GetForegroundWindow();
    let dwCurID = Kernel32.GetCurrentThreadId();
    let dwForeID = User32.GetWindowThreadProcessId(hForeWnd, ptr(0));
    // User32.AttachThreadInput(dwCurID, dwForeID, 1);
    User32.ShowWindow(this.hWnd, User32.Const.SW_RESTORE);

    User32.SetForegroundWindow(this.hWnd)
    // User32.SetWindowPos(this.hWnd, User32.Const.HWND_TOPMOST, 0, 0, 0, 0, User32.Const.SWP_NOSIZE | User32.Const.SWP_NOMOVE);
    // User32.SetWindowPos(this.hWnd, User32.Const.HWND_NOTOPMOST, 0, 0, 0, 0, User32.Const.SWP_NOSIZE | User32.Const.SWP_NOMOVE);

    // User32.AttachThreadInput(dwCurID, dwForeID, 0);
  }

  获取软件窗口位置_设置鼠标指针位置() {
    let lpOrgRect = Memory.alloc(4 * 4);
    User32.GetCursorPos(lpOrgRect);

    // typedef struct tagRECT {
    //   LONG left;
    //   LONG top;
    //   LONG right;
    //   LONG bottom;
    // } RECT, *PRECT, *NPRECT, *LPRECT;    
    let lpRect = Memory.alloc(4 * 4);
    User32.GetWindowRect(this.hWnd, lpRect);
    console.log("left", lpRect.readU32());
    console.log("top", lpRect.add(4).readU32());
    console.log("right", lpRect.add(8).readU32());
    console.log("bottom", lpRect.add(12).readU32());
    this.start_x = lpRect.readU32() + 7;
    this.start_y = lpRect.add(4).readU32() + 92;
    console.log("start_x", this.start_x);
    console.log("start_y", this.start_y);

    // User32.SetCursorPos(lpRect.readU32(), lpRect.add(4).readU32());
    // Kernel32.Sleep(2000);
    // User32.SetCursorPos(lpOrgRect.readU32(), lpOrgRect.add(4).readU32());

  }

  mouse_click(x: number, y: number, left_click: boolean = true) {
      User32.SetCursorPos(this.start_x + this.step * x, this.start_y + this.step * y);
      if (left_click) {
          User32.MouseEvent(User32.Const.MOUSEEVENTF_LEFTDOWN, 0, 0, 0, User32.GetMessageExtraInfo());
          User32.MouseEvent(User32.Const.MOUSEEVENTF_LEFTUP, 0, 0, 0, User32.GetMessageExtraInfo());
      }
      else {
          User32.MouseEvent(User32.Const.MOUSEEVENTF_RIGHTDOWN, 0, 0, 0, User32.GetMessageExtraInfo());
          User32.MouseEvent(User32.Const.MOUSEEVENTF_RIGHTUP, 0, 0, 0, User32.GetMessageExtraInfo());
      }
  }

  设置鼠标位置_自动点击鼠标() {
    this.mouse_click(2, 2, false);
  }

  run() {
    //遍历棋盘，按行遍历
    for (let i = 0; i < this.height + 2; i++) {
      //按列遍历
      let data = [];
      for (let j = 0; j < this.width + 2; j++) {
        let byte_data = this.head.add(j + 0x20 * i).readU8();
        data.push(byte_data.toString(16).padStart(2, "0"));

        // 如果是地雷，将其状态改为标记
        if  (byte_data == 0x8F) {
          this.head.add(j + 0x20 * i).writeU8(0x8E);
        }
      }
      console.log(data.join(" "));
    }

    // 重绘窗口区域
    this.board_repaint()

    this.将目标窗口切换到前台()
    this.获取软件窗口位置_设置鼠标指针位置()
    this.设置鼠标位置_自动点击鼠标()
  }
}

let l07 = new L07();
l07.run();
