import io
import json
import logging
import logging.config
import sys
from urllib.parse import parse_qsl

import pkg_resources

from .base import SATOSABase
from .context import Context
from .response import ServiceError, NotFound
from .routing import SATOSANoBoundEndpointError
from saml2.s_utils import UnknownSystemEntity

logger = logging.getLogger(__name__)


def unpack_get(environ):
    """
    Unpacks a redirect request query string.
    :param environ: whiskey application environment.
    :return: A dictionary with parameters.
    """
    if "QUERY_STRING" in environ:
        return dict(parse_qsl(environ["QUERY_STRING"]))

    return None


def unpack_post(environ, content_length):
    """
    Unpacks a post request query string.
    :param environ: whiskey application environment.
    :return: A dictionary with parameters.
    """
    post_body = environ['wsgi.input'].read(content_length).decode("utf-8")
    data = None
    if "application/x-www-form-urlencoded" in environ["CONTENT_TYPE"]:
        data = dict(parse_qsl(post_body))
    elif "application/json" in environ["CONTENT_TYPE"]:
        data = json.loads(post_body)

    logger.debug("unpack_post:: %s", data)
    return data


def unpack_request(environ, content_length=0):
    """
    Unpacks a get or post request query string.
    :param environ: whiskey application environment.
    :return: A dictionary with parameters.
    """
    data = None
    if environ["REQUEST_METHOD"] == "GET":
        data = unpack_get(environ)
    elif environ["REQUEST_METHOD"] == "POST":
        data = unpack_post(environ, content_length)

    logger.debug("read request data: %s", data)
    return data


class ToBytesMiddleware(object):
    """Converts a message to bytes to be sent by WSGI server."""

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

    def __call__(self, environ, start_response):
        data = self.app(environ, start_response)

        if isinstance(data, list):
            encoded_data = []
            for d in data:
                if isinstance(d, bytes):
                    encoded_data.append(d)
                else:
                    encoded_data.append(d.encode("utf-8"))
            return encoded_data

        if isinstance(data, str):
            return data.encode("utf-8")

        return data


class WsgiApplication(SATOSABase):
    def __init__(self, config):
        super().__init__(config)

    def __call__(self, environ, start_response, debug=False):
        path = environ.get('PATH_INFO', '').lstrip('/')
        if ".." in path or path == "":
            resp = NotFound("Couldn't find the page you asked for!")
            return resp(environ, start_response)

        context = Context()
        context.path = path

        # copy wsgi.input stream to allow it to be re-read later by satosa plugins
        # see: http://stackoverflow.com/
        #      questions/1783383/how-do-i-copy-wsgi-input-if-i-want-to-process-post-data-more-than-once
        content_length = int(environ.get('CONTENT_LENGTH', '0') or '0')
        body = io.BytesIO(environ['wsgi.input'].read(content_length))
        environ['wsgi.input'] = body
        context.request = unpack_request(environ, content_length)
        environ['wsgi.input'].seek(0)

        context.cookie = environ.get("HTTP_COOKIE", "")
        context.request_authorization = environ.get("HTTP_AUTHORIZATION", "")

        try:
            resp = self.run(context)
            if isinstance(resp, Exception):
                raise resp
            return resp(environ, start_response)
        except SATOSANoBoundEndpointError:
            resp = NotFound("The Service or Identity Provider you requested could not be found.")
            return resp(environ, start_response)
        except Exception as err:
            if type(err) != UnknownSystemEntity:
                logger.exception("%s" % err)
            if debug:
                raise

            resp = ServiceError("%s" % err)
            return resp(environ, start_response)


def make_app(satosa_config):
    try:
        if "LOGGING" in satosa_config:
            logging.config.dictConfig(satosa_config["LOGGING"])
        else:
            stderr_handler = logging.StreamHandler(sys.stderr)
            stderr_handler.setLevel(logging.DEBUG)

            root_logger = logging.getLogger("")
            root_logger.addHandler(stderr_handler)
            root_logger.setLevel(logging.DEBUG)

        try:
            _ = pkg_resources.get_distribution(module.__name__)
            logger.info("Running SATOSA version %s",
                        pkg_resources.get_distribution("SATOSA").version)
        except (NameError, pkg_resources.DistributionNotFound):
            pass
        return ToBytesMiddleware(WsgiApplication(satosa_config))
    except Exception:
        logger.exception("Failed to create WSGI app.")
        raise

@@ -1149,26 +1149,23 @@
 %0A    log
-ger.debug(
+line = 
 %22unpack_
@@ -1171,25 +1171,57 @@
 _post:: 
-%25s%22, data
+%7B%7D%22.format(data)%0A    logger.debug(logline
 )%0A    re
@@ -1639,26 +1639,23 @@
 %0A    log
-ger.debug(
+line = 
 %22read re
@@ -1670,17 +1670,49 @@
 ta: 
-%25s%22, data
+%7B%7D%22.format(data)%0A    logger.debug(logline
 )%0A  
@@ -3888,16 +3888,59 @@
 Entity:%0A
+                logline = %22%7B%7D%22.format(err)%0A
         
@@ -3964,26 +3964,23 @@
 ception(
-%22%25s%22 %25 err
+logline
 )%0A      
@@ -4627,17 +4627,15 @@
  log
-ger.info(
+line = 
 %22Run
@@ -4658,20 +4658,20 @@
 ion 
-%25s%22,%0A       
+%7B%7D%22.format(%0A
     
@@ -4682,17 +4682,16 @@
         
- 
 pkg_reso
@@ -4691,32 +4691,36 @@
 kg_resources.get
+.get
 _distribution(%22S
@@ -4734,16 +4734,62 @@
 .version
+%0A            )%0A            logger.info(logline
 )%0A      
@@ -4961,30 +4961,23 @@
      log
-ger.exception(
+line = 
 %22Failed 
@@ -4996,16 +4996,49 @@
 GI app.%22
+%0A        logger.exception(logline
 )%0A      

Modify logging for proxy_server