import asyncio
from aiohttp import web
import aiohttp_session
import aiohttp_security

import aiomysql
from pymysql.err import OperationalError

import datetime
import simplejson
from dateutil.relativedelta import relativedelta
import urllib.parse
import psutil

# Local
import files
import apps
import security

async def mysql_engine(app):
	print("Connecting to database... ", end='')
	try:
		pool = await aiomysql.create_pool(autocommit=True, **app['config']['database'])
		app['con'] = await pool.acquire()
		app['cur'] = await app['con'].cursor() #aiomysql.DictCursor
	except OperationalError as e:
		print(e)
	print("Done.")

	yield # Keep the cleanup context open until shutdown

	print("Disconnecting from database... ", end='')
	pool.close()
	await pool.wait_closed()
	print("Done.")

async def main():
	# Start tracking CPU usage
	_ = psutil.cpu_percent(percpu=True)

	root = web.Application()
	root['config'] = files.Config()
	root['templates'] = files.Templates()
	routes = web.RouteTableDef()
	@routes.get('/')
	async def home(request):
		return web.Response(text=request.config_dict['templates']['home.html'].template, content_type="text/html")

	aiohttp_session.setup(root, security.get_cookie_storage())
	aiohttp_security.setup(root, security.LocalSessionIdentityPolicy(), security.SimplePasswordAuthPolicy())
	root.add_routes(routes)

	# Should be served by reverse proxy in production
	root.router.add_static('/static/', path='./static', name='static')

	account = web.Application()
	account['prefix'] = '/log/'
	account['templates'] = files.Templates('apps/account/templates')
	apps.account.init_app(account)
	root.router.add_static('/log/static/', path='./apps/account/static', name='acc_static')
	root.add_subapp('/log', account)

	calendar = web.Application()
	calendar.middlewares.append(security.redirect_to_login)
	calendar['prefix'] = '/calendar/'
	calendar['templates'] = files.Templates('apps/calendar/templates')
	calendar['config'] = files.Config('apps/calendar/config', root['config'].config)
	calendar.cleanup_ctx.append(mysql_engine)
	apps.calendar.init_app(calendar)
	root.router.add_static('/calendar/static/', path='./apps/calendar/static', name='cal_static')
	root.add_subapp('/calendar', calendar)

	reporter = web.Application()
	reporter.middlewares.append(security.redirect_to_login)
	reporter['prefix'] = '/reporter/'
	reporter['templates'] = files.Templates('apps/reporter/templates')
	reporter['config'] = files.Config('apps/reporter/config', root['config'].config)
	reporter.cleanup_ctx.append(mysql_engine)
	apps.reporter.init_app(reporter)
	root.router.add_static('/reporter/static/', path='./apps/reporter/static', name='rep_static')
	root.add_subapp('/reporter', reporter)

	waiter = asyncio.Event()
	runner = web.AppRunner(root)
	# Hang on to these references so we can initiate a graceful shutdown from inside a coroutine
	root['waiter'] = waiter
	root['runner'] = runner

	await runner.setup()
	web_config = root['config']['web']
	site = web.TCPSite(runner, **web_config)
	await site.start()
	print(f"Listening on {web_config['host']}:{web_config['port']}.")

	# Wait for the Event to be .set() by the graceful shutdown procedure
	await waiter.wait()
	print("Goodbye!")

if __name__ == "__main__":
	asyncio.run(main())