import CryptoJS from "crypto-js"
// import Base64 from 'crypto-js/enc-base64';
import crypto from 'crypto';
import { createHmac } from 'crypto';
import jwt from 'jsonwebtoken';
import axios from 'axios';
import jose from 'node-jose';
import { User } from '../models_nosql';
import { getSingleUserProperty } from '../common';
import { CONSTANTS_GX } from '../constants';

// API_MG
// DOC_MG https://mxcdevelop.github.io/apidocs/spot_v3_en/#query-the-apikey-of-a-sub-account-for-master-account

// DOC_KX https://www.okx.com/docs-v5/en/#overview-v5-api-key-creation

// API_BZ_p2p https://github.com/bitzlato/api-auth-examples/blob/develop/js/connect.js
// DOC_BZ https://bitzlato.bz/swagger-ui/index.html?urls.primaryName=default#/user-ads-controller
// DOC_BZ https://bitzlato.com/docs
// API_BZ_spot https://github.com/bitzlato/peatio/blob/master/docs/api/websocket_api.md

// DOC_BT https://bybit-exchange.github.io/docs/futuresV2/linear/#t-authenticationparameters

// API_GT_v2 https://github.com/gateio/gateapi-nodejs
// DOC_GT_v2 https://www.gate.io/api2#depthc2c
// DOC_GT_v4 https://www.gate.io/api2#depthc2c

// DOC_KC https://www.kucoin.com/docs/rest/spot-trading/market-data/introduction

// DOC_PX https://pexpayapi.github.io/apidocs/spot/en/#p2p-endpoints

// API_BT https://bybit-exchange.github.io/docs/spot/v3/#t-authenticationparameters

// DOC_BG https://bitgetlimited.github.io/apidoc/en/mix/#api-verification
// DOC_BG https://bitgetlimited.github.io/apidoc/en/spot/#p2p-endpoint
// API_BG https://www.npmjs.com/package/bitget-api
// API_BG https://github.com/tiagosiebler/bitget-api

// DOC_HB https://www.huobi.com/ru-ru/opend/newApiPages/?id=419

// DOC_CN https://docs.coinex.com/api/v2/

// DOC_XT https://doc.xt.com/#documentationsignStatement

// DOC_AX https://apidocs.abcex.io/

// DOC_CM https://doc.cryptomus.com/ru/personal/general/getting-api-keys

// получение сигнатуры запроса Binance API
export const getSignature_BN = (query_string, apiSecret) => {
	// const res =  CryptoJS.HmacSHA256(query_string, apiSecret)
	// console.log("CryptoJS: "+res)
	return crypto
		.createHmac('sha256', apiSecret)
		.update(query_string)
		.digest('hex');
};

// получение сигнатуры запроса Huobi API
export const getSignature_HB = (query_string, apiSecret) => {
	const hash = CryptoJS.HmacSHA256(query_string, apiSecret)
	const signature = encodeURIComponent(CryptoJS.enc.Base64.stringify(hash));
	// console.log(signature)
	return signature
};

// получение сигнатуры запроса Okx API
export const getSignature_KX = (query_string, apiSecret) => {
	const hash = CryptoJS.HmacSHA256(query_string, apiSecret)
	const signature = CryptoJS.enc.Base64.stringify(hash)
	return signature
};

// получение сигнатуры запроса Pexpay API
export const getSignature_PX = (query_string, apiSecret) => {
	return crypto
		.createHmac('sha256', apiSecret)
		.update(query_string)
		.digest('hex');
};

// получение сигнатуры запроса CommEx API
export const getSignature_CX = (query_string, apiSecret) => {
	return crypto
		.createHmac('sha256', apiSecret)
		.update(query_string)
		.digest('hex');
};

// получение сигнатуры запроса Bybit API
export const getSignature_BT = (query_string, apiSecret) => {
	return crypto
		.createHmac('sha256', apiSecret)
		.update(query_string)
		.digest('hex');
};

// получение сигнатуры запроса Bitget API
export const getSignature_BG = (query_string, apiKeys) => {
	// https://github.com/BitgetLimited/v3-bitget-api-sdk/blob/222eecf98e1eb16b9a67a5ae4e7c4494122b200f/bitget-node-sdk-open-api/model/util.ts#L3
	return {
		signature: crypto
			.createHmac('sha256', apiKeys.secretKey)
			.update(query_string)
			.digest()
			.toString('base64'),
		passPhrase: 'ABCDk777',
		publicKey: apiKeys.publicKey,
	};
};

// получение сигнатуры запроса Mexc API
export const getSignature_MG = (query_string, apiSecret) => {
	return crypto
		.createHmac('sha256', apiSecret)
		.update(query_string)
		.digest('hex');
};

// получение сигнатуры запроса Gateio API
export const getSignature_GT = (query_string, apiSecret) => {
	return crypto
		.createHmac('sha256', apiSecret)
		.update(query_string)
		.digest('hex');
};

// получение сигнатуры запроса Kucoin API
export const getSignature_KC = (query_string, apiSecret) => {
	const hash = CryptoJS.HmacSHA256(query_string, apiSecret)
	const signature = CryptoJS.enc.Base64.stringify(hash)
	return signature
};

// получение сигнатуры запроса BingX API
export const getSignature_BX = (query_string, apiSecret) => {
	return crypto
		.createHmac('sha256', apiSecret)
		.update(query_string)
		.digest('hex');
};

// получение сигнатуры запроса Xeggex API
export const getSignature_XG = (query_string, apiSecret) => {
	return crypto
		.createHmac('sha256', apiSecret)
		.update(query_string)
		.digest('hex');
};

// получение сигнатуры запроса XT.com API
export const getSignature_XT = (query_string, apiSecret) => {
	return crypto
		.createHmac('sha256', apiSecret)
		.update(query_string)
		.digest('hex');
};

// получение сигнатуры запроса CoinEx API
export const getSignature_CN = (query_string, apiSecret) => {
	return crypto
		.createHmac('sha256', apiSecret)
		.update(query_string)
		.digest('hex');
};

// получение сигнатуры запроса Bitmart API
export const getSignature_BM = (query_string, apiSecret) => {
	return crypto
		.createHmac('sha256', apiSecret)
		.update(query_string)
		.digest('hex');
};

// получение сигнатуры запроса Cryptomus API
export const getSignature_CM = (query_string, apiSecret) => {
	var Base64 = {
		_keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
		//метод для кодировки в base64 на javascript
	encode : function (input) {
		var output = "";
		var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
		var i = 0
		input = Base64._utf8_encode(input);
				while (i < input.length) {
				chr1 = input.charCodeAt(i++);
			chr2 = input.charCodeAt(i++);
			chr3 = input.charCodeAt(i++);
				enc1 = chr1 >> 2;
			enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
			enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
			enc4 = chr3 & 63;
				if( isNaN(chr2) ) {
					enc3 = enc4 = 64;
			}else if( isNaN(chr3) ){
				enc4 = 64;
			}
				output = output +
			this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) +
			this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4);
			}
		return output;
	},

		//метод для раскодировки из base64
	decode : function (input) {
		var output = "";
		var chr1, chr2, chr3;
		var enc1, enc2, enc3, enc4;
		var i = 0;
			input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
			while (i < input.length) {
				enc1 = this._keyStr.indexOf(input.charAt(i++));
			enc2 = this._keyStr.indexOf(input.charAt(i++));
			enc3 = this._keyStr.indexOf(input.charAt(i++));
			enc4 = this._keyStr.indexOf(input.charAt(i++));
				chr1 = (enc1 << 2) | (enc2 >> 4);
			chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
			chr3 = ((enc3 & 3) << 6) | enc4;
				output = output + String.fromCharCode(chr1);
				if( enc3 != 64 ){
				output = output + String.fromCharCode(chr2);
			}
			if( enc4 != 64 ) {
				output = output + String.fromCharCode(chr3);
			}
		}
		output = Base64._utf8_decode(output);
			return output;
		},
		// метод для кодировки в utf8
	_utf8_encode : function (string) {
		string = string.replace(/\r\n/g,"\n");
		var utftext = "";
		for (var n = 0; n < string.length; n++) {
			var c = string.charCodeAt(n);
				if( c < 128 ){
				utftext += String.fromCharCode(c);
			}else if( (c > 127) && (c < 2048) ){
				utftext += String.fromCharCode((c >> 6) | 192);
				utftext += String.fromCharCode((c & 63) | 128);
			}else {
				utftext += String.fromCharCode((c >> 12) | 224);
				utftext += String.fromCharCode(((c >> 6) & 63) | 128);
				utftext += String.fromCharCode((c & 63) | 128);
			}
			}
		return utftext;

	},

	//метод для раскодировки из urf8
	_utf8_decode : function (utftext) {
		var string = "";
		var i = 0;
		var c = c1 = c2 = 0;
		while( i < utftext.length ){
			c = utftext.charCodeAt(i);
				if (c < 128) {
				string += String.fromCharCode(c);
				i++;
			}else if( (c > 191) && (c < 224) ) {
				c2 = utftext.charCodeAt(i+1);
				string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
				i += 2;
			}else {
				c2 = utftext.charCodeAt(i+1);
				c3 = utftext.charCodeAt(i+2);
				string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
				i += 3;
			}
			}
			return string;
	}
	}
	const hash = CryptoJS.enc.Base64.parse(query_string).toString()
	// const hash = query_string.toString(CryptoJS.enc.Base64)
	// const hash = CryptoJS.enc.Base64.stringify(query_string)
	// const hash = Base64.encode(query_string).toString()
	console.log(hash)
	const signature = CryptoJS.MD5(hash+apiSecret).toString();

	// const signature = md5(base64_encode(query_string), apiSecret);
	// const signature = Buffer.from(hash).toString('base64');
	// console.log(signature)
	return signature
};

// Получаем токен авторизации Garantex
export const getToken_GX = async (userId) => {
	try {
		const user = await User.findOne({ _id: userId });
		const apiKeys = getSingleUserProperty(
			'apiKeys',
			'Garantex',
			user.properties
		);
		const { publicKey, secretKey } = apiKeys;
		let { data } = await axios.post(CONSTANTS_GX.GET_AUTH_TOKEN.url, {
			kid: publicKey,
			jwt_token: jwt.sign(
				{
					exp: Math.round(Date.now() / 1000) + 30 * 60, // JWT Request TTL: 30 minutes
					jti: crypto.randomBytes(12).toString('hex'),
				},
				new Buffer.from(secretKey, 'base64').toString('ascii'),
				{ algorithm: 'RS256' }
			),
		});
		return data.token;
	} catch (e) {
		console.error(e);
		return false;
	}
};

// Получаем токен spot-авторизации Bitzlato
export const getToken_SPOT_BZ = async (userId) => {};

// Получаем токен p2p-авторизации Bitzlato
export const getToken_P2P_BZ = async (userId) => {
	try {
		const user = await User.findOne({ _id: userId });
		const apiKeys = getSingleUserProperty(
			'apiKeys',
			'Bitzlato',
			user.properties
		);

		const secret = JSON.parse(apiKeys.secretKey);

		// секретный ключ пользователя (private key). ID данного ключа (kid) = "1",
		// его вам выдали при постановке ключа. Или же его потом можно найти в настройках в web интерфейсе
		// const secret = {
		// 	kty: 'EC',
		// 	alg: 'ES256',
		// 	crv: 'P-256',
		// 	x: '4xEtXzZtG0uBYdYRGWxvAKidgVVJFVT__lDJL4fiBzM',
		// 	y: 'BgOXP5jnl6XQaXRYBDJG2UcLAL51eA5rqanqQ7LBlqE',
		// 	d: 'Pbw9qxHKzbAeDDpRaq6RM2OBBEFBALyqyBiHBlIcc5A',
		// };

		// обязательные claims
		// required claims
		const claims = {
			// user identity, one of: email, uid (user id), subject, tgid (telegram id)
			// идентификатор пользователя, одно из: email, uid (user id), subject, tgid (telegram id)
			// Email won't work in case when a user has two accounts with the same email, prefer user id (uid) for such case.
			// Email не будет работать в случае если у пользователя два аккаунта с один и тем же email (auth0 & google)
			// Используйте uid в таких случаях
			// email: 'bitzlato.demo@gmail.com',
			email: 'komplekt_17@mail.ru',
			// uid: '14789277',
			// leave as is
			// оставляем как есть
			aud: 'usr',
			// token issue time
			// время когда выпущен токен
			iat: (Date.now() / 1000) | 0,
			// unique token identifier
			// уникальный идентификатор токена
			jti: jose.util.randomBytes(8).toString('base64'),
		};

		// generate jwt token from users' private key
		// генерируем jwt token из секретного ключа пользователя
		const jwt = await jose.JWS.createSign(
			{
				alg: 'ES256',
				format: 'compact',
				// You omit this header if the account has a single key
				// Этот заголовок можно не указывать, если у аккаунта единственный ключ
				fields: { kid: '1' },
			},
			{ key: secret, reference: false }
		)
			.update(JSON.stringify(claims))
			.final();

		return jwt;

		// set auth header with token
		// установливаем заголовок аутентификации с токеном
		// const options = {
		// 	headers: {
		// 		Authorization: `Bearer ${jwt}`,
		// 	},
		// };

		// change to bitzlato api host
		// изменить на хост api bitzlato
		// await axios
		// 	.get('https://bitzlato.bz/api/p2p/trade/?limit=10&skip=0', options)
		// 	// .get('https://bitzlato.bz/api/auth/whoami', options)
		// 	.then((response) => {
		// 		console.log('strinf 139: ' + response.data.data.length);
		// 		console.log(response.data);
		// 	});
	} catch (e) {
		console.error('string 155: ' + e);
		return false;
	}
};
