import http.cookies
import logging
import json
import collections
from . import httpd
from . import sse
from . import fire, get_context
from . import sessions


# Logging
logger = logging.getLogger(__name__)

# bring some external handlers into this module's scope
# (now you can just import eca.http and have access to all standard handlers)
StaticContent = httpd.StaticContent
SessionManager = sessions.SessionManager


class Cookies(httpd.Filter):
    """Filter to read cookies from request."""
    def handle(self):
        # process available cookies
        cookies = http.cookies.SimpleCookie()
        if 'cookie' in self.request.headers:
            cookies.load(self.request.headers['cookie'])

        # set cookies on request
        self.request.cookies = cookies



class HelloWorld(httpd.Handler):
    """The mandatory Hello World example."""
    def handle_GET(self):
        self.request.send_response(200)
        self.request.send_header('content-type','text/html; charset=utf-8')
        self.request.end_headers()

        output = "<!DOCTYPE html><html><body><h1>Hello world!</h1><p><i>eca-session:</i> {}</p></body></html>"

        try:
            if not hasattr(self.request, 'cookies'): raise KeyError()
            cookie = self.request.cookies['eca-session'].value
        except KeyError:
            cookie = '<i>no cookie</i>';
        
        self.request.wfile.write(output.format(cookie).encode('utf-8'))


def Redirect(realpath):
    """
    Factory for redirection handlers.
    """
    class RedirectHandler(httpd.Handler):
        def handle_GET(self):
            location = None

            # check for absolute paths
            if realpath.startswith("http://") or realpath.startswith('https://'):
                location = realpath
            else:
                host = self.request.server.server_address[0]
                if self.request.server.server_address[1] != 80:
                    host += ":{}".format(self.request.server.server_address[1])
    
                if 'host' in self.request.headers:
                    host = self.request.headers['host']
    
                location = "http://{}{}".format(host, realpath)

            self.request.send_response(302)
            self.request.send_header('content-type','text/html; charset=utf-8')
            self.request.send_header('location',location)
            self.request.end_headers()
            output = "<!DOCTYPE html><html><body><p>Redirect to <a href='{0}'>{0}</a></p></body></html>"
            self.request.wfile.write(output.format(location).encode('utf-8'))

    return RedirectHandler


def GenerateEvent(name):
    """
    This function returns a handler class that creates the named event based
    on the posted JSON data.
    """
    class EventGenerationHandler(httpd.Handler):
        def handle_POST(self):
            # handle weirdness
            if 'content-length' not in self.request.headers:
                self.request.send_error(411)
                return

            # read content-length header
            length = int(self.request.headers['content-length'])

            # grab data
            data = self.request.rfile.read(length)
            try:
                structured = json.loads(data.decode('utf-8'))
            except ValueError as e:
                self.request.send_error(400, "Bad request: "+str(e))
                return

            if not isinstance(structured, collections.abc.Mapping):
                self.request.send_error(400, "Bad request: expect a JSON object")
                return

            try:
                fire(name, structured)
            except NotImplementedError:
                logger.warn("Event generated by HTTP request without active session. Do you have a SessionManager configured?")
                self.request.send_error(500, "No current context available.")
                return

            self.request.send_response(202)
            self.request.send_header('content-type', 'text/plain; charset=utf-8')
            self.request.send_header('content-length', 0)
            self.request.end_headers()

    return EventGenerationHandler


class EventStream(sse.ServerSideEvents):
    def go_subscribe(self):
        def receiver(name, event):
            self.send_event(event.data.get('json'), event.name, event.data.get('id'))

        self.receiver = receiver
        context = get_context()
        context.channel.subscribe(self.receiver, 'emit')

    def go_unsubscribe(self):
        context = get_context()
        context.channel.unsubscribe(self.receiver, 'emit')
