const { createMachine, interpret } = require("xstate");
const EventEmitter = require("events");
const fs = require("fs");

class FileOperationMachine {
  constructor() {
    this.stateMachine = createMachine({
      id: "fileOperation",
      initial: "idle",
      predictableActionArguments: true,
      states: {
        idle: {
          on: {
            START: { target: "checkingFile" },
          },
        },
        checkingFile: {
          invoke: {
            src: this.checkFile,
            onDone: {
              target: "open",
            },
            onError: {
              target: "error",
              actions: [this.setError],
            },
          },
        },
        open: {
          on: {
            CLOSE: { target: "idle", actions: [this.closeFile] },
          },
          invoke: {
            src: this.openFile,
            onDone: {
              target: "idle",
            },
            onError: {
              target: "error",
              actions: [this.setError],
            },
          },
        },
        error: {
          on: {
            START: { target: "checkingFile" },
          },
        },
      },
    });
    this.fsmSevice = interpret(this.stateMachine)
      .onTransition((state) => {
        this.state = state.value;
        this.onTransition(this.state);
      })
      .start();
    this.eventEmitter = new EventEmitter();
  }

  send(event) {
    this.fsmSevice.send(event);
  }
  onTransition() { }

  checkFile = (context, event) =>
    new Promise((resolve, reject) => {
      try {
        const fileUrl = event.params.url;
        var address = fileUrl.replace("file://", "");
        fs.accessSync(address, fs.constants.R_OK);
        return resolve(event);
      } catch (err) {
        return reject("文件不存在或者没有读写权限");
      }
    });
  closeFile = (context, event) =>
    new Promise((resolve, reject) => {
      this.fileStream.close();
    });

  openFile = (context, event) =>
    new Promise((resolve, reject) => {
      try {
        event = event.data;
        let cmd = event.cmd;
        const fileUrl = event.params.url;
        var address = fileUrl.replace("file://", "");
        this.fileStream = fs.createReadStream(address);
        var bytesPerFrame = ((16000 * 2) / 1000) * 160; //16000的采样率，16bits=2bytes， 1000ms  一个数据帧 160ms
        var buffer = [];
        this.fileStream.on("readable", async () => {
          while (null !== (buffer = this.fileStream.read(bytesPerFrame))) {
            //走一个调用方法
            this.eventEmitter.emit(cmd, buffer);
            await sleep(100);
          }
        });
        this.fileStream.on("end", () => {
          return resolve(event);
        });
      } catch (err) {
        return reject(err);
      }
    });

  setError = (context, event) =>
    new Promise((resolve, reject) => {
      console.log("setError:", event.data);
      return resolve();
    });
}

function sleep(ms) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}

module.exports.FileOperationMachine = FileOperationMachine;
