import { NormMsg, decodeNormMsg, encodeNormMsg } from "./entity/message";
import { Controller } from "../core/controller";
//@ts-ignore
import { saveAs } from "file-saver";

type UploadItem = {
  id: string;
  fpath: string;
  dir: string;
  name?: string;
  url?: string;
  size?: number;
};

export type FileInfo = {
  Fpath: string;
  Size: number;
  CreateAt: number; //info.ModTime().Unix()
};

export class DeviceController extends Controller {
  ipc: any;

  profile = { wsPort: "", appGuid: "" };
  appDataDir = "";
  httpServer = "";
  isEnvOk = false;

  constructor() {
    super();

    //@ts-ignore
    if (window.ipc) {
      //@ts-ignore
      this.ipc = window.ipc;
      this.isEnvOk = true;
    } else {
      this.ipc = {
        emit(name: string, ...args: any[]) {
          console.error("emit msg=>", name, args);
        },
        on(name: string) {
          console.error("on message", name);
        },
      };
    }
    this.initEvent();
  }
  _conn?: WebSocket;

  initEvent() {
    const scope = this;
    this.ipc.on("OnDragEnter", function (files: string[]) {
      scope.emit("onDragEnter", files);
    });
    this.ipc.on("downloadsucc", (fpath: string, size: number) => {
      scope.emit("downloadsucc", fpath, size);
    });

    this.ipc.emit("GetSocketUri", [], (uri: string) => {
      let conn = new WebSocket(uri);
      conn.onopen = (e) => {
        console.log("bus socket connected!!!");
      };
      conn.onclose = (evt) => {
        console.log("app bus socket conn closed", evt);

        setTimeout(() => {
          this._conn = new WebSocket(uri);
        }, 1000);
      };
      conn.onmessage = function (evt) {
        if (!evt.data || evt.data == "") return;

        try {
          const blob = evt.data as Blob;
          blob.arrayBuffer().then((buff) => {
            const msg = decodeNormMsg(new Uint8Array(buff));
            scope.emit("on" + msg.sub, msg);
          });
        } catch (error) {
          console.error(evt.data, typeof evt.data, error);
        }
      };
      this._conn = conn;
    });
  }

  async onReady() {
    if (!this.isEnvOk) return;

    this.profile = (await this.GetLocalAppProfile()) || {
      wsPort: "",
      appGuid: "",
    };
    this.appDataDir = await this.GetAppDataDir();
    const httpServer = await this.StartHttpServer(`${this.appDataDir}/screen`);
    this.httpServer = httpServer.substring(0, httpServer.length - 1);
    console.log("current app profile=>", this.profile);
  }

  //选择磁盘文件夹
  SelectDir(): Promise<string> {
    const sid = Date.now();
    const cbname = "c" + sid;
    return new Promise((r) => {
      const ipc = this.ipc;
      ipc.emit("SelectDir", [sid], function (ok: boolean) {
        console.log("call=>", ok);
        if (!ok) {
          r("");
        }
        ipc.on(cbname, function (dir: string) {
          r(dir);
        });
      });
    });
  }
  IsDirEmpty(dir: string): Promise<boolean> {
    return new Promise((r) => {
      const ipc = this.ipc;
      ipc.emit("IsDirEmpty", [dir], function (ok: boolean) {
        r(ok);
      });
    });
  }
  IsFileExit(fpath: string): Promise<boolean> {
    return new Promise((r) => {
      const ipc = this.ipc;
      ipc.emit("IsFileExit", [fpath], function (ok: boolean) {
        r(ok);
      });
    });
  }

  WriteFileText(dir: string, content: string): Promise<boolean> {
    return new Promise((r) => {
      const ipc = this.ipc;
      ipc.emit("WriteFileText", [dir, content], function (ok: boolean) {
        r(ok);
      });
    });
  }

  ReadFileText(dir: string): Promise<{ error: string; text: string }> {
    return new Promise((r) => {
      const ipc = this.ipc;
      ipc.emit("ReadFileText", [dir], function (data: any) {
        r(data);
      });
    });
  }

  //拷贝文件
  CopyFile(srcFile: string, targetFile: string): Promise<boolean> {
    const sid = Date.now();
    const cbname = "copy" + sid;
    return new Promise((r) => {
      const ipc = this.ipc;
      ipc.on(cbname, function (ok: boolean) {
        r(ok);
      });
      ipc.emit("CopyFile", [cbname, srcFile, targetFile]);
    });
  }

  //保存应用级的配置
  SaveSysConfigItem(key: string, value: string): Promise<boolean> {
    return new Promise((r) => {
      const ipc = this.ipc;
      ipc.emit("SaveAppConfigItem", [key, value], function (data: any) {
        r(data);
      });
    });
  }
  GetSysConfigItem(key: string): Promise<{ error: string; text: string }> {
    return new Promise((r) => {
      const ipc = this.ipc;
      ipc.emit("GetAppConfigItem", [key], function (data: any) {
        r(data);
      });
    });
  }
  RemoveSysConfigItem(key: string): Promise<{ error: string; text: string }> {
    return new Promise((r) => {
      const ipc = this.ipc;
      ipc.emit("RemoveSysConfigItem", [key], function (data: any) {
        r(data);
      });
    });
  }

  //获取应用的baseUrl
  GetSysDataBaseUrl() {
    return new Promise((r) => {
      const ipc = this.ipc;
      ipc.emit("GetAppDataBaseUrl", [], function (data: any) {
        r(data);
      });
    });
  }

  //获取应用的baseUrl
  CopyFileToAppData(src: string, targetRelativePath: string): Promise<string> {
    return new Promise((r) => {
      const ipc = this.ipc;
      ipc.emit(
        "CopyFileToAppData",
        [src, targetRelativePath],
        function (data: any) {
          r(data);
        }
      );
    });
  }

  RemoveAppData(targetRelativePath: string): Promise<boolean> {
    return new Promise((r) => {
      const ipc = this.ipc;
      ipc.emit("RemoveAppData", [targetRelativePath], function (data: any) {
        r(data);
      });
    });
  }

  //打开文件所在的目录
  OpenDir(dir: string): Promise<boolean> {
    return new Promise((r) => {
      const ipc = this.ipc;
      ipc.emit("OpenDir", [dir], function (data: any) {
        r(data);
      });
    });
  }

  SelectOneFilePath(title: string, filters: string): Promise<string> {
    const sid = Date.now();

    return new Promise((r) => {
      const ipc = this.ipc;
      const cbname = "c" + sid;
      ipc.emit(
        "SelectOneFilePath",
        [sid, title, filters],
        function (ok: boolean) {
          if (!ok) {
            r("");
          }
          ipc.on(cbname, function (dir: string) {
            r(dir);
          });
        }
      );
    });
  }

  //开启projects 的httpserver
  StartHttpServer(prjFile: string): Promise<string> {
    console.log("start server ", prjFile);
    const sid = Date.now();
    return new Promise((r) => {
      const ipc = this.ipc;
      ipc.emit("StartProjectHttpServer", [prjFile], function (data: any) {
        r(data);
      });
    });
  }

  //下在线文件 默认超时时间20分钟
  DownloadFile(
    url: string,
    fpath: string,
    timeoutSecend: number = 60 * 20,
    cb?: (event: "start" | "progress" | "error" | "succ", p1: NormMsg) => void
  ): Promise<boolean> {
    const sid = "d" + Date.now();
    return new Promise((r) => {
      console.log(url, "==>", fpath);
      const cancel = this.OnMsg(sid, (data) => {
        cb && cb(data.type as any, data);
        if (data.type == "succ") {
          r(true);
          cancel.unbind();
          return;
        }
        if (data.type == "error") {
          r(false);
          cancel.unbind();
        }
      });

      const ipc = this.ipc;
      ipc.emit(
        "DownloadFile",
        [sid, fpath, url, timeoutSecend],
        function (err: string) {
          console.log("DownloadFile callback");
          if (err) {
            console.error(err);
            r(false);
          }
        }
      );
    });
  }

  Unzip(
    fpath: string,
    distDir: string,
    cb?: (event: "progress" | "error" | "succ", p1: NormMsg) => void
  ) {
    const sid = "unzip" + Date.now();

    return new Promise((r) => {
      const cancel = this.OnMsg(sid, (data) => {
        cb && cb(data.type as any, data);
        if (data.type == "succ") {
          r(true);
          cancel.unbind();
          return;
        }
        if (data.type == "error") {
          r(false);
          cancel.unbind();
        }
      });
      const ipc = this.ipc;
      ipc.emit("Unzip", [sid, fpath, distDir]);
    });
  }

  //获取文件夹的大小
  //文件目录不要太大，不然会卡死程序
  GetDirSize(dir: string): Promise<number> {
    return new Promise((r) => {
      const ipc = this.ipc;
      ipc.emit("GetDirSize", [dir], function (size: number) {
        r(size);
      });
    });
  }

  //获取系统数据目录
  GetAppDataDir(): Promise<string> {
    return new Promise((r) => {
      const ipc = this.ipc;
      ipc.emit("GetAppDataDir", [], function (dir: string) {
        r(dir);
      });
    });
  }

  OpenAssetWindow(projectPath: string) {
    return new Promise((r) => {
      const ipc = this.ipc;
      ipc.emit(
        "openAssetsWindow",
        [
          `${location.host}/library.html?path=${projectPath}`,
          "资源管理库",
          1280,
          960,
        ],
        function (ok: boolean) {
          r(ok);
        }
      );
    });
  }

  SendMsg(subject: string, msg: string) {
    const conn = this._conn;
    if (!conn) {
      console.error("应用socket异常");
      return;
    }
    conn.send(encodeNormMsg({ sub: subject, msg: msg }));
  }

  OnMsg(subject: string, cb: (msg: NormMsg) => any) {
    return this.on("on" + subject, cb);
  }

  //同步阻塞当前进程
  UploadSync(files: UploadItem[]): Promise<UploadItem[]> {
    return new Promise((r) => {
      const ipc = this.ipc;
      ipc.emit("UploadSync", [files], function (ret: any) {
        r(ret);
      });
    });
  }

  //异步上传不会阻塞当前进程
  UploadASync(files: UploadItem[]): Promise<UploadItem[]> {
    const sid = "u" + Date.now();
    return new Promise((r) => {
      const ipc = this.ipc;
      ipc.emit("UploadASync", [sid, files], function (ok: boolean) {
        if (!ok) {
          r([]);
          return;
        }
        ipc.on(sid, (items: any) => {
          r(items);
        });
      });
    });
  }

  //异步上传不会阻塞当前进程
  UploadDir(dir: string, targetDir: string): Promise<UploadItem[]> {
    const sid = "u" + Date.now();
    return new Promise((r) => {
      const ipc = this.ipc;
      ipc.emit("UploadDir", [sid, dir, targetDir], function (ok: any) {
        if (!ok) {
          r([]);
          return;
        }
        ipc.on(sid, (items: any) => {
          r(items);
        });
      });
    });
  }

  GetFilesInDir(dir: string, filter: string): Promise<FileInfo[]> {
    return new Promise((r) => {
      const ipc = this.ipc;
      ipc.emit("GetFilesInDir", [dir, filter], function (ret: any) {
        r(ret);
      });
    });
  }

  GetSubDirNames(dir: string): Promise<string[]> {
    return new Promise((r) => {
      const ipc = this.ipc;
      ipc.emit("GetSubDirNames", [dir], function (ret: any) {
        r(ret);
      });
    });
  }

  RemoveFile(fpath: string): Promise<boolean> {
    return new Promise((r) => {
      const ipc = this.ipc;
      ipc.emit("RemoveFile", [fpath], function (ok: boolean) {
        r(ok);
      });
    });
  }

  GetSaveFile(title: string, filter = "图片(*.png;*.jpg)"): Promise<string> {
    const sid = "sf" + Date.now();
    return new Promise((r) => {
      const ipc = this.ipc;
      ipc.emit("GetSaveFile", [sid, title, filter], function (ok: boolean) {
        if (ok) {
          ipc.on(sid, (ret: any) => {
            r(ret);
          });
          return;
        }
        r("");
      });
    });
  }

  OpenOneFile(title: string, filter = "图片(*.png;*.jpg)"): Promise<string> {
    const sid = "sf" + Date.now();
    return new Promise((r) => {
      const ipc = this.ipc;
      ipc.emit("OpenOneFile", [sid, title, filter], function (file: any) {
        setTimeout(() => {
          r(file);
        }, 0);
      });
    });
  }

  GetImageMeta(
    fpath: string
  ): Promise<{ Width: number; Height: number; Size: number }> {
    return new Promise((r) => {
      const img = new Image();
      img.onload = () => {
        r({ Width: img.width, Height: img.height, Size: 0 });
      };
      img.src = fpath;

      // const ipc = this.ipc;
      // ipc.emit("GetImageMeta", [fpath], function (meta) {
      //     r(meta);
      // });
    });
  }

  SetMainTitle(title: string): Promise<boolean> {
    return new Promise((r) => {
      const ipc = this.ipc;
      ipc.emit("SetMainTitle", [title], function (ok: any) {
        r(ok);
      });
    });
  }

  SaveFile(fpath: string, buff: any): Promise<string> {
    return new Promise((r) => {
      const ipc = this.ipc;
      ipc.emit("SaveFile", [fpath, Array.from(buff)], function (err: string) {
        r(err);
      });
    });
  }

  OpenQueen5(url: string, title: any): Promise<boolean> {
    return new Promise((r) => {
      const ipc = this.ipc;
      ipc.emit("OpenQueen5", [url, title], function (err: any) {
        r(err);
      });
    });
  }
  OpenQueen5Play(url: string, title: any): Promise<boolean> {
    return new Promise((r) => {
      const ipc = this.ipc;
      ipc.emit("OpenQueen5Play", [url, title], function (err: any) {
        r(err);
      });
    });
  }

  SaveClipboard(blob: Blob) {
    return navigator.clipboard.write([
      new ClipboardItem({
        "image/png": blob,
      }),
    ]);
  }

  GetNatsProfile(): Promise<{ apiPort: string; wsPort: string; ip: string }> {
    return new Promise((r) => {
      const ipc = this.ipc;
      ipc.emit("NatsProfile", [], function (data: any) {
        r(data);
      });
    });
  }

  GetLocalAppProfile(): Promise<{ wsPort: string; appGuid: string }> {
    return new Promise((r) => {
      const ipc = this.ipc;
      ipc.emit("LocalAppProfile", [], function (data: any) {
        r(data || { wsPort: "", appGuid: "" });
      });
    });
  }

  OpenWeb(
    url: string,
    title: string,
    width = 1280,
    height = 720
  ): Promise<boolean> {
    return new Promise((r) => {
      const ipc = this.ipc;
      ipc.emit("OpenWeb", [url, title, width, height], function (data: any) {
        r(data);
      });
    });
  }

  RunNativeApp(guid: string, entry: string, params: string[]): Promise<string> {
    return new Promise((r) => {
      const ipc = this.ipc;
      ipc.emit("RunNativeApp", [guid, entry, params], function (err: string) {
        console.log("xxxx", err);
        r(err);
      });
    });
  }

  RunCmdSvcApp(
    guid: string,
    webUrl: string,
    entry: string,
    params: string[]
  ): Promise<string> {
    return new Promise((r) => {
      const ipc = this.ipc;
      ipc.emit(
        "RunCmdSvcApp",
        [guid, webUrl, entry, params],
        function (err: string) {
          console.log("xxxx", err);
          r(err);
        }
      );
    });
  }

  StopNativeApp(guid: string): Promise<boolean> {
    return new Promise((r) => {
      const ipc = this.ipc;
      ipc.emit("StopNativeApp", [guid], function (ok: boolean) {
        r(ok);
      });
    });
  }
}
