// Copyright (c) 2014-2019, MyMonero.com
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
//	conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
//	of conditions and the following disclaimer in the documentation and/or other
//	materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
//	used to endorse or promote products derived from this software without specific
//	prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
"use strict";
//
const response_parser_utils = require("./response_parser_utils");
const JSBigInt = require("../cryptonote_utils/biginteger").BigInteger; // important: grab defined export
//
function New_ParametersForWalletRequest(address, view_key__private) {
	return {
		address: address,
		view_key: view_key__private,
	};
}
exports.New_ParametersForWalletRequest = New_ParametersForWalletRequest;
//
function AddUserAgentParamters(
	parameters,
	appUserAgent_product,
	appUserAgent_version,
) {
	// setting these on params instead of as header field User-Agent so as to retain all info found in User-Agent, such as platform… and these are set so server has option to control delivery
	parameters["app_name"] = appUserAgent_product;
	parameters["app_version"] = appUserAgent_version;
}
exports.AddUserAgentParamters = AddUserAgentParamters;
//
function HTTPRequest(
	request_conformant_module, // such as 'request' or 'xhr' .. TODO: consider switching to 'fetch'
	apiAddress_authority, // authority means [subdomain.]host.…[:…] with no trailing slash
	endpointPath,
	final_parameters,
	fn,
) {
	// fn: (err?, data?) -> new Request
	if (typeof final_parameters == "undefined" || final_parameters == null) {
		throw "final_parameters must not be nil";
		// return null
	}
	const completeURL =
		_new_APIAddress_baseURLString(apiAddress_authority) + endpointPath;
	console.log("📡  " + completeURL);
	//
	const request_options = _new_requestOptions_base(
		"POST",
		completeURL,
		final_parameters,
	);
	const requestHandle = request_conformant_module(request_options, function(
		err_orProgressEvent,
		res,
		body,
	) {
		_new_HTTPRequestHandlerFunctionCallingFn(fn)(
			// <- called manually instead of directly passed to request_conformant_module call to enable passing completeURL
			completeURL,
			err_orProgressEvent,
			res,
			body,
		);
	});
	//
	return requestHandle;
}
exports.HTTPRequest = HTTPRequest;
//
function _new_APIAddress_baseURLString(
	apiAddress_authority, // authority means [subdomain.]host.…[:…]
) {
	return "https" + "://" + apiAddress_authority + "/";
}
function _new_requestOptions_base(methodName, completeURL, json_parameters) {
	return {
		method: methodName,
		url: completeURL,
		headers: {
			"Content-Type": "application/json",
			Accept: "application/json",
		},
		json: json_parameters,
		useXDR: true, // CORS
		withCredentials: true, // CORS
	};
}
function _new_HTTPRequestHandlerFunctionCallingFn(fn) {
	return function(completeURL, err_orProgressEvent, res, body) {
		// err appears to actually be a ProgressEvent
		var err = null;
		const statusCode = typeof res !== "undefined" ? res.statusCode : -1;
		if (statusCode == 0 || statusCode == -1) {
			// we'll treat 0 as a lack of internet connection.. unless there's a better way to make use of err_orProgressEvent which is apparently going to be typeof ProgressEvent here
			err = new Error("Connection Failure");
		} else if (statusCode !== 200) {
			const body_Error =
				body && typeof body == "object" ? body.Error : undefined;
			const statusMessage =
				res && res.statusMessage ? res.statusMessage : undefined;
			if (typeof body_Error !== "undefined" && body_Error) {
				err = new Error(body_Error);
			} else if (typeof statusMessage !== "undefined" && statusMessage) {
				err = new Error(statusMessage);
			} else {
				err = new Error("Unknown " + statusCode + " error");
			}
		}
		if (err) {
			console.error("❌  " + err);
			// console.error("Body:", body)
			fn(err, null);
			return;
		}
		var json;
		if (typeof body === "string") {
			try {
				json = JSON.parse(body);
			} catch (e) {
				console.error(
					"❌  HostedMoneroAPIClient Error: Unable to parse json with exception:",
					e,
					"\nbody:",
					body,
				);
				fn(e, null);
			}
		} else {
			json = body;
		}
		console.log("✅  " + completeURL + " " + statusCode);
		fn(null, json);
	};
}
