/*
Получение информации по ключу авторизации
NCALayer.sign('AUTH', null, result => {
  console.log(result)
});

получение информации по ключу и данных для подписания при согласовании/утверждении или просто подписания документа
NCALayer.sign('SIGN','documentID', result => {
  console.log(result)
});

авторизация в синержи по эцп
@return: token
NCALayer.authEDS(result => {
  console.log(result)
});

регистрация в синержи по эцп
@return: {email, iin, name, patronymic, surname}
NCALayer.registerEDS(result => {
  console.log(result)
});

*/

this.NCALayer = {
  SOCKET_URL: 'wss://127.0.0.1:13579/',
  storageName: "PKCS12",
  webSocket: null,
  info: {},
  keysConstType: null,
  documentID: null,
  successHandler: null,
  connect: null,

  initNCALayerSocket: function(){
    let me = this;
    this.webSocket = new WebSocket(this.SOCKET_URL);

    this.webSocket.onclose = function(event) {
      if(event.wasClean) {
        console.log(`[NCALayer] Соединение успешно закрыто, код: ${event.code} причина: ${event.reason}`);
      } else {
        console.log('[NCALayer] Соединение прервано');
      }
      me.webSocket = null;
      me.connect = null;
    }

    this.webSocket.onerror = function(error) {
      Cons.hideLoader();
      me.connect = null;
      console.log('[NCALayer error]', error);
      UIkit.modal.alert(`<span>${i18n.tr('Убедитесь что программа NCALayer запущена и повторите попытку.')}<br><a href="https://pki.gov.kz/ncalayer/" target="_blank">${i18n.tr('Инструкция по запуску программы')}</a></span>`);
    }

    this.webSocket.onmessage = function(event) {
      const result = parseNcaLayerMsg(event);
      if(result.hasOwnProperty('code')) {
        if(result.code == 200) {
          if (result.responseObject.hasOwnProperty('keyId')) {
            const {certNotAfter, certNotBefore, algorithm, subjectDn} = result.responseObject;
            me.info.certNotAfter = AS.FORMS.DateUtils.formatDate(new Date(Number(certNotAfter)), AS.FORMS.DateUtils.DATE_FORMAT_FULL);
            me.info.certNotBefore = AS.FORMS.DateUtils.formatDate(new Date(Number(certNotBefore)), AS.FORMS.DateUtils.DATE_FORMAT_FULL);
            me.info.algorithm = algorithm;

            const keyInfo = subjectDn.split(",");
            keyInfo.forEach(item => {
              const keyValue = item.split('=');
              me.info[keyValue[0]] = keyValue[1];
            });

            if(me.keysConstType == 'SIGN' && me.documentID) {
              me.signDocument();
            } else {
              if(me.successHandler) me.successHandler(me.info);
            }
          } else if(result.responseObject.hasOwnProperty('signedData')){
            const {certificate, dataForSign, signedData, esedoSign} = result.responseObject;
            me.info.certificate = certificate;
            me.info.dataForSign = dataForSign;
            me.info.signedData = signedData;
            if(esedoSign) me.info.esedoSign = esedoSign;
            me.verificationKey();
          } else {
            me.info.xml = result.responseObject;
            if (me.keysConstType == 'authEDS') {
              me.authSynergyEDS();
            } else if (me.keysConstType == 'registerEDS') {
              me.registerSynergyEDS();
            }
          }
        } else {
          console.log('[NCALayer onmessage error]', result);
          if(result.message != "action.canceled") {
            showMessage(i18n.tr("Ошибка проверки ключа."), "error");
          }
        }
      }
    }

    this.webSocket.onopen = function(event) {
      me.connect = true;
      console.log('[NCALayer] Соединение установлено');
    }
  },

  getNCALayerSocket: function(){
    if(!this.webSocket || [2, 3].includes(Number(this.webSocket.readyState))) {
      this.initNCALayerSocket();
    }
    return this.webSocket;
  },

  getKeyInfo: function(){
    const param = {
      module: 'kz.arta.synergy.signmodule',
      method: 'getFullKeyInfo',
      args: [this.storageName]
    };

    if(!this.webSocket) this.webSocket = this.getNCALayerSocket();

    setTimeout(() => {
      this.webSocket.send(JSON.stringify(param));
    }, 100);
  },

  signXML: function(uuid){
    const param = {
      module: 'kz.gov.pki.knca.commonUtils',
      method: 'signXml',
      args: [this.storageName, "AUTH", `<xml>${uuid}</xml>`, "", ""]
    };

    if(!this.webSocket) this.webSocket = this.getNCALayerSocket();

    setTimeout(() => {
      this.webSocket.send(JSON.stringify(param));
    }, 100);
  },

  signDocument: async function(socket){
    const { rawdata, isEsedoOutgoing } = await AS.FORMS.ApiUtils.simpleAsyncGet(`rest/api/docflow/doc/document_info?documentID=${this.documentID}&locale=${AS.OPTIONS.locale}`);

    const param = {
      module: 'kz.arta.synergy.signmodule',
      method: 'signDocument',
      args: ["", "SIGN", rawdata]
    };

    if(isEsedoOutgoing && isEsedoOutgoing == "true") {
      const digest = await AS.FORMS.ApiUtils.simpleAsyncPost(`rest/sign/esedo/getDigest?idDocument=${this.documentID}`);
      param.args = [JSON.stringify(digest), "SIGN", rawdata]
    }

    if(!this.webSocket) this.webSocket = this.getNCALayerSocket();

    setTimeout(() => {
      this.webSocket.send(JSON.stringify(param));
    }, 100);
  },

  registerSynergyEDS: async function(){
    try {
      const url = `../Synergy/rest/api/registerEDS`;
      const response = await fetch(url, {
        method: 'POST',
        headers: {"Content-Type": "application/json; charset=UTF-8"},
        body: JSON.stringify({"cert": this.info.xml})
      });
      const result = await response.json();

      if(!response.ok) throw new Error(result.errorMessage);

      if(this.successHandler) this.successHandler(result);

    } catch (err) {
      console.log(`ERROR [registerSynergyEDS]: ${err.message}`);
      if(this.successHandler) this.successHandler({errorCode: 13, errorMessage: err.message});
    }
  },

  authSynergyEDS: async function(){
    try {
      const url = `../Synergy/rest/api/authEDS`;
      const response = await fetch(url, {
        method: 'POST',
        headers: {"Content-Type": "application/json; charset=UTF-8"},
        body: JSON.stringify({"cert": this.info.xml})
      });
      const result = await response.json();

      if(!response.ok) throw new Error(result.errorMessage);

      if(this.successHandler) this.successHandler(result);

    } catch (err) {
      console.log(`ERROR [authSynergyEDS]: ${err.message}`);
      if(this.successHandler) this.successHandler({errorCode: 13, errorMessage: err.message});
    }
  },

  verificationKey: async function() {
    try {
      const {dataForSign, certificate, signedData, CN} = this.info;

      const verificationkey = await AS.FORMS.ApiUtils.simpleAsyncPost("rest/sign/verificationkey", null, "text", {
        uuid: AS.OPTIONS.currentUser.userid,
        pemCer: certificate,
        edsInfo: CN
      });

      if(verificationkey === null || verificationkey.indexOf("::::") === -1)
      throw new Error('Произошла ошибка проверки ключа.');
      if(verificationkey === "CERT REVOKED") throw new Error('Сертификат отозван.');
      if(verificationkey === "CERT END") throw new Error('Сертификат просрочен.');

      const certID = verificationkey.split('::::')[0];
      const alg = verificationkey.split('::::')[1];

      this.info.certID = certID;
      this.info.alg = alg;

      if(this.successHandler) this.successHandler(this.info);
    } catch (err) {
      showMessage(i18n.tr(err.message), "error");
    }
  },

  sign: function(keysConstType = 'AUTH', documentID = null, handler) {
    if(!this.webSocket) this.initNCALayerSocket();
    this.keysConstType = keysConstType;
    this.documentID = documentID;
    this.info = {};

    if(handler && typeof handler == 'function') {
      this.successHandler = handler;
    } else {
      this.successHandler = null;
    }

    const timerID = setInterval(() => {
      if(this.connect) {
        this.getKeyInfo();
        clearInterval(timerID);
      }
    }, 500);
  },

  getAuthUUID: async function(){
    return new Promise(async resolve => {
      try {
        const response = await fetch(`../Synergy/rest/api/uuidForSignature`, {method: 'GET'});

        if(!response.ok) throw new Error(await response.text());
        resolve(response.json());
      } catch (err) {
        console.log(`ERROR [ getAsfDataUUID ]: ${err.message}`);
        resolve(null);
      }
    });
  },

  authEDS: function(handler) {
    if(!this.webSocket) this.initNCALayerSocket();
    this.keysConstType = 'authEDS';
    this.info = {};

    if(handler && typeof handler == 'function') {
      this.successHandler = handler;
    } else {
      this.successHandler = null;
    }

    this.getAuthUUID().then(res => {
      const timerID = setInterval(() => {
        if(this.connect) {
          this.signXML(res.uuid);
          clearInterval(timerID);
        }
      }, 500);
    });
  },

  registerEDS: function(handler) {
    if(!this.webSocket) this.initNCALayerSocket();
    this.keysConstType = 'registerEDS';
    this.info = {};

    if(handler && typeof handler == 'function') {
      this.successHandler = handler;
    } else {
      this.successHandler = null;
    }

    this.getAuthUUID().then(res => {
      const timerID = setInterval(() => {
        if(this.connect) {
          this.signXML(res.uuid);
          clearInterval(timerID);
        }
      }, 500);
    });
  }
};

const parseNcaLayerMsg = event => {
  if(event.data == "OK") return event.data;
  const data = JSON.parse(event.data);
  if(data) return({...data});
  return event;
}
