const { ResourceService } = require("../../service/resourceService");
const { ASR, ShortVoiceASR, TaskASR } = require("../service/ASR");
const fs = require("fs");
const Url = require("url");
const axios = require("axios");
const { ISource } = require("./port/ISource");
const { OSink } = require("./port/OSink");
const { OSource } = require("./port/OSource");
const { ISink } = require("./port/ISink");
const { PortHub } = require("./portHub");

const resourceService = new ResourceService();

class Transform {
  constructor(options, obj) {
    this.serviceName = options.serviceName;
    this.instanceId;
    // 资源状态对象   
    this.serviceObj;
    this.portHub = new PortHub();

  }

  //获取状态
  async getState(params) {
    let iSource = {};
    let oSink = {};
    let iSink = {};
    let oSource = {};
    Object.assign(iSource, this.iSource);
    Object.assign(oSink, this.oSink);
    Object.assign(iSink, this.iSink);
    Object.assign(oSource, this.oSource);
    delete iSource.eventEmitter;
    delete iSource.connectStateMachine;
    delete oSink.eventEmitter;
    delete oSink.serviceInstance;
    delete oSource.eventEmitter;
    delete oSource.oSink;
    delete iSink.eventEmitter;
    let state = {
      iSource: iSource,
      oSink: oSink,
      oSource: oSource,
      iSink: iSink
    };
    return state;
  }

  async create(params) {
    this.instanceId = resourceService.generateId(this.serviceName);
    params.instanceId = this.instanceId;
    await this.saveResource(params);
    //状态迁移
    return this.instanceId;
  }

  async release(params) {
    const endpoint = this.oSink?.config?.endpoint;
    //释放资源
    await resourceService.releaseResource(this.serviceObj.sessionId, {
      type: this.serviceName,
      mode: endpoint.mode,
      sp: endpoint.sp,
    });
    return "success";
  }

  async update(params) {
    // 更新资源的逻辑
    if (this.serviceObj) {
      this.serviceObj = Object.assign(this.serviceObj, params);
      await resourceService.setResourceObj(
        this.serviceObj,
        this.serviceName,
        params.instanceId
      );
    } else {
      throw new Error("serviceObj not exist");
    }
    return "success";
  }

  async mutationUpdate(params) {
    // 更新资源的逻辑
    if (this.serviceObj) {
      this.serviceObj = Object.assign(this.serviceObj, params);
      await resourceService.setResourceObj(
        this.serviceObj,
        this.serviceName,
        params.instanceId 
      );

      if (params.iSource) {
        let iSourceTemp = this.portLogic(params.iSource, "iSource");
        this.iSources.mutationUpdate(iSourceTemp.ports);
      }
      if (params.oSink) {
        let oSinkTemp = this.oSinkLogic(params.oSink, "oSink");
        this.oSinks.mutationUpdate(oSinkTemp.ports);
      }
      if (params.oSource) {
        let oSourceTemp = this.portLogic(params.oSource, "oSource");
        this.oSources.mutationUpdate(oSourceTemp.ports);
      }
      if (params.iSink) {
        let iSinkTemp = this.portLogic(params.iSink, "iSink");
        this.iSinks.mutationUpdate(iSinkTemp.ports);
      }
      //重新构建路由表
      this.buildRouteTable();
      console.log("【Transform】路由表：", this.routeTable);
      //重构数据路径 iSource -> oSink -> oSource -> iSink
      this.buildDataPath();
    } else {
      throw new Error("serviceObj not exist");
    }
    return "success";
  }

  async cmdOpen(params) {
    // 打开命令的逻辑
    this.iSources = this.portLogic(this.serviceObj.iSource, "iSource");
    this.oSinks = this.oSinkLogic(this.serviceObj.oSink, "oSink");
    let oSink = this.oSinks.ports[0];
    this.oSources = this.portLogic(this.serviceObj.oSource, "oSource");
    this.iSinks = this.portLogic(this.serviceObj.iSink, "iSink");
    // 创建资源
    const endpoint = oSink?.config?.endpoint;
    if (!endpoint) {
      throw new Error("endpoint is required");
    }
    //分配资源
    params.appKey = this.serviceObj.appKey;
    params.sessionId = this.serviceObj.sessionId;
    await resourceService.getBestAppResource(params, {
      type: this.serviceName,
      mode: endpoint.mode,
      sp: endpoint.sp,
    });
    //get token
    var resourceToken = await resourceService.getToken(
      this.serviceObj.sessionId,
      this.serviceName
    );
    console.log("【ASR】获取token：", resourceToken);
    const context = {
      token: JSON.parse(resourceToken.oauthInfo),
      instanceId: this.instanceId,
      sessionId: this.serviceObj.sessionId,
      serviceName: this.serviceName
    }
    //port open
    this.iSources.init(context);
    this.oSinks.init(context);
    this.oSources.init(context);
    this.iSinks.init(context);
    //构建路由表
    this.buildRouteTable();
    console.log("【Transform】路由表：", this.routeTable);
    this.iSources.open();
    this.oSinks.open();
    this.oSources.open();
    this.iSinks.open();
    //构建数据路径 iSource -> oSink -> oSource -> iSink
    this.buildDataPath();
    return "success";
  }

  cmdClose(params) {
    //处理oSink
    this.iSources.close();
    this.oSinks.close();
    this.oSources.close();
    this.iSinks.close();
    return "success";
  }

  async cmdStart(params) {
    let iSourcePortId = params.targetId;
    this.iSinks.removeAllListeners("start");
    return new Promise((resolve, reject) => {
      this.iSinks.ports.forEach((iSink) => {
        iSink.eventEmitter.on("start", (data) => {
          resolve(data);
        });
      });
      if (!iSourcePortId) {
        this.iSources.start(params);
      } else {
        let iSource = this.iSources.getPortById(iSourcePortId);
        iSource.start(params);
      }
      setTimeout(() => {
        resolve("start timeout");
      }, 1000)
    });
  }

  cmdStop(params) {
    //状态迁移
    this.iSources.stop();
    this.oSinks.stop();
    this.oSources.stop();
    this.iSinks.stop();
    return "success";
  }

  cmdPause(params) {
    //状态迁移
    this.iSources.pause();
    this.oSinks.pause();
    this.oSources.pause();
    this.iSinks.pause();
    return "success";
  }

  cmdResume(params) {
    //状态迁移
    this.iSources.resume();
    this.oSinks.resume();
    this.oSources.resume();
    this.iSinks.resume();
    return "success";
  }


  async cmdQuery(params) {
    let iSourcePortId = params.targetId;
    this.iSinks.removeAllListeners("query");
    return new Promise((resolve, reject) => {
      this.iSinks.ports.forEach((iSink) => {
        iSink.eventEmitter.on("query", (data) => {
          resolve(data);
        });
      });
      if (!iSourcePortId) {
        this.iSources.query(params);
      } else {
        let iSource = this.iSources.getPortById(iSourcePortId);
        iSource.query(params);
      }
    });
  }

  async cmdGetTaskStatus(params) {
    //清除监听
    this.iSources.removeAllListeners("getTaskStatus");
    this.oSinks.removeAllListeners("getTaskStatus");
    this.oSources.removeAllListeners("getTaskStatus");
    this.iSinks.removeAllListeners("getTaskStatus");

    this.iSources.ports.forEach((iSource) => {
      iSource.eventEmitter.on("getTaskStatus", (data) => {
        let oSinks = this.routeTable.get(iSource.portId);
        oSinks.forEach((oSink) => {
          oSink.getTaskStatus(params, data);
        });
      });
    });

    this.oSinks.ports.forEach((oSink) => {
      oSink.eventEmitter.on("getTaskStatus", (data) => {
        let oSources = this.routeTable.get(oSink.portId);
        oSources.forEach((oSource) => {
          oSource.getTaskStatus(params, data);
        });
      });
    });
    this.iSources.getTaskStatus(params);
    return new Promise((resolve, reject) => {
      this.oSources.ports.forEach((oSource) => {
        oSource.eventEmitter.on("getTaskStatus", (data) => {
          let iSinks = this.routeTable.get(oSource.portId);
          iSinks.forEach(async (iSink) => {
            let result = await iSink.getTaskStatus(params, data);
            resolve(result);
          });
        });
      });
    });
  }


  //弃用
  async cmdQuery2(params) {
    //关闭监听
    this.iSource.eventEmitter.removeAllListeners("query");
    this.oSink.eventEmitter.removeAllListeners("query");
    this.oSource.eventEmitter.removeAllListeners("query");
    // 查询命令的逻辑
    this.iSource.eventEmitter.on("query", (data) => {
      this.oSink.query(params, data);
    });
    this.oSink.eventEmitter.on("query", (data) => {
      this.oSource.query(params, data);
    });
    this.iSource.query(params);

    return new Promise((resolve, reject) => {
      this.oSource.eventEmitter.on("query", async (data) => {
        let result = await this.iSink.query(params, data);
        resolve(result);
      });
    });
  }

  async cmdGetTaskStatus2(params) {
    this.iSource.eventEmitter.removeAllListeners("getTaskStatus");
    this.oSink.eventEmitter.removeAllListeners("getTaskStatus");
    this.oSource.eventEmitter.removeAllListeners("getTaskStatus");
    // 查询命令的逻辑
    this.iSource.eventEmitter.on("getTaskStatus", (data) => {
      this.oSink.getTaskStatus(params, data);
    });
    this.oSink.eventEmitter.on("getTaskStatus", (data) => {
      this.oSource.getTaskStatus(params, data);
    });
    this.iSource.getTaskStatus(params);

    return new Promise((resolve, reject) => {
      this.oSource.eventEmitter.on("getTaskStatus", async (data) => {
        let result = await this.iSink.getTaskStatus(params, data);
        resolve(result);
      });
    });
  }

  async saveResource(params) {
    //存入redis作为资源状态聚合
    await resourceService.setResourceObj(
      params,
      this.serviceName,
      params.instanceId
    );
    this.serviceObj = params;
  }
  async dealISink(res, sink) {
    if (sink.mode == "rest") {
      // axios({
      //   url: onCallback.url,
      //   method: "POST",
      //   headers: {
      //     "Content-Type": "application/json",
      //   },
      //   data: res,
      // });
      console.log("sink.onComplete:", sink.url, res);
    } else if (sink.mode == "dmhub") {
      //传入会话中控
      // this.sendResult(res.result.voice_text_str, onCallback.url);
    }
  }
  portLogic(port, portType) {
    let portHub = new PortHub(portType);
    for (let key in port) {
      for (let source of port[key]) {
        portHub.addPort({
          connectType: key,
          ...source
        });
      }
    }
    return portHub;
  }



  oSinkLogic(port, portType) {
    let portHub = new PortHub(portType);
    for (let key in port) {
      for (let sink of port[key]) {
        portHub.addPort({
          serviceType: key,
          ...sink
        });
      }
    }
    return portHub;
  }



  buildDataPath() {
    this.iSources.removeAllListeners("start");
    this.iSources.removeAllListeners("query");
    this.oSinks.removeAllListeners("start");
    this.oSinks.removeAllListeners("query");
    this.oSources.removeAllListeners("start");
    this.oSources.removeAllListeners("query");
    this.iSinks.removeAllListeners("start");
    this.iSinks.removeAllListeners("query");
    var params = {};
    this.iSources.ports.forEach((iSource) => {
      iSource.eventEmitter.on("start", (data) => {
        let oSinks = this.routeTable.get(iSource.portId);
        oSinks.forEach((oSink) => {
          oSink.start(params, data);
        });
      });
      iSource.eventEmitter.on("query", (data) => {
        let oSinks = this.routeTable.get(iSource.portId);
        oSinks.forEach((oSink) => {
          oSink.query(params, data);
        });
      });
    });

    this.oSinks.ports.forEach((oSink) => {
      oSink.eventEmitter.on("start", (data) => {
        let oSources = this.routeTable.get(oSink.portId);
        oSources.forEach((oSource) => {
          oSource.start(params, data);
        });
      });
      oSink.eventEmitter.on("query", (data) => {
        let oSources = this.routeTable.get(oSink.portId);
        oSources.forEach((oSource) => {
          oSource.query(params, data);
        });
      });
    });
    this.oSources.ports.forEach((oSource) => {
      oSource.eventEmitter.on("start", (data) => {
        let iSinks = this.routeTable.get(oSource.portId);
        iSinks.forEach(async (iSink) => {
          iSink.start(params, data);
        });
      });
      oSource.eventEmitter.on("query", (data) => {
        let iSinks = this.routeTable.get(oSource.portId);
        iSinks.forEach(async (iSink) => {
          iSink.query(params, data);
        });
      });
    });
  }

  buildRouteTable() {
    this.routeTable = new Map();
    //构建路由表
    for (let iSource of this.iSources.ports) {
      let oSink = this.oSinks.getPortById(iSource.targetId);
      if (oSink) {
        this.createRoute(iSource.portId, oSink);
      }
    }
    for (let oSink of this.oSinks.ports) {
      let oSource = this.oSources.getPortById(oSink.targetId);
      if (oSource) {
        //oSource,oSink绑定
        oSource.mutationUpdate(oSource, oSink);
        this.createRoute(oSink.portId, oSource);
      }
    }
    for (let oSource of this.oSources.ports) {
      let iSink = this.iSinks.getPortById(oSource.targetId);
      if (iSink) {
        this.createRoute(oSource.portId, iSink);
      }
    }
  }

  createRoute(sourcePort, destPort) {
    if (!this.routeTable.has(sourcePort)) {
      this.routeTable.set(sourcePort, []);
    }
    this.routeTable.get(sourcePort).push(destPort);
  }

  updateRoute(sourcePort, destPort) {
    this.routeTable.set(sourcePort, [destPort]);
  }

  removeRoute(sourcePort) {
    this.routeTable.delete(sourcePort);
  }

}



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