#include "lnurlutil.h"
#include "config.h"

namespace {

const uint8_t FIATPRECESION = 2;
const char* FIATCURRENCY = "EUR";

  Lnurl::SignerConfig getLnurlSignerConfig() {
    struct Lnurl::SignerConfig lnurl;
    lnurl.apiKey.id = "86f6d045d26e4e39";
    lnurl.apiKey.key = "b2ff678c2c634868b70bf678948e92c4382b1e8f7c651bd648b0caefd5cca613";
    lnurl.apiKey.encoding = "hex";
    lnurl.callbackUrl = "https://lnbits.makerlab-murnau.de/bleskomat/u";
    lnurl.shorten = true;
    return lnurl;
  }

	std::string generate_nonce() {
		std::ostringstream ss;
		uint32_t entropy = esp_random();
		// Random numbers generated by esp_random are probably sufficient.
		// But just to be safe let's append the current time in microseconds as well.
		auto extraEntropyFromTime = std::ceil((std::chrono::steady_clock::now().time_since_epoch().count() / 1000) % (UINT32_MAX / 10));
		entropy += extraEntropyFromTime;
		ss << entropy;
		return ss.str();
	}
}

namespace lnurlutil {

  std::string createQrContent (const double accumulatedValue) {
    const std::string signedUrl = createSignedLnurlWithdraw(accumulatedValue);
    const std::string encoded = lnurlEncode(signedUrl);
    std::string qrcodeData = "";
    qrcodeData += toUpperCase(encoded);
    return qrcodeData;
  }

	std::string createSignedLnurlWithdraw(const double &t_amount) {
		Lnurl::Signer signer(getLnurlSignerConfig());
		std::string nonce = generate_nonce();
		Lnurl::WithdrawParams params;
		std::string amount = floatToStringWithPrecision(t_amount, FIATPRECESION);
		params.minWithdrawable = amount;
		params.maxWithdrawable = amount;
		params.defaultDescription = "";
		params.custom["f"] = FIATCURRENCY;
		return signer.create_url(params, nonce);
	}

	std::string lnurlEncode(const std::string &text) {
		return Lnurl::encode(text);
	}

	std::string toUpperCase(std::string s) {
		std::transform(s.begin(), s.end(), s.begin(), [](unsigned char c){ return std::toupper(c); });
		return s;
	}

	std::string urlEncode(const std::string &value) {
		std::ostringstream escaped;
		escaped.fill('0');
		escaped << std::hex;
		for (std::string::const_iterator i = value.begin(), n = value.end(); i != n; ++i) {
			std::string::value_type c = (*i);
			// Keep alphanumeric and other accepted characters intact
			if (isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~') {
				escaped << c;
				continue;
			}
			// Any other characters are percent-encoded
			escaped << std::uppercase;
			escaped << '%' << std::setw(2) << int((unsigned char) c);
			escaped << std::nouppercase;
		}
		return escaped.str();
	}

	std::string floatToStringWithPrecision(const float &value, const unsigned short &precision) {
		std::ostringstream out;
		out.precision(precision);
		out << std::fixed << value;
		return out.str();
	}
}


