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

let { Sequelize, Log, userWall, Thread, User, Category } = require('../models')

const Errors = require('../lib/errors')
const now = new Date()
const lastWeek = new Date(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate() - 6)

function processLogsForLineChart (logs) {
	let normalizedDateLogs = logs.map(log => {
		let date = new Date(log.createdAt)
		date.setHours(0, 0, 0)
		return { createdAt: date }
	})

	let pageViewsObj = normalizedDateLogs.reduce((obj, log) => {
		if(!obj[log.createdAt]) {
			obj[log.createdAt] = { date: log.createdAt, pageViews: 1 }
		} else {
			obj[log.createdAt].pageViews++
		}

		return obj
	}, {})

	for(let i = 0; i < 7; i++) {
		let date = new Date(lastWeek)
		date.setUTCDate(date.getUTCDate() + i)

		if(!pageViewsObj[date]) {
			pageViewsObj[date] = {
				date,
				pageViews: 0
			}
		}
	}

	let pageViewsArr = Object.keys(pageViewsObj).map(date => {
		return pageViewsObj[date]
	})

	let pageViewsSorted = pageViewsArr.sort((a, b) => {
		if(a.date < b.date) {
			return -1
		} else if(a.date > b.date) {
			return 1
		} else {
			return 0
		}
	})

	return pageViewsSorted
}

router.post('/', auth, async(req, res, next) => {
	try {
		let thread, user
		if(req.body.route === 'thread') {
			thread = await Thread.findByPk(req.body.resourceId)

			if(!thread) throw Errors.sequelizeValidation(Sequelize, {
				error: 'thread does not exist',
				value: req.body.resourceId
			})
		} else if(
			req.body.route === 'userPosts' ||
			req.body.route === 'userThreads' ||
			req.body.route === 'userMarketplace' ||
			req.body.route === 'userWall'
		) {
			user = await User.findByPk(req.body.resourceId)

			if(!user) throw Errors.sequelizeValidation(Sequelize, {
				error: 'User does not exist, or feature isn\'t implemented.',
				value: req.body.resourceId
			})
		} else if(
			(req.body.route === 'settingsGeneral' ||
			req.body.route === 'settingsAccount') &&
			!req.userData.loggedIn
		) {
			throw Errors.requestNotAuthorized
		}

		let log = await Log.create({
			route: req.body.route
		})

		if(thread) await log.setThread(thread)
		if(user) await log.setUser(user)
		if(req.userData.username) {
			let sessionUser = await User.findOne({
				where: { username: req.userData.username }
			})
			await log.setSessionUser(sessionUser)
		}

		res.json(log.toJSON())

	} 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.get('/top-threads', auth, async(req, res, next) => {
	try {
		let logs = await Log.findAll({
			where: {
				createdAt: {
					$gt: new Date(Date.now() - 1000*60*60*24)
				},
				route: 'thread'
			},
			include: [Thread]
		})

		//Sum each log for a thread
		let pageViewsObj = logs.reduce((obj, log) => {
			//E.g. if thread deleted
			if(!log.Thread) return obj;

			if(!obj[log.Thread.id]) {
				obj[log.Thread.id] = { Thread: log.Thread, pageViews: 1 }
			} else {
				obj[log.Thread.id].pageViews++
			}

			return obj
		}, {})

		//Transform to array
		let pageViewsArr = Object.keys(pageViewsObj).map(id => {
			return pageViewsObj[id]
		})

		//Sort by number of page views descending
		let sortedPageViewsArr = pageViewsArr.sort((a, b) => {
			if(a.pageViews < b.pageViews) {
				return 1
			} else if (a.pageViews > b.pageViews) {
				return -1
			} else {
				return 0
			}
		})

		//Return top 3
		res.json(sortedPageViewsArr.slice(0, 4))

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

router.get('/page-views', auth, async(req, res, next) => {
	try {
		let logs = await Log.findAll({
			where: {
				createdAt: {
					$gt: lastWeek
				}
			},
			order: [['createdAt', 'ASC']]
		})

		res.json(processLogsForLineChart(logs))
	} catch (e) { next(e) }
})

router.get('/new-users', auth, async(req, res, next) => {
	try {
		let users = await User.findAll({
			where: {
				createdAt: {
					$gt: lastWeek
				}
			},
			order: [['createdAt', 'ASC']]
		})

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

router.get('/categories', auth, async(req, res, next) => {
	try {
		let categories = await Category.findAll()
		let categoryThreadCount = []

		await Promise.all(categories.map(async category => {
			let count = await Thread.count({ where: { CategoryId: category.id } })
			categoryThreadCount.push({
				value: count,
				label: category.name,
				color: category.color
			})
		}))

		res.json(categoryThreadCount)
	} catch (e) { next(e) }
})

router.get('/new-thread', auth, async(req, res, next) => {
	try {
		let now = Date.now()

		let threadsTodayCount = await Thread.count({
			where: {
				createdAt: {
					$gt: new Date(now - 1000*60*60*24)
				}
			}
		})
		let threadsYesterdayCount = await Thread.count({
			where: {
				createdAt: {
					$lt: new Date(now - 1000*60*60*24),
					$gt: new Date(now - 1000*60*60*24*2)
				}
			}
		})

		res.json({
			count: threadsTodayCount,
			change: threadsTodayCount - threadsYesterdayCount
		})
	} catch (e) { next(e) }
})

module.exports = router
