text: import createStep from '../createStep';
  import createModuleCreator from '../createModuleCreator';
  import { getMethodByHandlingModule, methodTypes, moduleNames } from '../config';
  import MethodException from '../MethodException';
  
  const MODULE_NAME = moduleNames.idCardSignature;
  
  const settingsSchema = {
    iframeHolder: {
      type: 'object',
    },
    docId: {
      type: 'string',
      required: true,
    },
  };
  
  const createMessenger = function createMessenger({ iframe }) {
    const url = new URL(iframe.src);
    return {
      post(message) {
        iframe.contentWindow.postMessage(message, url.origin);
      },
    };
  };
  
  const getIframeUrl = function getIframeUrl({ countryCode, clientId, apiEndpoints }) {
    const method = getMethodByHandlingModule(methodTypes.SIGNATURE, MODULE_NAME, countryCode);
    return apiEndpoints.inCurrentMode.idCardIframe({
      clientId,
      actionType: method.actionType,
    });
  };
  
  const handleIframeError = function handleIframeError(error, i18n) {
    if (error instanceof Error) {
      throw error;
    }
  
    let userMessage;
    if (error.result === 'no_certificates') {
      userMessage = i18n.t('no_certificates');
    }
    throw new MethodException({
      userMessage,
      message: error.message,
      details: error,
    });
  };
  
  const createIframe = function createIframe({
    iframeHolder, iframeUrl, i18n,
  }) {
    const iframe = document.createElement('iframe');
    iframe.setAttribute('src', iframeUrl);
    iframe.setAttribute('referrerpolicy', 'origin');
    iframe.style.width = '0';
    iframe.style.height = '0';
    iframe.style.position = 'absolute';
    iframe.style.border = '0';
    // eslint-disable-next-line no-param-reassign
    iframeHolder.innerHTML = '';
    const promise = new Promise((resolve, reject) => {
      window.addEventListener('message', (e) => {
        const { operation, error, status } = e.data;
        if (error) {
          reject(e.data);
        } else if (operation === 'ready' || operation === 'welcome') {
          if (status === 'OK') {
            resolve(iframe);
          } else {
            reject(e.data);
          }
        } else {
          reject(e.data);
        }
      }, { once: true });
      // eslint-disable-next-line prefer-promise-reject-errors
      window.setTimeout(() => reject({ message: i18n.t('createIframeTimeout') }), 30 * 1000);
    });
    iframeHolder.appendChild(iframe);
    return promise;
  };
  
  const getCertificate = function getCertificate({ messenger }) {
    const promise = new Promise((resolve, reject) => {
      window.addEventListener('message', (e) => {
        const { result, cert } = e.data;
        if (result === 'ok' && cert) {
          resolve(e.data);
        } else {
          let error = {};
          if (e.data && e.data.result === 'user_cancel') {
            error.isCancel = true;
          } else {
            error = e.data;
          }
          reject(error);
        }
      }, { once: true });
    });
  
    messenger.post({
      operation: 'getCertificate',
    });
  
    return promise;
  };
  
  const startSigning = function startSigning({
    certificate, clientId, docId, cancelToken, apiEndpoints, apiClient,
  }) {
    const url = apiEndpoints.inCurrentMode.startSigning();
    return apiClient.post({
      url,
      withCredentials: false,
      data: {
        client_id: clientId,
        doc_id: docId,
        sign_type: 'id-card',
        certificate,
      },
      cancelToken,
    });
  };
  
  const getSignature = function createSignature({ messenger, hexDigest }) {
    const promise = new Promise((resolve, reject) => {
      window.addEventListener('message', (e) => {
        const { result, signature } = e.data;
        if (result === 'ok' && signature) {
          resolve(e.data);
        } else {
          let error = {};
          if (e.data && e.data.result === 'user_cancel') {
            error.isCancel = true;
          } else {
            error = e.data;
          }
          reject(error);
        }
      }, { once: true });
    });
  
    messenger.post({
      operation: 'getSignature',
      hexDigest,
    });
  
    return promise;
  };
  
  const completeSigning = function completeSigning({
    signature, clientId, docId, cancelToken, apiEndpoints, apiClient,
  }) {
    const url = apiEndpoints.inCurrentMode.completeSignatureIdCard();
    return apiClient.post({
      url,
      withCredentials: false,
      data: {
        client_id: clientId,
        doc_id: docId,
        signature_value: signature,
      },
      cancelToken,
    });
  };
  
  const executable = async function executable(config) {
    const iframeUrl = await createStep(getIframeUrl, { shouldFormatResult: false })({
      countryCode: config.countryCode,
      clientId: config.clientId,
      apiEndpoints: config.apiEndpoints,
    });
  
    const iframe = await createStep(createIframe, { shouldFormatResult: false })({
      iframeUrl,
      iframeHolder: config.iframeHolder,
      i18n: config.i18n,
    }).catch((error) => handleIframeError(error, config.i18n));
  
    const messenger = await createStep(createMessenger, { shouldFormatResult: false })({
      iframe,
    });
  
    const certificateResult = await createStep(getCertificate, {
      shouldFormatResult: false,
    })({
      messenger,
    }).catch((error) => handleIframeError(error, config.i18n));
  
    const startSigningResult = await createStep(startSigning)({
      certificate: certificateResult.cert,
      clientId: config.clientId,
      docId: config.docId,
      cancelToken: config.cancelToken,
      apiEndpoints: config.apiEndpoints,
      apiClient: config.apiClient,
    });
  
    const getSignatureResult = await createStep(getSignature, { shouldFormatResult: false })({
      messenger,
      hexDigest: startSigningResult.data.hexDigest,
    });
  
    return createStep(completeSigning)({
      signature: getSignatureResult.signature,
      clientId: config.clientId,
      docId: config.docId,
      cancelToken: config.cancelToken,
      apiEndpoints: config.apiEndpoints,
      apiClient: config.apiClient,
    });
  };
  
  const createIdCardSignature = createModuleCreator(MODULE_NAME, executable, settingsSchema);
  export default createIdCardSignature;
  