import json
from pyroute2 import NDB
from pyroute2.cli.session import Session

try:
    from BaseHTTPServer import HTTPServer as HTTPServer
    from BaseHTTPServer import BaseHTTPRequestHandler
except ImportError:
    from http.server import HTTPServer as HTTPServer
    from http.server import BaseHTTPRequestHandler


class ProxyEncoder(object):

    def __init__(self, wfile):
        self.wfile = wfile

    def write(self, data):
        self.wfile.write(data.encode('utf-8'))

    def flush(self):
        self.wfile.flush()


class Handler(BaseHTTPRequestHandler):

    def do_error(self, code, reason):
        self.send_error(code, reason)
        self.end_headers()

    def do_POST(self):
        #
        # sanity checks:
        #
        # * path
        if self.path != '/v1/':
            return self.do_error(404, 'url not found')
        # * content length
        if 'Content-Length' not in self.headers:
            return self.do_error(411, 'Content-Length')
        # * content type
        if 'Content-Type' not in self.headers:
            return self.do_error(400, 'Content-Type')
        #

        content_length = int(self.headers['Content-Length'])
        content_type = self.headers['Content-Type']
        data = self.rfile.read(content_length)

        if content_type == 'application/json':
            try:
                request = json.loads(data)
            except ValueError:
                return self.do_error(400, 'Incorrect JSON input')
        elif content_type == 'text/plain':
            request = {'commands': data.decode('utf-8').split(';')}
        else:
            self.do_error(400, 'Incorrect content type')

        # auth plugins
        if 'X-Auth-Mech' in self.headers:
            auth_plugin = (self
                           .server
                           .auth_plugins
                           .get(self.headers['X-Auth-Mech']))
            if auth_plugin is None:
                return self.do_error(501, 'Authentication mechanism not found')
            try:
                am = auth_plugin(self.headers)
            except Exception:
                return self.do_error(401, 'Authentication failed')
            ndb = self.server.ndb.auth_proxy(am)
        elif self.server.auth_strict:
            return self.do_error(401, 'Authentication required')
        else:
            ndb = self.server.ndb

        session = Session(ndb=ndb,
                          stdout=ProxyEncoder(self.wfile),
                          builtins=('ls', '.', '..', 'version'))
        self.send_response(200)
        self.end_headers()
        for cmd in request['commands']:
            session.handle(cmd)


class Server(HTTPServer):

    def __init__(self,
                 address='localhost',
                 port=8080,
                 sources=None,
                 ndb=None,
                 log=None,
                 auth_strict=False,
                 auth_plugins=None):
        self.sessions = {}
        self.auth_strict = auth_strict
        self.auth_plugins = auth_plugins or {}
        if ndb is not None:
            self.ndb = ndb
        else:
            self.ndb = NDB(sources=sources, log=log)
        self.ndb.config = {'show_format': 'json'}
        HTTPServer.__init__(self, (address, port), Handler)
