import { Router } from 'express';
import bcrypt from 'bcryptjs';
import { auth } from '../middleware';
import {
	User,
	Ticker,
	PayType,
	OrderStatus,
	Exchange,
	Currency,
} from '../models_nosql';
import { getToken_GX, getToken_P2P_BZ } from '../utilities';
import {
	getSingleUserProperty,
	getArrayItemsCustomed,
	updateAuthToken_BZ_GX,
} from '../common';

export const usersRouter = Router();

// https://medium.com/swlh/jwt-authentication-authorization-in-nodejs-express-mongodb-rest-apis-2019-ad14ec818122

// преобразование UserProperties для frontend
const getUserProperties = (properties) => {
	const userProps = [];
	if (properties.length !== 0) {
		for (let i = 0; i < properties.length; i++) {
			userProps.push({
				exchange: properties[i].exchange,
				exchangeId: properties[i].exchangeId,
				exchangeUserId: properties[i].exchangeUserId,
				userNickName: properties[i].userNickName,
				updateOrders: properties[i].updateOrders,
				soundAlert: properties[i].soundAlert,
				payTypeList: properties[i].payTypeList,
				dateApiKeys:
					properties[i].apiKeys.publicKey !== '' &&
					properties[i].apiKeys.secretKey !== ''
						? properties[i].apiKeys.dateApiKeys
						: 0,
				favorites: properties[i].favorites,
				// requestHeader: properties[i].requestHeader,
				requestHeader: {},
				p2pOrders: [],
				spotOrders: [],
				merchantOrders: [],
				merchantPayMethods: [],
				merchantAdvs: [],
				currentBalances: {
					p2pBalance: [],
					spotBalance: [],
					futBalance: [],
					earnBalance: [],
				},
			});
		}
	}
	return userProps;
};

// создание properties для нового юзера
const createNewUserProperties = (arrExchanges) => {
	const userProperties = [];
	for (let i = 0; i < arrExchanges.length; i++) {
		const item = {
			exchange: arrExchanges[i].name,
			exchangeId: arrExchanges[i]._id,
			exchangeUserId: '',
			userNickName: 'User',
			updateOrders: false,
			orderStatuses: { unpaid: 0, paid: 0 },
			soundAlert: 'Sound/newOrder.wav',
			payTypeList: [],
			requestHeader: {},
			apiKeys: {
				publicKey: '',
				secretKey: '',
				dateApiKeys: 0,
			},
			favorites: [],
		};
		userProperties.push(item);
	}
	return userProperties;
};

// Создать нового пользователя
usersRouter.post('/createUser', async (req, res) => {
	try {
		//  проверяем существование такого логина в БД
		const result = await User.findByCredentials(
			req.body.inputEmail,
			null,
			'createUser'
		);
		// если логин пользователя не нашелся в БД и оказался уникальным
		if (!result) {
			const arrTickers = await Ticker.find();
			const arrPayTypes = await PayType.find();
			const arrExchanges = await Exchange.find();
			const arrCurrencies = await Currency.find();
			const arrOrderStatus = await OrderStatus.find();

			const objNewUser = {
				login: req.body.inputEmail,
				pass: req.body.inputPassword,
				properties: createNewUserProperties(arrExchanges),
			};

			const user = new User(objNewUser);
			const token = await user.generateAuthToken();

			await user.save();
			const data = {
				user: {
					id: user._id,
					login: user.login,
					lang: user.lang,
					theme: user.theme,
					advSell: user.advSell,
					status: user.status,
					subAccounts: user.subAccounts,
					properties: getUserProperties(user.properties),
				},
				token,
				message: 'User was created successful!',
				success: true,
				tickers: getArrayItemsCustomed(arrTickers, 'arrTickers'),
				payTypes: getArrayItemsCustomed(arrPayTypes, 'arrPayTypes'),
				exchanges: getArrayItemsCustomed(arrExchanges, 'arrExchanges'),
				currencies: getArrayItemsCustomed(arrCurrencies, 'arrCurrencies'),
				statuses: getArrayItemsCustomed(arrOrderStatus, 'arrOrderStatus'),
			};
			res.status(200).send(data);
		}
		// если такой логин уже существует
		else {
			const data = {
				message: 'This login is already busy!',
				success: false,
			};
			res.status(201).send(data);
		}
	} catch (error) {
		res.status(400).send({
			error,
			message: 'Creating new user is failed',
		});
	}
});

// Войти зарегистрированному пользователю
usersRouter.post('/enterUser', async (req, res) => {
	try {
		const { login, pass } = req.body;
		const user = await User.findByCredentials(login, pass, 'enterUser');
		if (user.error) {
			const data = {
				message: user.error,
				success: false,
			};
			res.status(201).send(data);
		} else {
			const token = await user.generateAuthToken();

			const arrTickers = await Ticker.find();
			const arrPayTypes = await PayType.find();
			const arrOrderStatus = await OrderStatus.find();
			const arrExchanges = await Exchange.find();
			const arrCurrencies = await Currency.find();

			const data = {
				user: {
					id: user._id,
					login: user.login,
					lang: user.lang,
					theme: user.theme,
					advSell: user.advSell,
					status: user.status,
					subAccounts: user.subAccounts,
					properties: getUserProperties(user.properties),
				},
				token,
				message: 'User was authorized successful!',
				success: true,
				tickers: getArrayItemsCustomed(arrTickers, 'arrTickers'),
				payTypes: getArrayItemsCustomed(arrPayTypes, 'arrPayTypes'),
				exchanges: getArrayItemsCustomed(arrExchanges, 'arrExchanges'),
				currencies: getArrayItemsCustomed(arrCurrencies, 'arrCurrencies'),
				statuses: getArrayItemsCustomed(arrOrderStatus, 'arrOrderStatus'),
			};
			res.status(200).send(data);
		}
	} catch (error) {
		res.status(400).send({
			error,
			message: 'Login is failed',
		});
	}
});

// обновление user
usersRouter.put('/updateUser', async (req, res) => {
	const user = await User.findOne({ _id: req.body.id });
	if (!user) {
		const data = { error, message: 'User not found!' };
		return res.status(404).json(data);
	}

	let message = 'User not updated!';

	const {
		fieldChangeable,
		lang,
		theme,
		advSell,
		status,
		subAccounts,
		inputOldPass,
		inputNewPass,
		exchangeId,
		exchange,
		exchangeUserId,
		userNickName,
		updateOrders,
		objExchange,
		requestHeader,
		apiKeys,
		payTypeList,
		favoriteUser,
	} = req.body;

	if (
		fieldChangeable === 'changePassword' &&
		inputOldPass &&
		inputNewPass
	) {
		const isPasswordMatch = await bcrypt.compare(inputOldPass, user.pass);
		if (isPasswordMatch) {
			user.pass = inputNewPass;
			message = 'Password was updated successful!';
		} else {
			message = 'Entered incorrect old Password';
		}
	} else if (fieldChangeable === 'changeLang' && lang) {
		user.lang = lang;
		message = 'Lang was updated successful!';
	} else if (fieldChangeable === 'changeTheme' && theme) {
		user.theme = theme;
		message = 'Theme was updated successful!';
	} else if (fieldChangeable === 'changeStatus' && status) {
		user.status = status;
		message = 'Status was updated successful!';
	} else if (fieldChangeable === 'subAccounts' && subAccounts) {
		user.subAccounts = subAccounts;
		message = 'subAccounts were updated successful!';
	} else if (fieldChangeable === 'advSell' && advSell) {
		user.advSell = advSell;
		message = 'AdvSell was updated successful!';
	} else if (fieldChangeable === 'addFavorite' && favoriteUser) {
		const properties = user.properties;
		const arrFavorites = getSingleUserProperty(
			'favorites',
			exchange,
			properties
		).slice();

		for (let i = 0; i < properties.length; i++) {
			if (properties[i].exchange === exchange) {
				arrFavorites.push(favoriteUser);
				properties[i].favorites = arrFavorites;
			}
		}
		user.properties = properties;
		message = 'Favorite User was added successful!';
	} else if (fieldChangeable === 'removeFavorite' && favoriteUser) {
		const properties = user.properties;
		const arrFavorites = getSingleUserProperty(
			'favorites',
			exchange,
			properties
		).slice();
		for (let i = 0; i < properties.length; i++) {
			for (let j = 0; j < arrFavorites.length; j++) {
				if (arrFavorites[j].userId === favoriteUser.userId) {
					arrFavorites.splice(j, 1); // вырезаем элемент
					properties[i].favorites = arrFavorites;
				}
			}
		}
		user.properties = properties;
		message = 'Favorite User was removed successful!';
	} else if (fieldChangeable === 'requestHeader' && requestHeader) {
		const userProps = user.properties.slice();
		if (exchange === 'Garantex') {
			const userPropsUpdated = await updateAuthToken_BZ_GX(
				exchange,
				userProps,
				user._id,
				requestHeader
			);
			user.properties = userPropsUpdated;
		} else {
			for (let i = 0; i < userProps.length; i++) {
				if (userProps[i].exchange === exchange) {
					userProps[i].requestHeader = requestHeader;
				}
			}
			user.properties = userProps;
		}
		message = `${exchange} requestHeader was updated successful!`;
	} else if (fieldChangeable === 'apiKeys' && apiKeys) {
		const properties = user.properties;
		for (let i = 0; i < properties.length; i++) {
			if (properties[i].exchange === exchange) {
				properties[i].apiKeys.publicKey = apiKeys.publicKey;
				properties[i].apiKeys.secretKey = apiKeys.secretKey;
				properties[i].apiKeys.dateApiKeys = apiKeys.dateApiKeys;
			}
		}
		user.properties = properties;
		message = `${exchange} apiKeys was updated successful!`;
	} else if (fieldChangeable === 'updateOrders') {
		const properties = user.properties;
		for (let i = 0; i < properties.length; i++) {
			if (properties[i].exchange === exchange) {
				properties[i].updateOrders = updateOrders;
			}
		}
		user.properties = properties;
		const onOff = updateOrders ? 'On' : 'Off';
		message = `${exchange} updateOrders is switched ${onOff} successful!`;
	} else if (fieldChangeable === 'updateUserPayTypes' && payTypeList) {
		const properties = user.properties;
		for (let i = 0; i < properties.length; i++) {
			if (properties[i].exchange === exchange) {
				properties[i].payTypeList = payTypeList;
			}
		}
		user.properties = properties;
		message = 'UserProfile was updated successful!';
	} else if (
		fieldChangeable === 'updateProfile' &&
		exchangeUserId &&
		userNickName
	) {
		const properties = user.properties;
		for (let i = 0; i < properties.length; i++) {
			if (properties[i].exchange === exchange) {
				properties[i].exchangeUserId = exchangeUserId;
				properties[i].userNickName = userNickName;
			}
		}
		user.properties = properties;
		message = 'UserProfile was updated successful!';
	} else if (fieldChangeable === 'newExchange' && objExchange) {
		// получение всех юзеров из БД
		const allUsers = await User.find();
		// если юзер`s есть в БД
		if (allUsers.length !== 0) {
			for (let i = 0; i < allUsers.length; i++) {
				// получение свойств конкретного юзера
				const properties = allUsers[i].properties.slice();
				// проверяем подключенность добавляемой биржи к свойствам юзера
				const isExistUserExchange = properties.filter((item) => {
					return item.exchange === objExchange.exchange.trim()
						? true
						: false;
				});
				// если подключена - isExistUserExchange.length > 0
				if (isExistUserExchange.length !== 0) {
					console.log(
						allUsers[i].login +
							' has already exchange: ' +
							objExchange.exchange.trim()
					);
					message = 'UserProfile was updated successful!';
				} else {
					// не подключена - добавляем в БД
					properties.push(objExchange);
					allUsers[i].properties = properties;
					// сохраняем в БД
					allUsers[i]
						.save()
						.then(() => {
							message = 'UserProfiles were updated successful!';
							console.log(
								allUsers[i].login +
									' exchange ' +
									objExchange.exchange.trim() +
									' added'
							);
						})
						.catch((error) => {
							console.log(error);
							message = 'Error user inserting';
						});
				}
			}
		} else message = 'allUsers.length equals 0';
	}

	user
		.save()
		.then(() => {
			return res.status(200).json({
				success: true,
				user: {
					id: user._id,
					login: user.login,
					lang: user.lang,
					theme: user.theme,
					advSell: user.advSell,
					status: user.status,
					properties: getUserProperties(user.properties),
				},
				message,
				// fieldChangeable
			});
		})
		.catch((error) => {
			console.log(error);
			return res.status(400).json({
				success: false,
				message: 'Error user updating',
			});
		});
});

// Восстановление пароля пользователя
usersRouter.post('/reset-pass', async (req, res) => {
	const { inputLogin } = req.body;
	//console.log('string_185', inputLogin)

	User.findOne({ login: inputLogin }, async (error, user) => {
		if (error) {
			const data = { error, message: 'User not found!' };
			return res.status(404).json(data);
		}
		if (!user) {
			const data = {
				error,
				message: `Your email ${inputLogin} not registered!`,
			};
			return res.status(201).json(data);
		} else {
			user.pass = await User.getRundomPass();
			await User.sendNewPassword(user);

			user
				.save()
				.then(() => {
					const data = {
						success: true,
						//data: user,
						message: `New Password sent on ${inputLogin}, Check spam`,
					};
					return res.status(201).json(data);
				})
				.catch((error) => {
					const data = { error, message: 'Email not found!' };
					console.log(error);
					return res.status(400).json(data);
				});
		}
	});
});

// Выход пользователя из приложения
usersRouter.route('/logout').get(auth, async (req, res) => {
	// Log user out of the application
	try {
		req.user.tokens = req.user.tokens.filter((token) => {
			return token.token != req.token;
		});
		await req.user.save();
		const data = {
			user: req.user,
			message: 'User was logout successful!',
			success: true,
		};
		res.status(200).send(data);
	} catch (error) {
		res.status(500).send({
			error,
			message: 'Logout is failed',
		});
	}
});

// Выход пользователя из всех устройств
usersRouter.route('/logoutall').get(auth, async (req, res) => {
	// Log user out of all devices
	try {
		req.user.tokens.splice(0, req.user.tokens.length);
		await req.user.save();
		const data = {
			user: req.user,
			message: 'User was logoutAll successful!',
			success: true,
		};
		res.status(200).send(data);
	} catch (error) {
		res.status(500).send({
			error,
			message: 'LogoutAll is failed',
		});
	}
});
