const UserModel = require('../model/user');
const ChatModel = require('../model/chat');
const MessageModel = require('../model/message');
const ContactModel = require('../model/contact');
const fs = require('fs').promises;
const path = require('path');
const jwt = require('jsonwebtoken');
const createFolderIsExist = require('../helpers/create-directory');
require('dotenv').config();
const client = require('../helpers/twilio');
const phoneToken = require('generate-sms-verification-code');
const SECRET_KEY = process.env.JWT_SECRET;
const DIR_FILES = process.env.DIR_FILES;

const createNewUser = async (req, res, next) => {
	try {
		const code = phoneToken(4, { type: 'number' });
		const color = `#${Math.floor(Math.random() * 16777215).toString(16)}`;
		const { number, country } = req.body;
		const isExist = await UserModel.findByNumber(number);
		if (isExist) {
			await UserModel.updateUser(isExist._id, { code });
		} else {
			await UserModel.createUser({ number, country, color, code });
		}
		client.messages.create({
			body: `${code}`,
			to: `${number}`,
			from: '+18305875860',
		});
		return res.status(201).json({
			status: 'success',
			code: 201,
			data: String(code),
		});
	} catch (e) {
		next(e);
	}
};

const logIn = async (req, res, next) => {
	try {
		const { number, code } = req.body;
		const user = await UserModel.findByNumber(number);
		if (!user || user.code !== code)
			return res.status(401).json({
				status: 'error',
				code: 401,
				data: 'UNAUTHORIZED',
				message: 'Invalid credentials',
			});
		const id = user._id;
		const payload = { id };
		const token = jwt.sign(payload, SECRET_KEY, { expiresIn: '24h' });
		let registered = true;
		if (!user.name || !user.lastName || !user.avatarUrl) registered = false;
		const online = true;
		await UserModel.updateUser(id, { token, code: '', online });
		await ChatModel.updateCompanionsChat(id, { online });
		return res.status(200).json({
			status: 'success',
			code: 200,
			data: {
				token,
				registered,
			},
		});
	} catch (e) {
		next(e);
	}
};

const logOut = async (req, res, next) => {
	try {
		const id = req.user.id;
		const user = await UserModel.findById(id);
		const online = new Date();
		if (!user)
			return res.status(401).json({
				status: 'error',
				code: 401,
				data: 'UNAUTHORIZED',
				message: 'Invalid credentials',
			});
		await UserModel.updateUser(id, { token: null, online });
		await ChatModel.updateCompanionsChat(id, { online });
		return res.status(204).json({});
	} catch (e) {
		next(e);
	}
};

const online = async (req, res, next) => {
	try {
		const id = req.user.id;
		const user = await UserModel.findById(id);
		const online = new Date();
		if (!user)
			return res.status(401).json({
				status: 'error',
				code: 401,
				data: 'UNAUTHORIZED',
				message: 'Invalid credentials',
			});
		await ChatModel.updateCompanionsChat(id, { online });
		await UserModel.updateUser(id, { online });
		return res.status(204).json({});
	} catch (e) {
		next(e);
	}
};

const getCurrent = async (req, res, next) => {
	try {
		const user = req.user;
		if (!user)
			return res.status(401).json({
				status: 'error',
				code: 401,
				data: 'UNAUTHORIZED',
				message: 'Invalid credentials',
			});
		const id = req.user.id;
		const online = true;
		await UserModel.updateUser(id, { online });
		await ChatModel.updateCompanionsChat(id, { online });
		const updatedUser = await UserModel.findById(id);
		return res.status(200).json({
			status: 'success',
			code: 200,
			data: updatedUser,
		});
	} catch (e) {
		next(e);
	}
};

const updateCredentials = async (req, res, next) => {
	try {
		const { id } = req.user;
		const { name, lastName, originalName, originalLastName } = req.body;
		await UserModel.updateUser(id, req.body);
		await ChatModel.updateCompanionsChat(id, {
			originalName,
			originalLastName,
		});
		await MessageModel.updateOwnerMessages(
			{ companionIdFlow: { $eq: id }, owner: id },
			{ name, lastName }
		);
		return res.status(200).json({
			data: {},
		});
	} catch (e) {
		next(e);
	}
};

const updateUser = async (req, res, next) => {
	try {
		const { id } = req.user;
		await UserModel.updateUser(id, req.body);
		return res.status(200).json({
			data: {},
		});
	} catch (e) {
		next(e);
	}
};

const removeAvatar = async (req, res, next) => {
	try {
		const { id, avatarsArr, number } = req.user;
		const index = req.params.index;
		const toDelete = avatarsArr[index];
		const filteredAvatars = [...avatarsArr].filter(
			({ avatarUrl }) => avatarUrl !== toDelete.avatarUrl
		);
		await fs.unlink(path.join(DIR_FILES, toDelete.avatarUrl));
		const avatarUrl = filteredAvatars[0].avatarUrl;
		await UserModel.updateUser(id, { avatarUrl, avatarsArr: filteredAvatars });
		await ChatModel.updateCompanionsChat(id, {
			avatarUrl,
			avatarsArr: filteredAvatars,
		});
		await ContactModel.updateCompanionsContact(number, { avatarUrl });
		await MessageModel.updateOwnerMessages(
			{ companionIdFlow: { $eq: id } },
			{ avatarUrl }
		);
		return res.status(200).json({
			data: {},
		});
	} catch (e) {
		next(e);
	}
};

const updateAvatar = async (req, res, next) => {
	try {
		const userId = req.user.id;
		const userNumber = req.user.number;
		const token = req.user.token;
		const pathToFile = req.file.path;
		const originalName = req.file.originalname;
		const newNameAvatar = `${Math.round(Date.now() / 1000)}${originalName}`;
		await createFolderIsExist(path.join(DIR_FILES, userId));
		await fs.rename(pathToFile, path.join(DIR_FILES, userId, newNameAvatar));
		const avatarUrl = path.normalize(path.join(userId, newNameAvatar));
		const avatarsArr = [
			{ avatarUrl, updatedAt: new Date() },
			...req.user.avatarsArr,
		];
		await UserModel.updateUser(userId, { avatarUrl, avatarsArr });
		await ChatModel.updateCompanionsChat(userId, { avatarUrl, avatarsArr });
		await ContactModel.updateCompanionsContact(userNumber, { avatarUrl });
		await MessageModel.updateOwnerMessages(
			{ companionIdFlow: { $eq: userId } },
			{ avatarUrl }
		);
		return res.status(200).json({
			status: 'success',
			code: 200,
			data: {
				token,
			},
		});
	} catch (e) {
		next(e);
	}
};

module.exports = {
	createNewUser,
	logIn,
	logOut,
	online,
	getCurrent,
	updateCredentials,
	updateUser,
	removeAvatar,
	updateAvatar,
};
