let express = require('express')
let router = express.Router()
const auth = require('../lib/auth')

const Errors = require('../lib/errors')
let { User, Thread, Post, Notification, Ban, Sequelize, sequelize } = require('../models')
const rateLimit = require("express-rate-limit");
const postLimiter = rateLimit({
	windowMs: 60000,
	max: 10,
	message: "{\"errors\":[{\"name\":\"rateLimit\",\"message\":\"You may only make 10 requests to this endpoint per minute.\",\"status\":429}]}"
});

const likeLimiter = rateLimit({
	windowMs: 60000,
	max: 25,
	message: "{\"errors\":[{\"name\":\"rateLimit\",\"message\":\"You may only make 25 requests to this endpoint per minute.\",\"status\":429}]}"
});

router.get('/:post_id', async(req, res, next) => {
	try {
		let post = await Post.findByPk(req.params.post_id, { include: Post.includeOptions() })
		if(!post) throw Errors.sequelizeValidation(Sequelize, {
			error: 'post does not exist',
			path: 'id'
		})

		res.json(post.toJSON())
	} catch (e) { next(e) }
})

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


router.put('/:post_id/like', likeLimiter, auth, async(req, res, next) => {
	try {
		let post = await Post.findByPk(req.params.post_id)
		let user = await User.findOne({ where: { username: req.userData.username }})

		if(!post) throw Errors.invalidParameter('id', 'post does not exist')
		if(post.UserId === user.id) throw Errors.cannotLikeOwnPost

		await post.addLikes(user)

		res.json({ success: true })

	} catch (e) { next(e) }
})

router.delete('/:post_id/like', likeLimiter, auth, async(req, res, next) => {
	try {
		let post = await Post.findByPk(req.params.post_id)
		let user = await User.findOne({ where: { username: req.userData.username }})

		if(!post) throw Errors.invalidParameter('id', 'post does not exist')

		await post.removeLikes(user)

		res.json({ success: true })

	} catch (e) { next(e) }
})

router.post('/', postLimiter, auth, async(req, res, next) => {
	let thread, replyingToPost, post, uniqueMentions = []
	let queryObj = {
		attributes: {include: ['emailVerified']},
		where: {username: req.userData.username}
	}
	let user = await User.findOne(queryObj)
	try {
		//Will throw an error if banned
		await Ban.ReadOnlyMode(req.userData.UserId)

		if(req.body.mentions) {
			uniqueMentions = Notification.filterMentions(req.body.mentions)
		}

		if(!user.emailVerified) {
			throw Errors.verifyEmail
		}

		thread = await Thread.findOne({ where: {
			id: req.body.threadId
		}})
		user = await User.findOne({ where: {
			username: req.userData.username
		}})

		if(thread.locked) throw Errors.threadLocked

		if(req.body.replyingToId) {
			replyingToPost = await Post.getReplyingToPost(
				req.body.replyingToId, thread
			)

			post = await Post.create({ content: req.body.content, postNumber: thread.postsCount })

			await post.setReplyingTo(replyingToPost)
			await replyingToPost.addReplies(post)

			let replyNotification = await Notification.createPostNotification({
				usernameTo: replyingToPost.User.username,
				userFrom: user,
				type: 'reply',
				post: post
			})
			await replyNotification.emitNotificationMessage(
				req.app.get('io-users'),
				req.app.get('io')
			)
		} else {
			post = await Post.create({ content: req.body.content, postNumber: thread.postsCount })
		}

		await post.setUser(user)
		await post.setThread(thread)

		await thread.increment('postsCount')

		if(uniqueMentions.length) {
			let ioUsers = req.app.get('io-users')
			let io = req.app.get('io')

			for(const mention of uniqueMentions) {
				let mentionNotification = await Notification.createPostNotification({
					usernameTo: mention,
					userFrom: user,
					type: 'mention',
					post
				})

				if(mentionNotification) {
					await mentionNotification.emitNotificationMessage(ioUsers, io)
				}
			}
		}

		res.json(await post.reload({
			include: Post.includeOptions()
		}))

		req.app.get('io').to('thread/' + thread.id).emit('new post', {
			postNumber: thread.postsCount,
			content: post.content,
			username: user.username
		})

	} catch (e) { next(e) }
})

router.all('*', auth, async(req, res, next) => {
	let user = await User.findOne({ where: {
			username: req.userData.username
		}})
	if(!user) throw Errors.requestNotAuthorized
	if(req.userData.admin && user.admin) {
		next()
	} else {
		res.status(401)
		res.json({
			errors: [Errors.sessionAdminProtection]
		})
	}
})

router.delete('/:post_id', auth, async(req, res, next) => {
	try {
		if(!req.userData.admin){
			res.status(401)
			res.json({errors: [Errors.requestNotAuthorized]})
		}
		let post = await Post.findByPk(req.params.post_id)
		if(!post) throw Errors.sequelizeValidation(Sequelize, {
			error: 'post does not exist',
			path: 'id'
		})

		await post.update({ content: '[This post has been removed by an administrator]', removed: true })

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

module.exports = router
