import mqtt from "mqtt/dist/mqtt";
import orders from "./orders";

function uint8array2json(uint8array) {
  if (!uint8array || !uint8array.length) {
    return uint8array;
  }
  let decoder = new TextDecoder("utf-8");
  let content = decoder.decode(uint8array);
  return content ? JSON.parse(content) : content;
}

export default {
  namespaced: true,
  state: {
    client: null, //mqtt client
    clientId: "",
    dataSet: {
      //数据集
      /* deviceHardId: {
        type(如258): {}
      } */
    },
    orders, //所有指令
    username: 'tmj',
    password: 'Tmj@192D9'
  },
  mutations: {
    /**
     * 单纯的给state赋值
     * @param {*} param0
     * @param {*} data {key: '', value}
     */
    setState(state, data) {
      try {
        state[data.key] = data.value;
      } catch (e) {
        console.log("setDate err", e);
      }
    },
    setClient(state, data) {
      state.client = data;
    },
    setClientId(state, data) {
      state.clientId = data;
    },
    setUrl(state, data) {
      state.url = data;
    },
    setDataSet(state, data) {
      let temp = {};
      Object.keys(data).forEach((key) => {
        temp[key] = data[key];
      });
      state.dataSet = temp;
    },
  },
  actions: {
    init({ commit, state }, data) {
      let clientId = Date.now();
      let client = mqtt.connect(data.url, {
        username: state.username,  
        password: state.password,  
        clientId,
      });

      console.log("MQTT client", client);
      commit("setClient", client);
      commit("setClientId", clientId);

      client.on("reconnect", function (reconnect) {
        console.log(reconnect, "reconnect");
      });

      client.on("message", (topic, payload, packet) => {
        let data = uint8array2json(payload);
        let deviceHardId = packet.topic.split("/")[2];

        if (!state.dataSet[deviceHardId]) {
          state.dataSet[deviceHardId] = {};
        }

        data.$time = Date.now(); // 打上时间戳
        state.dataSet[deviceHardId][data.type] = data;
        commit("setDataSet", state.dataSet);
      });

      /**
       * 订阅无人机上线下线消息
       */
      /* subscribe(`on_and_off_broker`, (e) => {
        console.log("subscribe on_and_off_broker");
      }); */

      return new Promise((resolve, reject) => {
        client.on("connect", () => {
          console.log("mqtt is connected");
          resolve();
        });

        client.on("`error`", (error) => {
          console.log("mqtt is `error`", error);
          reject();
        });
      });
    },
    /**
     * 断开mqtt连接
     * @param {} param0
     */
    end({ state, commit }) {
      console.log('MMCMQTT: 断开mqtt连接')
      state.client?.end();
      commit("setClient", null);
      commit("setClientId", "");
    },
    /**
     * 订阅
     * @param {*} topic
     * @param {*} callback
     */
    subscribe({ state }, { topic, callback }) {
      if (!topic) {
        return topic;
      }
      let { client } = state;
      if (client) {
        console.log("订阅数据", topic);
        client.subscribe(topic, callback);
      }
    },
    /**
     * 取消订阅
     * @param {*} topic
     * @returns
     */
    unsubscribe({ state }, { topic, deviceHardId, callback }) {
      if (!topic) {
        return topic;
      }
      let { client } = state;
      if (client) {
        client.unsubscribe(topic, callback);
      }
      if (state.dataSet[deviceHardId]) {
        state.dataSet[deviceHardId] = undefined;
        commit("setDataSet", state.dataSet);
      }
    },
    /**
     * 发布
     * QoS 0：消息最多传递一次，如果当时客户端不可用，则会丢失该消息。
     * QoS 1：消息传递至少 1 次。
     * QoS 2：消息仅传送一次。
     * @param {*} publication
     * @param {*} callback
     * @param {*} options
     * @param {*} type
     */
    publish({ state }, { topic, data, callback, options = { qos: 0 } }) {
      console.log("publish", topic, data);
      state.client.publish(
        topic,
        new TextEncoder().encode(JSON.stringify(data)),
        options,
        callback
      );
    },
    /**
     * 全部指令
     * @param {*} param0
     * @param {*} param1
     * @param {String} param1.topic 发送的主题
     * @param {String} param1.order 指令名称
     * @param {Object} param1.data 指令对应的数据
     * @param {Function} param1.callback 成功回调
     */
    order({ dispatch }, { topic, order, data, callback }) {
      if (orders[order] === undefined) {
        throw "该命令不存在！";
      }

      dispatch("publish", {
        topic,
        data: {
          type: orders[order],
          data,
        },
        callback,
      });
    },
  },
};
