import { Schema, model } from 'mongoose';
import validator from 'validator';
import bcrypt from 'bcryptjs';
import jwt from 'jsonwebtoken';
import nodemailer from 'nodemailer';

import {
	JWT_KEY,
	SITE_NAME,
	SERVICE_HOST,
	SERVICE_USER,
	SERVICE_PASS,
} from '../constants';

const userSchema = new Schema(
	{
		login: {
			type: String,
			required: true,
			unique: true,
			minlength: 3,
			trim: true,
			lowercase: true,
			validate: (value) => {
				if (!validator.isEmail(value)) {
					throw new Error({ error: 'Invalid Email address' });
				}
			},
		},
		pass: {
			type: String,
			required: true,
			trim: true,
			minlength: 3,
		},
		lang: { type: String, default: 'en' },
		theme: { type: String, default: 'night' },
		advSell: { type: Number, default: 0 },
		id_tgbot: { type: String, default: '' },
		status: { type: String, default: 'user' },
		subAccounts: [
			{
				subAccount: { type: String }, // "T01"
				remarkTooltip: { type: String }, // "KAV"
				payTypeId: { type: String }, // id способа оплаты
			},
		],
		properties: [
			{
				exchange: { type: String, default: '' }, // Binance
				exchangeId: { type: String, default: '' },
				exchangeUserId: { type: String, default: '' }, // "old binanceId",
				// количество текущих неоплаченных ордеров
				orderStatuses: {
					unpaid: { type: Number, default: 0 },
					paid: { type: Number, default: 0 },
					appeal: { type: Number, default: 0 },
					// completed: { type: Number, default: 0 },
					reject: { type: Number, default: 0 },
				},
				userNickName: { type: String, default: '' }, // ""
				updateOrders: { type: Boolean, default: false },
				soundAlert: { type: String, default: 'Sound/newOrder.wav' },
				requestHeader: {
					//------- Binance -------
					cookie: { type: String, default: '' },
					csrftoken: { type: String, default: '' },
					deviceInfo: { type: String, default: '' },
					userAgent: { type: String, default: '' },
					//------- Huobi --------
					token: { type: String, default: '' },
					fingerprint: { type: String },
					// userAgent: {type: String, default: ""},
					traceId: { type: String, default: '' },
					//------- Okex ---------
					authorization: { type: String, default: '' },
					// cookie: {type: String, default: ""},
					// userAgent: {type: String, default: ""},
					devId: { type: String, default: '' },
					//------- Bybit ---------
					usertoken: { type: String, default: '' },
					//------- BingX ---------
					appVersion: { type: String, default: '' },
					// authorization: { type: String, default: '' },
					deviceId: { type: String, default: '' },
					sign: { type: String, default: '' },
					timestamp: { type: Number, default: 0 },
					// traceId: { type: String, default: '' },
					// userAgent: { type: String, default: '' },
					additionals: [
						{
							appVersion: { type: String, default: '' },
							authorization: { type: String, default: '' },
							deviceId: { type: String, default: '' },
							sign: { type: String, default: '' },
							timestamp: { type: Number, default: 0 },
							traceId: { type: String, default: '' },
							userAgent: { type: String, default: '' },
							typeRequest: { type: String, default: '' },
						},
					],
				},
				payTypeList: [{ type: String }],
				apiKeys: {
					publicKey: { type: String, default: '', trim: true },
					secretKey: { type: String, default: '', trim: true },
					dateApiKeys: { type: Number, default: 0 },
				},
				favorites: [
					{
						nickName: { type: String },
						userId: { type: String },
					},
				],
			},
		],
		tokens: [
			{
				token: { type: String, required: true },
			},
		],
	},
	{
		timestamps: true,
	}
);

// Hash the pass before saving the user model
// Хешируем пароль перед сохранением пользовательской модели
userSchema.pre('save', async function(next) {
	const user = this;
	if (user.isModified('pass')) {
		user.pass = await bcrypt.hash(user.pass, 8);
	}
	next();
});

// Generate an auth token for the user
// Генерируем авторизационный токен для пользователя
userSchema.methods.generateAuthToken = async function() {
	const user = this;
	const token = jwt.sign({ _id: user._id }, JWT_KEY);
	user.tokens = user.tokens.concat({ token });
	await user.save();
	return token;
};

// отправляем новый пароль на email user'a
userSchema.statics.sendNewPassword = async (user) => {
	//console.log('string_64', user)
	let mailOptions = {
		from: SERVICE_USER,
		to: user.login,
		subject: 'Reset your account password',
		html: `<h4><b>Resetting Password on ${SITE_NAME}</b></h4>
		<p>your temporary password - ${user.pass}</p>
		<p>--${SITE_NAME} Team</p>`,
	};

	var transporter = nodemailer.createTransport({
		host: SERVICE_HOST,
		port: 465,
		secure: true, // true for 465, false for other ports
		auth: {
			user: SERVICE_USER,
			pass: SERVICE_PASS,
		},
	});

	await transporter.sendMail(mailOptions, function(error, info) {
		if (error) console.log(error);
		else console.log('Email sent: ' + info.response);
	});
};

// генератор случайного пароля
userSchema.statics.getRundomPass = () => {
	var length = 8,
		charset =
			'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789',
		retVal = '';
	for (var i = 0, n = charset.length; i < length; ++i) {
		retVal += charset.charAt(Math.floor(Math.random() * n));
	}
	return retVal;
};

// Search for a user by login and pass.
// Поиск пользователя по электронной почте и паролю.
userSchema.statics.findByCredentials = async (login, pass, nameRoute) => {
	let user = {};
	const result = await User.findOne({ login });
	// проверка при входе пользователя
	if (nameRoute === 'enterUser') {
		// если пользователь по логину не нашелся
		if (!result) {
			user = { error: 'Invalid login credentials' };
		} else {
			user = result;
			const isPasswordMatch = await bcrypt.compare(pass, user.pass);
			if (!isPasswordMatch) {
				user = { error: 'Invalid password credentials' };
			}
		}
	}
	// проверка при создании пользователя
	else if (nameRoute === 'createUser') {
		// если логин пользователя не нашелся в БД и оказался уникальным
		if (!result) {
			user = false;
		}
		// если такой логин уже существует
		else {
			user = true;
		}
	}
	return user;
};

export const User = model('User', userSchema);
