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

const Errors = require('../lib/errors')
let pagination = require('../lib/pagination')
let { Category, Post, Thread, User, Sequelize } = require('../models')

router.get('/', auth, async(req, res) => {
	try {
		let queryObj = {
			attributes: {exclude: ['hash', 'currency2', 'emailToken', 'passwordResetToken', 'deleteCode', 'deleteEnabled', 'jwtOffset']},
			where: {username: req.userData.username}
		}
		let user = await User.findOne(queryObj)
		let categories = await Category.findAll()

		res.json(categories)
	} catch (e) {
		res.status(500)
		res.json({
			errors: [Errors.unknown]
		})
	}

})


router.get('/:category', async(req, res, next) => {
	try {
		let threads, threadsLatestPost, resThreads, user
		let { from, limit } = pagination.getPaginationProps(req.query, true)

		if(req.query.username) {
			user = await User.findOne({ where: { username: req.query.username }})
		}

		function threadInclude(order) {
			let options = {
				model: Thread,
				order: [['id', 'DESC']],
				limit,
				where: {},
				include: [
					Category,
					{ model: User, attributes: ['username', 'createdAt', 'id', 'color', 'picture', 'locked'] },
					{
						model: Post, limit: 1, order: [['id', order]], include:
						[{ model: User, attributes: ['username', 'id'] }]
					}
				]
			}

			if(user) {
				options.where.userId = user.id
			}

			if(from !== null) {
				options.where.id = { $lte: from }
			}

			return [options]
		}

		if(req.params.category === 'ALL') {
			threads = await Thread.findAll( threadInclude('ASC')[0] )
			threadsLatestPost = await Thread.findAll( threadInclude('DESC')[0] )
		} else {
			threads = await Category.findOne({
				where: { value: req.params.category },
				include: threadInclude('ASC')
			})

			threadsLatestPost = await Category.findOne({
				where: { value: req.params.category },
				include: threadInclude('DESC')
			})
		}
		if(!threads) throw Errors.invalidParameter('ID','Category doesn\'t exist')
		if(Array.isArray(threads)) {
			resThreads = {
				name: 'All',
				value: 'ALL',
				Threads: threads,
				meta: {}
			}

			threadsLatestPost = { Threads: threadsLatestPost }
		} else {
			resThreads = threads.toJSON()
			resThreads.meta = {}
		}
		threadsLatestPost.Threads.forEach((thread, i) => {
			resThreads.Threads[i].Posts.push()
		})


		let nextId = await pagination.getNextIdDesc(Thread, user ? { userId: user.id } : {}, resThreads.Threads)

		if(nextId) {
			resThreads.meta.nextURL =
				`/api/v1/forums/category/${req.params.category}?&limit=${limit}&from=${nextId - 1}`

			if(user) {
				resThreads.meta.nextURL += '&username=' + user.username
			}

			resThreads.meta.nextThreadsCount = await pagination.getNextCount(
				Thread, resThreads.Threads, limit,
				user ? { userId: user.id } : {},
				true
			)
		} else {
			resThreads.meta.nextURL = null
			resThreads.meta.nextThreadsCount = 0
		}

		res.json(resThreads)

	} 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.post('/', auth, async(req, res, next) => {
if (req.body.name.toLowerCase() == "all" || req.body.name.toLowerCase == "other") {
                res.status(400)
		res.json({
		        errors: [Errors.categoryAlreadyExists]
		});
                return;
}
	try {
		let category = await Category.create({
			name: req.body.name,
			color: req.body.color,
			locked: false
		})

		res.json(category.toJSON())
	} catch (e) {
		if(e.name === 'SequelizeUniqueConstraintError') {
			res.status(400)
			res.json({
				errors: [Errors.categoryAlreadyExists]
			})
		} else {
			next(e)
		}
	}
})

router.put('/:category_id', auth, async(req, res, next) => {
	try {
		let id = req.params.category_id
		let obj = {}
		if(req.body.color) obj.color = req.body.color
		if(req.body.name) obj.name = req.body.name
		if(req.body.locked) obj.locked = req.body.locked

		let affectedRows = await Category.update(obj, {
			where: { id }
		})


		if(!affectedRows[0]) {
			throw Errors.sequelizeValidation(Sequelize, {
				error: 'Are you sure that\'s a real category? (INVALID_CATEGORY_ID)',
				value: id
			})
		} else {
			let ret = await Category.findByPk(id)
			res.json(ret.toJSON())
		}
	} catch(e) { next(e) }
})

router.delete('/:id', auth, async(req, res, next) => {
	try {
		let category = await Category.findByPk(req.params.id)
		if(!category) throw Errors.sequelizeValidation(Sequelize, {
			error: 'category id does not exist',
			value: req.params.id
		})

		let otherCategory = await Category.findOrCreate({
			where: { name: 'Other' },
			defaults: { color: '#9a9a9a' }
		})

		let up = await Thread.update({ CategoryId: otherCategory[0].id }, {
			where: { CategoryId: req.params.id }
		})

		await category.destroy()

		res.json({
			success: true,
			otherCategoryCreated: otherCategory[1] ? otherCategory[0] : null
		})
	} catch (e) { next(e) }
})

module.exports = router
