const request = require('request');
const { hashPersonalMessage, ecsign, ecrecover, toRpcSig, fromRpcSig, keccak256, addHexPrefix, sha3 } = require('ethereumjs-util');
const { default: MerkleTree } = require('merkle-tree-solidity');

const args = process.argv.slice(2);
const [configPath] = args;

// Configuration file downloaded after registering device
const deviceConfig = require(configPath);

const hashMessageEth = message => hashPersonalMessage(Buffer.from(message));

const signMessageEth = (message, privateKey) => {
  let messageHash = hashMessageEth(message);
  //console.log('Message hash: ' + messageHash.toString('hex'));
  let { v, r, s } = ecsign(messageHash, privateKey);
  let rpcSignature = toRpcSig(v, r, s);
  //console.log('Message signature: ' + rpcSignature);
  return rpcSignature;
}

const validateSignatureEth = (messageHash, signature, publicKey, address) => {
  signature = fromRpcSig(signature);
  let recoveredPublicKey = ecrecover(messageHash, signature.v, signature.r, signature.s);
  let recoveredPublicKeyHex = recoveredPublicKey.toString('hex');
  let recoveredAddress = addHexPrefix(keccak256(recoveredPublicKey).toString('hex').substring(64 - 40));
  //console.log('Recovered public key: ' + recoveredPublicKeyHex);
  //console.log('Recovered address: ' + recoveredAddress);
  if (recoveredPublicKeyHex === publicKey && recoveredAddress === address) return true;
  return false;
}

// Gather data and sign
const privateKey = Buffer.from(deviceConfig.privateKey, 'hex');

let message = 'test';
let signature = signMessageEth(message, privateKey);

// Validate signature
if (!validateSignatureEth(hashMessageEth(message), signature, deviceConfig.publicKey, deviceConfig.address)) {
  process.exit();
}

// Construct Merkle tree
const metadataHashes = deviceConfig.metadata.map(el => sha3(el));
const merkleTree = new MerkleTree(metadataHashes);

// Index of metadata element to send
const elementToSend = 0;

// Generate proof
let proof = merkleTree.getProof(metadataHashes[elementToSend]);
proof = proof.map(el => addHexPrefix(el.toString('hex')));

// Build payload
let payload = {
  deviceId: deviceConfig.deviceId,
  message,
  signature: signature,
  metadata: deviceConfig.metadata[elementToSend],
  proof,
  firmware: deviceConfig.firmware,
  curve: deviceConfig.curve
}

// Send to platform
const platformEndpoint = 'http://localhost:1337/receive'
request.post({ url: platformEndpoint, json: payload }, function (error, response, body) {
  if (!error) {
    console.log(body)
  } else {
    console.log(error);
  }
})