import sys
import gzip
import signal
import asyncio
from aiohttp import web
import aiohttp_cors
import aiosqlite
import logging

logging.basicConfig(level=logging.INFO)

# Database to connect to
# (tested with files generated by tippecanoe: https://github.com/mapbox/tippecanoe)
DATA_FILE = 'data/geography_usa_blockgroup_2015.mbtiles'

async def get_db_conn(app):
    if app.get('db_conn'):
        return app['db_conn']
    else:
        app['db_conn'] = await aiosqlite.connect(DATA_FILE)
    return app['db_conn']

async def on_cleanup(app):
    conn = await get_db_conn(app)
    await conn.close()

async def tile(request):
    z = request.match_info['z']
    x = request.match_info['x']
    y = request.match_info['y']
    logging.info(f'- Requested tile: {z}/{x}/{y}')

    # y = (1 << zoom_level) - 1 - tile_row
    # ==> tile_row = (1 << (int(z))) - int(y) - 1
    tr = (1 << (int(z))) - int(y) - 1
    logging.info(f'GETTING: {z}, {x}, {y} ({tr})')
    sql = f'''
        SELECT tile_data as mvt
        FROM tiles
        WHERE zoom_level = {z} AND tile_column = {x} AND tile_row = {tr};
    '''

    db_conn = await get_db_conn(request.app)
    async with db_conn.execute(sql) as cursor:
        res = await cursor.fetchone()
        await cursor.close()
        if res:
            logging.info(f'+ serving tile: {z}/{x}/{y}')
        return web.Response(
            body=gzip.decompress(res[0]) if res else None,
            content_type='application/vnd.mapbox-vector-tile'
        )

async def create_app():
    app = web.Application()
    # asyncio.set_event_loop(app.loop)
    app.on_cleanup.append(on_cleanup)

    app.add_routes([web.get('/{z}/{x}/{y}.{ext}', tile)])

    cors = aiohttp_cors.setup(app, defaults={
        '*': aiohttp_cors.ResourceOptions(
            allow_methods='*',
            allow_credentials=True,
            allow_headers='*',
            expose_headers='*'
        )
    })
    for route in app.router.routes():
        cors.add(route)

    return app


def main_exit_handler(*args, **kwargs):
    sys.exit(0)

signal.signal(signal.SIGTERM, main_exit_handler)


app = asyncio.run(create_app())

# Run script with:
# gunicorn minimal-mvt-aiohttp-mbtiles:app -b localhost:8081 -w 1 --worker-class aiohttp.GunicornUVLoopWebWorker --reload
