from aiohttp import web, log
import json
import socket
from duniterpy.documents import Peer
import asyncio


class Request:
    def __init__(self, method, url, content):
        self.url = url
        self.method = method
        self.content = content


class HTTPServer:
    def __init__(self, port, loop):
        self.lp = loop
        self.requests = []
        self.app = web.Application(middlewares=[self.middleware_factory])

        self.handler = None
        self.runner = None
        self.port = self.find_unused_port() if not port else port

    def get_request(self, i):
        return self.requests[i]

    async def middleware_factory(self, app, handler):
        async def middleware_handler(request):
            try:
                resp = await handler(request)
                return resp
            except web.HTTPNotFound:
                return web.Response(status=404, body=bytes(json.dumps({"ucode":1001,
                                                                    "message": "404 error"}),
                                                           "utf-8"),
                                    headers={'Content-Type': 'application/json'})

        return middleware_handler

    async def _handler(self, request, handle):
        await request.read()
        self.requests.append(Request(request.method, request.path, request.content))
        json_data, http_code = await handle(request)
        return web.Response(body=bytes(json.dumps(json_data), "utf-8"),
                            headers={'Content-Type': 'application/json'},
                            status=http_code)

    def add_route(self, req_type, url, handle):
        self.app.router.add_route(req_type, url,
                                  lambda request: self._handler(request, handle))

    def find_unused_port(self):
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.bind(('127.0.0.1', 0))
        port = s.getsockname()[1]
        s.close()
        return port

    async def create_server(self, ssl_ctx=None):
        self.handler = self.app.make_handler(
            keep_alive_on=False,
            access_log=log.access_logger,
        )

        self.port = self.find_unused_port()
        self.runner = web.AppRunner(self.app)
        await self.runner.setup()
        site = web.TCPSite(self.runner, '127.0.0.1', self.port)
        await site.start()

        protocol = "https" if ssl_ctx else "http"
        url = "{}://127.0.0.1:{}".format(protocol, self.port)
        return self.port, url

    async def close(self):
        await self.handler.shutdown()
        await self.runner.cleanup()