import { getCapturePhotoYunSign, saveCapturePhoto } from "@/api/login";
import { HOST_FILE_HASH_MAP } from "@/constants/constants";
import { throttle, xor } from "lodash-es";

export function isElectron() {
  return typeof window.nodeRequire != "undefined";
}

const fs: typeof import("fs") = isElectron() && window.nodeRequire("fs");

/** 执行本地exe文件 */
export function execLocal(exeName: string): Promise<void> {
  if (!isElectron()) {
    logger({
      pgu: "AUTO",
      cnl: ["local", "server"],
      dtl: "不在Electron中，调用 " + exeName + " 失败",
    });
    throw new Error("不在Electron中，调用 fs 失败");
  }
  if (import.meta.env.DEV) {
    return Promise.resolve();
  }
  // if (import.meta.env.MODE !== "production") {
  //   return Promise.resolve();
  // }
  // FIXME: 在苹果电脑跳过检测
  if (navigator.userAgent.includes("Macintosh")) {
    fs.writeFileSync("remoteApplication.txt", "");
    fs.writeFileSync("CameraInfo.txt", "[{}]");
    return Promise.resolve();
  }

  return new Promise<void>((resolve) => {
    // eslint-disable-next-line
    window
      .nodeRequire("node-cmd")
      .get(
        "cmd /c chcp 65001>nul && " + exeName,
        async (err: Error, data: string, stderr: string) => {
          console.log(exeName, err, data); // 未免过多日志，此处后续可以关闭
          logger({
            pgu: "AUTO",
            cnl: ["console", "local", "server"],
            act: exeName + " called",
            ejn: JSON.stringify(err),
            dtl: data,
            ext: {
              stderr: JSON.stringify(stderr),
              absPath: exeName.includes(":"),
            },
          });
          // 如果相对路径没找到，则通过绝对路径来执行
          if (!exeName.includes(":") && err) {
            const remote: typeof import("electron").remote =
              window.nodeRequire("electron").remote;
            const fs: typeof import("fs") = remote.require("fs");

            const path: typeof import("path") = remote.require("path");

            const [exePath, exeParams] = exeName.split(" ");
            const absPath = path.join(
              remote.app.getAppPath(),
              "../../",
              exePath
            );
            if (fs.existsSync(absPath)) {
              try {
                await execLocal([absPath, exeParams].join(" ").trim());
              } catch (error) {
                console.log("second try error", absPath);
                logger({
                  cnl: ["local", "server"],
                  dtl: "second try error: " + absPath,
                });
              }
            }
          }
          resolve();
        }
      );
  });
}

/** 文件路径是否存在 */
export function fileExists(file: string): boolean {
  // FIXME: 在苹果电脑跳过检测
  if (navigator.userAgent.includes("Macintosh")) {
    return true;
  }
  if (!isElectron()) {
    logger({
      pgu: "AUTO",
      cnl: ["local", "server"],
      dtl: "不在Electron中，调用 fs 失败",
    });
    throw new Error("不在Electron中，调用 fs 失败");
  }
  return fs.existsSync(file);
}

/** 检测当前运行的进程中是否有“向日葵”和"ToDesk" */
export function nodeCheckRemoteDesktop() {
  if (import.meta.env.DEV) return {};
  // FIXME: 在苹果电脑跳过检测
  if (navigator.userAgent.includes("Macintosh")) return {};

  logger({
    pgu: "AUTO",
    cnl: ["local", "server"],
    key: "nodeCheckRemoteDesktop",
  });

  // eslint-disable-next-line @typescript-eslint/no-unsafe-call
  const appList: string = window
    .nodeRequire("child_process")
    .execSync("cmd /c chcp 65001>nul && tasklist /FO CSV")
    .toString();
  // console.debug(appList);

  const regex = new RegExp("sunloginclient|选择免安装运行，截图识别", "gi");
  const hasSun = !!(appList?.match(regex) || []).length;

  let hasTodesk = false;
  if ((appList.match(/todesk/gi) || []).length > 0) {
    hasTodesk = true;
  }
  return { hasSun, hasTodesk };
}

let previousAppList: string[] = [];
/** 将电脑运行的进程记录到日志 */
export function nodeCheckProcess(): void {
  if (import.meta.env.DEV) return;
  // FIXME: 在苹果电脑跳过检测
  if (navigator.userAgent.includes("Macintosh")) return;

  try {
    // eslint-disable-next-line @typescript-eslint/no-unsafe-call
    const appListCP: string = window
      .nodeRequire("child_process")
      .execSync("cmd /c chcp 65001>nul && tasklist /FO CSV")
      .toString();
    // 不能打印，electron-log 不能接收
    // console.log(appList);
    let appList = appListCP.split("\r\n");
    appList.shift();
    appList = appList.map((v) => v.split(",")[0]);
    const xorRes = xor(previousAppList, appList);
    if (xorRes && xorRes.length > 0) {
      logger({
        pgu: "AUTO",
        cnl: ["local", "server"],
        key: "nodeCheckProcess",
        dtl: xorRes.join(" ||| "),
      });
    }
    previousAppList = appList;
  } catch (error) {
    logger({
      cnl: ["console", "local", "server"],
      pgu: "AUTO",
      ejn: JSON.stringify(error),
    });
  }
}

/** 检测当前程序包的完整性。 */
export function checkMainExe(): boolean {
  try {
    let iid: string = window.nodeRequire("process").pid;
    const cp: typeof import("child_process") =
      window.nodeRequire("child_process");
    iid = cp
      .execSync(
        `cmd /c chcp 65001>nul && C:\\Windows\\System32\\wbem\\wmic process where ^(processid^=${iid}^) get parentprocessid /value`
      )
      .toString();
    iid = iid.replace("ParentProcessId=", "").trim();
    console.log(iid);
    logger({
      cnl: ["local", "console", "server"],
      key: "checkMainExe",
      dtl: `iid1: ${iid}`,
    });
    iid = cp
      .execSync(
        `cmd /c chcp 65001>nul && C:\\Windows\\System32\\wbem\\wmic process where ^(processid^=${iid}^) get parentprocessid /value`
      )
      .toString();
    iid = iid.replace("ParentProcessId=", "").trim();
    logger({
      cnl: ["local", "console", "server"],
      key: "checkMainExe",
      dtl: `iid2: ${iid}`,
    });

    const executablePathBuffer = cp.execSync(
      `cmd /c chcp 65001>nul && C:\\Windows\\System32\\wbem\\wmic process where ^(processid^=${iid}^) get executablepath /value`
    );
    console.log(executablePathBuffer);
    const encoding = window.nodeRequire("encoding");
    // eslint-disable-next-line @typescript-eslint/no-unsafe-call
    let executablePath: string = encoding
      .convert(executablePathBuffer, "utf8", "gbk")
      .toString();
    logger({
      cnl: ["local", "console", "server"],
      key: "checkMainExe",
      dtl: executablePath,
    });
    executablePath = executablePath
      .replace("ExecutablePath=", "")
      .trim()
      .replace(/&amp;/g, "&");
    // @ts-expect-error
    // eslint-disable-next-line no-undef
    const portableFile = window.proceess?.env?.PORTABLE_EXECUTABLE_FILE;
    if (executablePath === portableFile) {
      const crypto: typeof import("crypto") = window.nodeRequire("crypto");
      const getHash = crypto
        .createHmac("sha256", "abcdefg")
        .update(fs.readFileSync(executablePath))
        .digest("hex");
      console.log("the hash: ", getHash);
      logger({
        cnl: ["local", "console", "server"],
        key: "checkMainExe",
        dtl: `the hash: ${getHash}`,
      });
      if (HOST_FILE_HASH_MAP.get(window.location.hostname) === getHash) {
        return true;
      }
    }
    // check filepath executablePath md5
  } catch (error) {
    console.log(error);
    logger({
      cnl: ["local", "console", "server"],
      key: "checkMainExe",
      ejn: JSON.stringify(error),
    });
  }
  return false;
}

/** 初始化桌面抓拍 */
export function initScreenShot() {
  if (import.meta.env.DEV) return;
  if (!isElectron()) return;

  function handleStream(stream: MediaStream) {
    const video: HTMLVideoElement = document.querySelector("#ssVideo")!;
    video.srcObject = stream;
    video.onloadedmetadata = () => video.play();
  }

  const electron: typeof import("electron") = window.nodeRequire("electron");

  electron.desktopCapturer.getSources(
    { types: ["window", "screen"] },
    (e: any, sources: { id: string; name: string }[]) => {
      console.log(e, sources);
      for (const source of sources) {
        console.log(source);
        if (source.name === "Entire screen") {
          try {
            navigator.mediaDevices
              .getUserMedia({
                audio: false,
                video: {
                  // @ts-expect-error 不确定是chrome/electron标准是否不一样，需要测试
                  mandatory: {
                    chromeMediaSource: "desktop",
                    chromeMediaSourceId: source.id,
                    minWidth: 600,
                    maxWidth: 600,
                    minHeight: 480,
                    maxHeight: 480,
                  },
                },
              })
              .then((stream) => handleStream(stream))
              .catch((e) =>
                logger({
                  cnl: ["local", "server"],
                  pgu: "AUTO",
                  act: "ss-failed",
                  possibleError: e,
                })
              );
          } catch (err) {
            logger({
              cnl: ["local", "server"],
              pgu: "AUTO",
              act: "ss-failed",
              ejn: JSON.stringify(err),
            });
          }
          return;
        }
      }
    }
  );
}

/** 保存当前屏幕截图 */
export async function getScreenShot({ cause = "ss-none" }) {
  const video: HTMLVideoElement = document.querySelector("#ssVideo")!;
  async function getSnapShot() {
    return new Promise((resolve, reject) => {
      if (video.readyState !== 4 || !(<MediaStream>video.srcObject)?.active) {
        reject("desktop没有正常启用");
      }
      video.pause();
      const canvas = document.createElement("canvas");
      canvas.width = 220;
      canvas.height = 165;
      const context = canvas.getContext("2d");
      context?.drawImage(video, 0, 0, 220, 165);
      canvas.toBlob(resolve, "image/png", 0.95);
    });
  }
  if (window.location.pathname.includes("/login")) return;
  const captureBlob = await getSnapShot();
  const res = await getCapturePhotoYunSign({ fileSuffix: "png" });
  try {
    await saveCapturePhoto(res.data.formUrl, res.data.formParams, {
      file: captureBlob,
    });
    logger({
      pgu: "AUTO",
      cnl: ["server"],
      dtl: "桌面抓拍保存成功",
      ext: {
        resultUrl: res.data.accessUrl,
        cause,
      },
    });
  } catch (error) {
    console.log(error);
    logger({
      pgu: "AUTO",
      cnl: ["server"],
      dtl: "桌面抓拍失败",
      ejn: JSON.stringify(error),
      ext: {
        cause,
      },
    });
  } finally {
    video && video.play();
  }
}

/** 在app resize时触发 */
export function registerOnResize() {
  const throttledResizeLog = throttle(() => {
    logger({
      cnl: ["local", "server"],
      pgu: "AUTO",
      act: "registerOnResize",
      ext: {
        width: window.screen.width,
        height: window.screen.height,
        screenX: window.screen.availWidth,
        screenY: window.screen.availHeight,
        clientWidth: document.documentElement.clientWidth,
        clientHeight: document.documentElement.clientHeight,
        windowInnerWidth: window.innerWidth,
        windowInnerHeight: window.innerHeight,
        windowOuterWidth: window.outerWidth,
        windowOuterHeight: window.outerHeight,
      },
    });
    void getScreenShot({ cause: "ss-registerOnResize" });
  }, 3000);
  window.onresize = throttledResizeLog;
}
