# -*- coding: utf-8 -*-
#
# copyright 2018 joseph weston
#
# this program is free software: you can redistribute it and/or modify
# it under the terms of the gnu general public license as published by
# the free software foundation, either version 3 of the license, or
# (at your option) any later version.
#
# this program is distributed in the hope that it will be useful,
# but without any warranty; without even the implied warranty of
# merchantability or fitness for a particular purpose.  see the
# gnu general public license for more details.
#
# you should have received a copy of the gnu general public license
# along with this program.  if not, see <http://www.gnu.org/licenses/>.
"""Serve nord as a web app.

To use this package as a library, simply instantiate an instance of the
app with `init_app`.

The API can be accessed by opening a websocket connection to '/api'.


Requests
========
The API accepts 2 types of request.

Connect
*******
A request to connect to a server in the provided country. Countries
are specified as case-insensitive ISO alpha-2 codes. An example
request is::

    {
      "method" : "connect",
      "country" : "NL"
    }

Disconnect
**********
A request to disconnect the current OpenVPN connection. An
example request is::

    {
      "method" : "disconnect"
    }


Responses
=========

Connecting
**********
After receiving a "connect" request, the API will send a message
to all connected peers with the following example format::

    {
      "state" : "connecting",
      "country" : "nl",
    }

Connected
*********
When an OpenVPN connection is established, the API will send
a message to all connected peers with the following example
format::

    {
      "state" : "connected",
      "host" : "nl123.nordvpn.com"
    }

Disconnecting
*************
After receiving a "disconnect" request, the API will send a message
to all connected peers with the following example format::

    {
      "state" : "disconnecting"
    }

Disconnected
************
When an OpenVPN connection is established, the API will send
a message to all connected peers with the following example
format::

    {
      "state" : "disconnected"
    }

Error
*****
If there was some error on the server side the API will send a
message to all connected peers in the following example format::

    {
      "state" : "error",
      "message" : "Something went wrong!"
    }
"""

import asyncio
import os.path
from os.path import abspath, dirname

from structlog import get_logger
from aiohttp import web

from . import api

STATIC_FOLDER_PATH = os.path.join(abspath(dirname(__file__)), 'static')


async def index(_):
    """Serve frontend files."""
    return web.FileResponse(os.path.join(STATIC_FOLDER_PATH, 'index.html'))


def init_app(client, credentials):
    """Instantiate a new nord web app.

    Parameters
    ----------
    client : nord.api.Client
    credentials: (username, password)

    Returns
    -------
    aiohttp.web.Application
    """
    app = web.Application()

    app.router.add_get('/', index)
    app.router.add_get('/api', api.handler)
    app.router.add_static('/', path=STATIC_FOLDER_PATH, name='static')

    app['credentials'] = credentials
    app['client'] = client
    app['peers'] = set()
    app['queue'] = asyncio.Queue(loop=app.loop)
    app['log'] = get_logger(__name__)
    app['shutdown_signal'] = asyncio.Event(loop=app.loop)

    app.on_startup.append(api.on_startup)
    app.on_cleanup.append(api.on_cleanup)

    return app