//------------------------------------------------------------------------------------
//npm install --save axios moment dotenv
const axios = require("axios");
const moment = require("moment");
require('dotenv').config()

//------------------------------------------------------------------------------------
/*
BEFORE RUNNING THIS EXAMPLE: 

* Set CONNECTFI_CLIENTID, CONNECTFI_PASSWORD, and CONNECTFI_BASE_URL in an .env file 
(Speak to a support representative to be issued client credentials and URL after 
receiving access to the sandbox.)

* Set UNIQUE_REFERENCE_ID to a unique identifier.

*/
const CONNECTFI_CLIENTID = process.env.CONNECTFI_CLIENTID;
const CONNECTFI_PASSWORD = process.env.CONNECTFI_PASSWORD;
const CONNECTFI_BASE_URL = process.env.CONNECTFI_BASE_URL;

const UNIQUE_REFERENCE_ID = "exampleRef1007"; //Update this value so that it is a unique ID before running

//------------------------------------------------------------------------------------
//Get Authorization Token
/*
All other requests must have a valid authorization token in the request headers, 
so your first request in any workflow should be to /auth/get-token in order to receive 
an authorization token. A valid token should be included in the headers of all 
subsequent requests.

*/
async function getAuthToken() {
  const data = {
    "user": {
      "login": `${CONNECTFI_CLIENTID}`,
      "password": `${CONNECTFI_PASSWORD}`
    }
  };
  const config = {
    method: 'POST',
    url: `${CONNECTFI_BASE_URL}/auth/get-token`,
    headers: {
      'Content-Type': "application/json"
    },
    data
  };

  let result;
  try {
    result = await axios.request(config);
    if (result.status === 200) {
      return Promise.resolve(result.data.data);
    }
  } catch (err) {
    console.log({
      errCode: err.code,
      responseStatus: err.response && err.response.status,
      data: err.response && JSON.stringify(err.response.data)
    });
  }
}


//------------------------------------------------------------------------------------
//Send a Wire
/*
Send a wire transfer through a POST request to /transfer-to/wire. Wire transfers are 
processed same-day and funds typically are transferred within a few hours. As soon as 
our banking partner sends confirmation that the wire transfer request has been 
received, you will receive a webhook showing the transfer status has updated to 
"Complete".

*/
async function sendWire(authToken) {

  const data = {
    "amount": 16.53,
    "currency": "USD",
    "endUserAccount": "1234567890123456",
    "reference": UNIQUE_REFERENCE_ID,
    "originator": {
      "commonName": "John Doe",
      "legalName": "John Doe",
      "address": {
        "addressLine1": "999 Main Street",
        "addressLine2": "Ste. A",
        "city": "San Francisco",
        "state": "CA",
        "postalCode": "12345",
        "country": "US"
      }
    },
    "beneficiary": {
      "bankName": "Unicorn Bank",
      "bankABANumber": "122244184",
      "accountNumber": "1234567890123456",
      "name": "John Smith",
      "address": {
        "addressLine1": "1346 Pleasant Ave",
        "addressLine2": "Apt A123",
        "city": "Salt Lake City",
        "state": "UT",
        "postalCode": "12345",
        "country": "US"
      }
    },
    "narrative": "Invoice #123 for May",
    "memos": [
      "For spare parts per contract #123",
      "Delivered Salt Lake City UT 12345"
    ],
    "webhookURL": `https://your_webhook_url/${UNIQUE_REFERENCE_ID}`
  };
  const config = {
    method: 'POST',
    url: `${CONNECTFI_BASE_URL}/transfer-to/wire`,
    headers: {
      'Content-Type': "application/json",
      'x-connectfi-token': authToken //previously obtained authorization token is required
    },
    data
  };

  let result;
  try {
    result = await axios.request(config);

    if (result.status === 200) {
      return Promise.resolve(result.data.data);
    }
  } catch (err) {
    console.log({
      errCode: err.code,
      responseStatus: err.response && err.response.status,
      data: err.response && JSON.stringify(err.response.data)
    });
  }
}


//------------------------------------------------------------------------------------
//Query
/*
If you have not received a webhook response with an expected status change within 
the expected time period, you may query the current status of up to 20 wire transfers 
at a time using a /transfer-to/wire/query request. It is recommended that you run a 
/transfer-to/wire/query request only once or twice per day. The conditions under 
which a /transfer-to/wire/query should be made are as follows:

* A status change was expected to have already occurred (For example, a wire was 
  sent. It is now 12 hours later and a status change to "Complete" or "Declined" 
  was expected to have already occurred.)
* An expected webhook response has not been received for the transfer. This is a 
  rare occurrence and would indicate that something unforeseen has happened.
* Do not send multiple queries for the same transaction within a 12 hour period. 
  If a query confirms that the status of a wire transfer has not moved when 
  expected, contact customer support with the cFiTransactionId, current status, 
  expected status, and date that the wire transfer was created.
* If you have more than one wire transfer to query, do not send multiple queries 
  with one transfer at a time. The queries should be sent in batches of 20 
  cFiTransactionIds/reference IDs per request. If you have less than 20 transfers 
  to query, they can all be queried in a single request.

Note: When testing, wire transfers in the sandbox environment will not move status 
unless triggered. See "Testing Wires in the Sandbox" in the API documentation for 
a description of how to trigger error messages and status changes for wires when 
in a testing environment.

*/
async function query(authToken, cFiTransactionId) {

  const data = {
    "cFiTransactionIds": [cFiTransactionId]
  };
  const config = {
    method: 'POST',
    url: `${CONNECTFI_BASE_URL}/transfer-to/wire/query`,
    headers: {
      'Content-Type': "application/json",
      'x-connectfi-token': authToken //previously obtained authorization token is required
    },
    data
  };

  let result;
  try {
    result = await axios.request(config);
    if (result.status === 200) {
      return Promise.resolve(result.data.data);
    }
  } catch (err) {
    console.log({
      errCode: err.code,
      responseStatus: err.response && err.response.status,
      data: err.response && JSON.stringify(err.response.data)
    });
  }
}


//------------------------------------------------------------------------------------
//List
/*
It is possible to list up to 1000 wire transfers at a time using search criteria with 
a /transfer-to/wire/list request. Search criteria may include a date range, a status 
value, or a combination of these search criteria. Use case examples for a 
/transfer-to/wire/list request include but are not limited to the following.

* Listing all wire transfers that still have a "Sent" status.
* Listing all transactions that have a "Declined" status with a date range of 
  "2023-05-10T12:00:30.000Z" to "2023-05-11T12:00:00.000Z".
* Listing all transactions that have a "Completed" status in batches of 150. (You can 
  use the "numberOfRecords" property and the "skipRecords" property to list up to 
  1000 transfers at a time or to skip a certain number of transfers.)

*/
async function list(authToken, status, numRecords, numToSkip) {

  const data = {
    "dateCreateFrom": `${new Date(moment(new Date()).add(-1, "hour")).toISOString()}`,
    "dateCreateTo": `${new Date(moment(new Date()).add(1, "hour")).toISOString()}`,
    "status": status,
    "numberOfRecords": numRecords,
    "skipRecords": numToSkip
  };
  const config = {
    method: 'POST',
    url: `${CONNECTFI_BASE_URL}/transfer-to/wire/list`,
    headers: {
      'Content-Type': "application/json",
      'x-connectfi-token': authToken //previously obtained authorization token is required
    },
    data
  };

  let result;
  try {
    result = await axios.request(config);
    if (result.status === 200) {
      return Promise.resolve(result.data.data);
    }
  } catch (err) {
    console.log({
      errCode: err.code,
      responseStatus: err.response && err.response.status,
      data: err.response && JSON.stringify(err.response.data)
    });
  }
}


//------------------------------------------------------------------------------------
//Run the walkthrough
async function wiresWalkthrough() {

  //Get Authorization Token
  console.log(`Start /auth/get-token example.\n`);
  const authObject = await getAuthToken();
  let authToken = undefined;

  if (authObject) {
    console.log(`Successfully obtained authorization: ${JSON.stringify(authObject)}\n`);
    authToken = authObject.token;
    console.log(`Authorization token: ${authToken}\n`);
  } else {
    console.log(`Error getting authorization token\n`)
  }
  console.log(`End /auth/get-token example.\n`);

  //Send a Wire
  console.log(`Start /transfer-to/wire example.\n`);
  let sendWireResult;
  if (authToken) {
    sendWireResult = await sendWire(authToken);
  } else {
    console.log(`Authorization token is required.\n`)
  }
  if (sendWireResult) {
    console.log(`Successfully created wire: ${JSON.stringify(sendWireResult)}\n`);
  }
  console.log(`End /transfer-to/wire example.\n`);

  //Query
  console.log(`Start /transfer-to/wire/query.\n`);
  let wireQueryResult;
  if (authToken && sendWireResult && sendWireResult.cFiTransactionId) {
    wireQueryResult = await query(authToken, sendWireResult.cFiTransactionId);
  } else {
    console.log(`Authorization token and cFiTransactionId are required.\n`)
  }
  if (wireQueryResult) {
    console.log(`Successfully queried wires: ${JSON.stringify(wireQueryResult)}\n`);
  }
  console.log(`End /transfer-to/wire/query.\n`);

  //List
  console.log(`Start transfer-to/wire/list example.\n`);
  let listWiresResult;
  if (authToken) {
    listWiresResult = await list(authToken, "Sent", 5, 0);
  } else {
    console.log(`Authorization token is required.\n`)
  }
  if (listWiresResult) {
    console.log(`Successfully retrieved list of wires matching criteria: ${JSON.stringify(listWiresResult)}\n`);
  }
  console.log(`End transfer-to/wire/list example.\n`);

}

if (process.env.CONNECTFI_CLIENTID && process.env.CONNECTFI_PASSWORD && process.env.CONNECTFI_BASE_URL) {
  wiresWalkthrough();
} else {
  console.log("Before running the walkthrough, set the required .env variables.");
}