import { ParsedMessage } from '@spruceid/siwe-parser';
import log from 'loglevel';
import { stripHexPrefix } from './hexstring-utils';

const msgHexToText = (hex) => {
  try {
    const stripped = stripHexPrefix(hex);
    const buff = Buffer.from(stripped, 'hex');
    return buff.length === 32 ? hex : buff.toString('utf8');
  } catch (e) {
    log.error(e);
    return hex;
  }
};

/**
 * A locally defined object used to provide data to identify a Sign-In With Ethereum (SIWE)(EIP-4361) message and provide the parsed message
 *
 * @typedef localSIWEObject
 * @param {boolean} isSIWEMessage - Does the intercepted message conform to the SIWE specification?
 * @param {ParsedMessage} parsedMessage - The data parsed out of the message
 */

/**
 * This function intercepts a sign message, detects if it's a
 * Sign-In With Ethereum (SIWE)(EIP-4361) message, and returns an object with
 * relevant SIWE data.
 *
 * {@see {@link https://eips.ethereum.org/EIPS/eip-4361}}
 *
 * @param {object} msgParams - The params of the message to sign
 * @returns {localSIWEObject}
 */
export const detectSIWE = (msgParams) => {
  try {
    const { data } = msgParams;
    const message = msgHexToText(data);
    const parsedMessage = new ParsedMessage(message);

    return {
      isSIWEMessage: true,
      parsedMessage,
    };
  } catch (error) {
    // ignore error, it's not a valid SIWE message
    return {
      isSIWEMessage: false,
      parsedMessage: null,
    };
  }
};

/**
 * Takes in a parsed Sign-In with Ethereum Message (EIP-4361)
 * and generates an array of label-value pairs
 *
 * @param {object} parsedMessage - A parsed SIWE message with message contents
 * @param {Function} t - i18n function
 * @returns {Array} An array of label-value pairs with the type of the value as the label
 */
export const formatMessageParams = (parsedMessage, t) => {
  const output = [];

  const {
    statement,
    uri,
    version,
    chainId,
    nonce,
    issuedAt,
    expirationTime,
    notBefore,
    requestId,
    resources,
  } = parsedMessage;

  if (statement) {
    output.push({
      label: t('SIWELabelMessage'),
      value: statement,
    });
  }

  if (uri) {
    output.push({
      label: t('SIWELabelURI'),
      value: uri,
    });
  }

  if (version) {
    output.push({
      label: t('SIWELabelVersion'),
      value: version,
    });
  }

  if (chainId) {
    output.push({
      label: t('SIWELabelChainID'),
      value: chainId,
    });
  }

  if (nonce) {
    output.push({
      label: t('SIWELabelNonce'),
      value: nonce,
    });
  }

  if (issuedAt) {
    output.push({
      label: t('SIWELabelIssuedAt'),
      value: issuedAt,
    });
  }

  if (expirationTime) {
    output.push({
      label: t('SIWELabelExpirationTime'),
      value: expirationTime,
    });
  }

  if (notBefore) {
    output.push({
      label: t('SIWELabelNotBefore'),
      value: notBefore,
    });
  }

  if (requestId) {
    output.push({
      label: t('SIWELabelRequestID'),
      value: requestId,
    });
  }

  if (resources && resources.length > 0) {
    output.push({
      label: t('SIWELabelResources', [resources.length]),
      value: resources
        .reduce((previous, resource) => `${previous}${resource}\n`, '')
        .trim(),
    });
  }

  return output;
};