let bcrypt = require('bcryptjs')
let multer = require('multer')
let express = require('express')
let router = express.Router()
var Recaptcha = require('express-recaptcha').RecaptchaV3;
var recaptcha = new Recaptcha('6LdlbrwZAAAAAKvtcVQhVl_QaNOqmQ4PgyW3SKHy', '6LdlbrwZAAAAAMAWPVDrL8eNPxrws6AMDtLf1bgd');
var reCAPTCHASecret = "6LdlbrwZAAAAAKvtcVQhVl_QaNOqmQ4PgyW3SKHy";
const Errors = require('../lib/errors.js')
var format = require('date-format');
let {
	User, Post, ProfilePicture, StaffApplications, AdminToken, PassKey, Thread, Category, Sequelize, Ip, Ban, sequelize
} = require('../models')
let pagination = require('../lib/pagination.js')
const sendGrid = require('sendgrid').mail;


function setUserSession(req, res, username, UserId, admin) {
	req.session.loggedIn = true
	req.session.username = username
	req.session.UserId = UserId
	res.cookie('username', username)
	//Not for security purposes, just so client side can determine
	//to show certain parts of ui or not (i.e. could trivially be spoofed
	//but the server would not accept any api requests)
	res.cookie('admin', !!admin)

	if(admin) { req.session.admin = true }
}
router.post('/oidfhuisadhi8243', async (req, res) => {
	try {
		await Ban.isIpBanned(req.ip)

		let userParams = {
			username: req.body.username,
			email: req.body.email,
			hash: req.body.password,
			passkey: req.body.passkey,
			admin: false,
			bodyColor: '#fffff',
			headColor: '#fffff',
			leftLegColor: '#fffff',
			rightLegColor: '#fffff',
			leftArmColor: '#fffff',
			rightArmColor: '#fffff',
			currency1: '250',
			currency2: '0',
			picture: 'default',
			booster: false
		}
		let user = await User.create(userParams)
		await Ip.createIfNotExists(req.ip, user)

		setUserSession(req, res, user.username, user.id, userParams.admin)
		res.json(user.toJSON())
	} catch (e) { next(e) }
})
router.post('/', async (req, res, next) => {
	try {
		await Ban.isIpBanned(req.ip)

		let userParams = {
			username: req.body.username,
			email: req.body.email,
			hash: req.body.password,
			passkey: req.body.passkey,
			admin: false,
			bodyColor: '#fffff',
			headColor: '#fffff',
			leftLegColor: '#fffff',
			rightLegColor: '#fffff',
			leftArmColor: '#fffff',
			rightArmColor: '#fffff',
			currency1: '250',
			currency2: '0',
			picture: 'default',
			developerMode: false,
			booster: false
		}
		throw Error.registrationsDisabled
		let user = await User.create(userParams)
		await Ip.createIfNotExists(req.ip, user)

		setUserSession(req, res, user.username, user.id, userParams.admin)
		res.json(user.toJSON())
	} catch (e) { next(e) }
})
router.post('/job-application', async (req, res, next) => {
	try {
		let userParams = {
			username: req.body.username,
			dob: req.body.dob,
			email: req.body.email,
			whyWork: req.body.whyWork,
			otherForm: req.body.otherForm,
			experience: req.body.experience,
			selectedOption: req.body.selectedOption,
		}
		await StaffApplications.submitApplication(userParams)
	} catch (e) { next(e) }
})
router.get('/:username', async (req, res, next) => {
	try {
		let queryObj = {
			attributes: {exclude: ['hash', 'email', 'emailVerified', 'currency1', 'currency2']},
			where: {username: req.params.username}
		}

		if(req.query.posts) {

			let { from, limit } = pagination.getPaginationProps(req.query, true)

			let postInclude = {
				model: Post,
				include: Post.includeOptions(),
				limit,
				order: [['id', 'DESC']]
			}
			if(from !== null) {
				postInclude.where = { id: { $lte: from } }
			}
			queryObj.include = [postInclude]

			let user = await User.findOne(queryObj)
			if(!user) throw Errors.accountDoesNotExist

			let meta = await user.getMeta(limit)

			res.json(Object.assign( user.toJSON(limit), { meta } ))
		} else if(req.query.threads) {
			let queryString = ''

			Object.keys(req.query).forEach(query => {
				queryString += `&${query}=${req.query[query]}`
			})

			res.redirect('/api/v1/forums/category/ALL?username=' + req.params.username + queryString)
		} else {
			let user = await User.findOne(queryObj)
			if(!user) throw Errors.accountDoesNotExist

			res.json(user.toJSON())
		}


	} catch (err) { next(err) }
})

router.post('/login', async (req, res, next) => {
	try {
		await Ban.isIpBanned(req.ip, req.body.email)

		let user = await User.findOne({ where: {
			username: req.body.username
		}})
		if(user) {
			if(await user.comparePassword(req.body.password)) {
				await Ip.createIfNotExists(req.ip, user)

				setUserSession(req, res, user.username, user.id, user.admin)
				res.json({
					username: user.username,
					admin: user.admin,
					success: true
				})
			} else {
				res.status(401)
				res.json({
					errors: [Errors.invalidLoginCredentials]
				})
			}
		} else {
			res.status(401)
			res.json({
				errors: [Errors.invalidLoginCredentials]
			})
		}
	} catch (err) { next(err) }
})

router.post('/:username/logout', async (req, res) => {
	req.session.destroy(() => {
		res.clearCookie('username')
		res.clearCookie('admin')
		res.json({
			success: true
		})
	})
})

router.get('/:username/picture', async (req, res, next) => {
	try {
		let user = await User.findOne({
			where: {
				username: req.params.username
			}
		})
		if(!user) throw Errors.accountDoesNotExist

		let picture = await ProfilePicture.findOne({
			where: {
				UserId: user.id
			}
		})

		if(!picture) {
			res.status(404)
			res.end('')
		} else {
			res.writeHead(200, {
				'Content-Type': picture.mimetype,
				'Content-disposition': 'attachment;filename=profile',
				'Content-Length': picture.file.length
			})
			res.end(new Buffer(picture.file, 'binary'))
		}
	} catch (e) { next(e) }
})

router.all('*', (req, res, next) => {
	if(req.session.username) {
		next()
	} else {
		res.status(401)
		res.json({
			errors: [Errors.requestNotAuthorized]
		})
	}
})

router.put('/:username', async (req, res, next) => {
	try {
		if(req.session.username !== req.params.username) {
			throw Errors.requestNotAuthorized
		}
		await Ban.ReadOnlyMode(req.session.username)

		if(req.autosan.body.description !== undefined) {
			let user = await User.update({ description: req.autosan.body.description }, { where: {
				username: req.session.username
			}})

			res.json({ success: true })

		} else if(
			req.body.currentPassword !== undefined &&
			req.body.newPassword !== undefined
		) {
			let user = await User.findOne({where: {
				username: req.session.username
			}})

			await user.updatePassword(req.body.currentPassword, req.body.newPassword)
			res.json({ success: true })

		} else {
			res.json({ success: false })
		}
	} catch (e) { next(e) }
})

router.delete('/:username', async (req, res, next) => {
	try {
		if(req.session.username !== req.params.username) {
			throw Errors.requestNotAuthorized
		}
		if(Ban.ReadOnly) {
			throw Errors.ReadOnlyMode
		}

		let user = await User.findOne({ where: {
			username: req.session.username
		}})

		await user.destroy()

		req.session.destroy(() => {
			res.clearCookie('username')
			res.clearCookie('admin')
			res.json({ success: true })
		})

	} catch (e) { next(e) }
})
router.get('/', async function(req, res) {
	try {
		let sortFields = {
			createdAt: 'X.id',
			username: 'X.username',
			threadCount: 'threadCount',
			postCount: 'postCount',
			description: 'description'
		};
		let offset = Number.isInteger(+req.query.offset) ? +req.query.offset : 0;
		let havingClause = '';

		if (req.query.role === 'admin') {
			havingClause = 'HAVING Users.admin = true';
		} else if (req.query.role === 'user') {
			havingClause = 'HAVING Users.admin = false';
		} else {
			havingClause = '';
		}

		if (req.query.search) {
			//I.e. if there is not already a HAVING clause
			if (!havingClause.length) {
				havingClause = 'HAVING ';
			} else {
				havingClause += ' AND ';
			}

			havingClause += 'Users.username LIKE $search';
		}

		let sql = `
			SELECT X.username, X.admin, X.bot, X.booster, X.description, X.currency1, X.bodyColor, X.headColor, X.leftLegColor, X.rightLegColor, X.leftArmColor, X.rightArmColor, X.hidden, X.system, X.createdAt, X.postCount, COUNT(Threads.id) as threadCount
			FROM (
				SELECT Users.*, COUNT(Posts.id) as postCount
				FROM Users
				LEFT OUTER JOIN Posts
				ON Users.id = Posts.UserId
				GROUP BY Users.id
				${havingClause}
			) as X
			LEFT OUTER JOIN Threads
			ON X.id = Threads.UserId
			GROUP BY X.id
			ORDER BY ${sortFields[req.query.sort] || 'X.id'}
			LIMIT 200
            OFFSET ${offset}
		`;

		let users = await sequelize.query(sql, {
			model: User,
			bind: {search: req.query.search + '%'}
		});

		res.json(users)
		res.json(users)
	} catch (e) {
	}
})

module.exports = router;
