import MqttClient from './mqttws31';

export const NEW_MESSAGE = 'NEW_MESSAGE';
export class Message {
  constructor({
    id,
    infoContent,
    infoLevel,
    time,
    infoType,
    dateTime,
    webConfig,
    webPath,
    messType,
  } = message) {
    this.id = id;
    this.infoContent = infoContent;
    this.infoLevel = infoLevel;
    this.time = time;
    this.infoType = infoType; // 方案类型 - 工单 报警 公告 定时推送
    this.dateTime = dateTime;
    this.webConfig = webConfig;
    this.webPath = webPath;
    this.messType = messType; //方案名称 -  大类型下细类型
  }
}

class Notifier {
  constructor(userInfo) {
    this.userInfo = userInfo;
    this.messageCache = {
      totalCount: 0,
      messages: [],
    }; // 当前消息缓存
    this._subscribers = {}; //订阅器缓存
    this._siteConfig = {
      site_code: this.userInfo.site,
      TcpIP: '',
      TcpPort: 443,
      TimeOut: '',
      KeepAlive: '',
      IsSSL: true,
      mqtt_path: '/mqtt',
    };
    this._config = {
      mqtt_path: '/mqtt',
      nginxStart: 'false',
      mqtt_mess: {
        IsSSL: false,
      },
    };
    this.MQTTCount = 0;
    this.MQTTClient = null;
    this.MQTTOptions = {};
    this.IsNeedReconnect = true;
    this.currentPageIndex = 1;
    this.currentPageSize = 10;

    // 对外接口处理this指向问题
    this.start = this.start.bind(this);
    this.stop = this.stop.bind(this);
    this.subscribe = this.subscribe.bind(this);
    this.unsubscribe = this.unsubscribe.bind(this);
    this.confirmRead = this.confirmRead.bind(this);
    this.loadMore = this.loadMore.bind(this);
    this.hasMore = this.hasMore.bind(this);
  }

  // 对外接口
  async start() {
    window.cc=this.messageCache;
    this._getMqttSiteCode().then(() => {
      this.loadHisMessages(this.currentPageIndex,this.currentPageSize);
      this.connectMQTTServer();
    });
  }
  stop() {
    this.disconnectMQTTServer();
  }
  subscribe(type, handler) {
    if (!(type in this._subscribers)) {
      this._subscribers[type] = [];
    }
    this._subscribers[type].push(handler);
  }
  unsubscribe(type, handler) {
    if (!(type in this._subscribers)) {
      console.log('无效事件无法删除');
    }
    if (!handler) {
      delete this._subscribers[type];
    } else {
      const idx = this._subscribers[type].findIndex(ele => ele === handler);
      if (idx === -1) {
        console.log('无效事件无法删除');
        return;
      }
      this._subscribers[type].splice(idx, 1);
      if (this._subscribers[type].length === 0) {
        delete this._subscribers[type];
      }
    }
  }
  publish(type, payload) {
    if (!(type in this._subscribers) || this._subscribers[type].length === 0)
      return;
    this._subscribers[type].forEach(handler => {
      try {
        handler(payload);
      } catch (e) {
        console.log('订阅器委托错误');
      }
    });
  }
  confirmRead(isAll = false, hisIDs = []) {
    let list = [];
    if (
      this.messageCache &&
      this.messageCache.totalCount == 0 &&
      this.messageCache.messages.length == 0
    )
      return;
    if (isAll) hisIDs = this.messageCache.messages.map(item => item.id);
    let me = this;
    Http.postInformationStatus({
      userID: this.userInfo.OID,
      hisID: hisIDs.join(','),
      isAll: isAll ? 1 : '',
    })
      .then(res => {
        if (res.statusCode != '0000') {
          console.log(res.errMsg);
          return;
        }
        if (isAll) {
          me.messageCache.totalCount = 0;
          me.messageCache.messages = [];
          me.currentPageIndex= 1;
        } else {
          hisIDs.forEach(id => {
            let index = me.messageCache.messages.findIndex(
              item => item.id == id,
            );
            if (index != -1) {
              me.messageCache.messages.splice(index, 1);
              me.messageCache.totalCount--;
            }
          });
        }
        me.publish(NEW_MESSAGE, me.messageCache);
      })
      .catch(err => {
        console.log('postInformationStatus调用失败' + err);
      });
  }
  hasMore() {
    if (!this.messageCache) return false;
    if (!this.messageCache.totalCount) return false;
    return this.messageCache.totalCount > this.messageCache.messages.length;
  }
  loadMore(callback) {
    if (!this.hasMore()) return Promise.resolve([]);
    this.currentPageIndex+=1;
    return this.loadHisMessages(this.currentPageIndex, this.currentPageSize);
  }

  // mqtt
  async connectMQTTServer() {
    let hostname = this._siteConfig.TcpIP,
      port = this._siteConfig.TcpPort,
      clientId = 'client-' + this._createGuid(),
      timeout = 50,
      keepAlive = 60,
      cleanSession = true,
      ssl = this._siteConfig.IsSSL,
      userName = 'mao2080',
      password = '123',
      path = this._siteConfig.mqtt_path;
    this.MQTTCount = 0;
    this.MQTTClient = new MqttClient.Client(hostname, port, path, clientId);
    this.MQTTOptions = {
      invocationContext: {
        host: hostname,
        port: port,
        path: path,
        clientId: clientId,
      },
      timeout: timeout,
      keepAliveInterval: keepAlive,
      cleanSession: cleanSession,
      useSSL: ssl,
      userName: userName,
      password: password,
      onSuccess: this.onMQTTConnect.bind(this),
      onFailure: function(e) {
        console.log(e);
      },
    };
    this.MQTTClient.connect(this.MQTTOptions);
    this.MQTTClient.onConnectionLost = this.onMQTTConnectionLost.bind(this);
    this.MQTTClient.onMessageArrived = this.onMessageArrived.bind(this);
  }
  disconnectMQTTServer() {
    if (this.MQTTClient) {
      this.IsNeedReconnect = false;
      this.MQTTClient.disconnect();
      this.MQTTClient = null;
    }
  }
  onMQTTConnect() {
    var site = this._siteConfig.site_code;
    //信息化主题
    var EIMTopic = site + `/EIM/info`;
    this.MQTTClient.subscribe(EIMTopic);
    //节水主题
    var saveWaTopic = site + `/saveWater/info`;
    this.MQTTClient.subscribe(saveWaTopic);
    //系统主题
    var sysTopic = site + `/system/info`;
    this.MQTTClient.subscribe(sysTopic);
    //工单主题
    var caseTopic = site + `/workerOrder/info`;
    this.MQTTClient.subscribe(caseTopic);
    //报警主题
    var SCADATopic = site + `/scada/alarm`;
    this.MQTTClient.subscribe(SCADATopic);
    //用户主题
    var UserTopic = site + `/Message/${this.userInfo.OID}`;
    this.MQTTClient.subscribe(UserTopic);
  }
  onMQTTConnectionLost(responseObject) {
    console.log('连接丢失', responseObject);
    var me = this;
    if (this.IsNeedReconnect) {
      this.MQTTClient.connect(me.MQTTOptions);
      this.MQTTtester = setInterval(function() {
        if (me.MQTTClient.isConnected) {
          clearInterval(me.MQTTtester);
        } else {
          me.MQTTClient.connect(me.MQTTOptions);
        }
      }, 1000);
    }
  }
  onMessageArrived(buffer) {
    let me = this;
    try {
      // console.log('收到消息:' + buffer.payloadString);
      let temp = JSON.parse(buffer.payloadString);
      let infoType = this._typeInfo(temp.infoType);
      if (
        temp.tousers == '' ||
        me.userInfo.OID == temp.tousers ||
        temp.tousers.includes(me.userInfo.OID + ',') ||
        temp.tousers.includes(',' + me.userInfo.OID)
      ) {
        let messContent = temp.content;
        let timeH = (new Date() - new Date(temp.createTime)) / 1000 / 60;
        let timeMss =
          Math.abs(timeH) > 1440
            ? temp.createTime.split('.')[0]
            : Math.abs(timeH) > 60
            ? (timeH / 60).toFixed(0) + '小时前'
            : Math.abs(timeH) > 1
            ? timeH.toFixed(0) + '分钟前'
            : '刚刚';
        let messString = {
          id: temp.ID,
          infoContent: messContent,
          infoLevel: temp.level,
          time: `${timeMss}`,
          infoType: infoType,
          dateTime: temp.createTime,
          webConfig: temp.web_config,
          webPath: temp.web_path,
          messType: temp.MessType,
        };
        if (this._IsVersion1())
          messString.infoContent = this._handleMessageStrToJSON(
            infoType,
            messString,
          );
        else messString.infoContent = JSON.parse(messString.infoContent);
        let message = new Message(messString);
        this.messageCache.totalCount += 1;
        this.messageCache.messages.push(message);
        me.publish(NEW_MESSAGE, this.messageCache);
      }
    } catch (e) {
      console.log('收到消息处理异常:' + e.message);
    }
  }

  // 工具类
  async loadHisMessages(pageIndex,pageSize) {
    let me = this;
    return Http.getInformationInfo({
      userID: me.userInfo.OID,
      pageIndex,
      pageSize,
      'request.preventCache': Date.now(),
    }).then(res => {
      let result = {
        totalCount: res.totalRcdNum,
        messages: res.getMe.map(this._handleHisToMessage.bind(this)),
      };
      me.messageCache.totalCount = result.totalCount;
      result.messages.forEach(message => {
        // 防止加载更多时候塞入重复数据
        let index = me.messageCache.messages.findIndex(item => {
          return item.id == message.id;
        });
        index == -1 && me.messageCache.messages.push(message);
      });
      me.publish(NEW_MESSAGE, me.messageCache);
      return Promise.resolve(result);
    });
  }
  async _getMqttSiteCode() {
    let me = this;
    return Http.getMqttSiteCode({ 'request.preventCache': Date.now() }).then(
      res => {
        if (res.say.statusCode == '0000') {
          if (res.getMe[0]) {
            me._siteConfig.IsSSL = res.getMe[0].IsSSL
              ? res.getMe[0].IsSSL
              : false;
            me._siteConfig.site_code =
              res.getMe[0].SiteCode || me._siteConfig.site_code;
            me._siteConfig.TcpIP = res.getMe[0].TcpIP;
            me._siteConfig.TcpPort = res.getMe[0].TcpPort
              ? parseInt(res.getMe[0].TcpPort)
              : 8083;
            me._siteConfig.MessageLevel = res.getMe[0].MessageLevel
              ? res.getMe[0].MessageLevel
              : '1.0';
          }
          if (res.getMe[0].NginxStart) {
            me._siteConfig.TcpIP = window.location.hostname;
            me._siteConfig.TcpPort = parseInt(window.location.port);
            me._siteConfig.mqtt_path = '/ws/';
          } else {
            me._siteConfig.TcpIP = 'emqttd.panda-water.cn';
            me._siteConfig.TcpPort = 443;
            me._siteConfig.IsSSL = true;
          }
        } else {
          console.log('获取mqtt服务器参数失败');
        }
      },
    );
  }
  _createGuid() {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'
      .replace(/[xy]/g, function(c) {
        var r = (Math.random() * 16) | 0,
          v = c == 'x' ? r : (r & 0x3) | 0x8;
        return v.toString(16);
      })
      .toUpperCase();
  }
  _typeInfo(infoTypeStr) {
    var infoType = 'unknown';
    switch (infoTypeStr) {
      case '工单流程':
        infoType = 'caseType';
        break;
      case '系统消息':
      case '系统通知':
        infoType = 'sysType';
        break;
      case '节水通知':
        infoType = 'saveWaType';
        break;
      case '信息化':
        infoType = 'EIMType';
        break;
      case '消息提醒':
        infoType = 'remindType';
        break;
      case 'SCADA报警':
        infoType = 'scadaType';
      default:
        break;
    }
    return infoType;
  }
  _handleHisToMessage(hisMessage) {
    var timeH = (new Date() - new Date(hisMessage.HisCreateTime)) / 1000 / 60;
    var timeMss =
      Math.abs(timeH) > 1440
        ? hisMessage.HisCreateTime.split('.')[0]
        : Math.abs(timeH) > 60
        ? (timeH / 60).toFixed(0) + '小时前'
        : Math.abs(timeH) > 1
        ? timeH.toFixed(0) + '分钟前'
        : '刚刚';
    let message = {
      id: hisMessage.HisID,
      infoContent: hisMessage.InfoContent,
      time: `${timeMss}`,
      infoType: this._typeInfo(hisMessage.InfoType),
      dateTime: hisMessage.HisCreateTime,
      infoLevel: hisMessage.InfoLevel,
      webConfig: hisMessage.web_config,
      webPath: hisMessage.web_path,
      messType: hisMessage.MessType,
    };
    if (this._IsVersion1())
      message.infoContent = this._handleMessageStrToJSON(
        message.infoType,
        message,
      );
    else message.infoContent = JSON.parse(message.infoContent);
    return new Message(message);
  }

  // 1.0 解析规则
  _IsVersion1() {
    return (
      !this._siteConfig.MessageLevel || this._siteConfig.MessageLevel != '2.0'
    );
  }
  _handleMessageStrToJSON(infoType, messString) {
    let infoContent = messString;
    switch (infoType) {
      case 'scadaType':
        infoContent = this._analysisAlarm(messString);
        break;
      case 'caseType':
        infoContent = this._analysisCase(messString);
        break;
      case 'sysType':
        infoContent = this._analysisNotice(messString);
        break;
      case 'saveWaType':
        break;
      case 'EIMType':
        break;
      default:
        break;
    }
    return infoContent;
  }
  _analysisCase(messString) {
    let attr = messString.infoContent.split('\\n');
    let caseContent = {
      caseType: attr[0].split('】')[0].split('【')[1],
      flowName: attr[0].split('】')[1],
      nodeName: attr[1],
      content: attr[2],
      time: messString.dateTime,
    };
    return caseContent;
  }
  _analysisAlarm(messString) {
    let attr = messString.infoContent.split('\\n');
    let alarmContent = {
      alarmType: attr[0].split('】')[0].split('【')[1],
      deviceCode: '',
      alarmDevice: attr[0].split('】')[1],
      alarmContent: attr[1],
      alarmThreshold: attr[2].includes(' / ')
        ? attr[2].split('/')[1].trim(' ')
        : '',
      alarmValue: attr[2].includes(' / ')
        ? attr[2].split('/')[0].trim(' ')
        : attr[2].includes('：')
        ? attr[2].split('：')[1]
        : '',
      time: messString.dateTime,
    };
    return alarmContent;
  }
  _analysisNotice(messString) {
    let attr = messString.infoContent.split('\\n');
    let noticeContent = {
      noticeType: attr[0].split('】')[0].split('【')[1],
      noticeTitle: attr[0].split('】')[1],
      noticeContent: attr[1],
      time: messString.dateTime,
    };
    return noticeContent;
  }

}

export default Notifier;
