# -*- coding: utf-8 -*-
# @Author  : Gloo
# @time    : 2019/10/7 19:11
# @File    : __init__.py
# @Software: PyCharm
from wsgiref.simple_server import make_server
from webob import Request, Response
from webob.dec import wsgify
from webob.exc import HTTPNotFound
import re


class Content(dict):
    def __getattr__(self, item):
        try:
            return self[item]
        except KeyError:
            raise AttributeError(f"'Content' object has no attribute '{item}'")

    def __setattr__(self, key, value):
        self[key] = value


class NestedContent(Content):
    def __init__(self, global_content=None):
        super().__init__()
        self.global_content = global_content

    def relate(self, global_content):
        self.global_content = global_content

    def __getattr__(self, item):
        if item in self.keys():
            return self[item]
        return self.global_content[item]


class DictObject:
    def __init__(self, _dict):
        if isinstance(_dict, dict):
            self.__dict__['_dict'] = _dict
        else:
            self.__dict__['_dict'] = {}

    def __getattr__(self, item):
        try:
            return self._dict[item]
        except KeyError:
            return AttributeError(f"'DictObject' object has no attribute '{item}'")

    def __setattr__(self, key, value):
        raise NotImplementedError

    def items(self):
        return self._dict.items()


class _Router:
    GET = "GET"
    HEAD = "HEAD"
    POST = "POST"
    PUT = "PUT"
    DELETE = "DELETE"

    def __init__(self, prefix: str = ""):
        self._prefix = prefix.rstrip("/\\")
        self._route_table = []

        # 拦截器
        self.pre_interceptor = []
        self.post_interceptor = []

        # 上下文
        self.ctx = NestedContent()  # 未定义
        self.ctx.route = self

    def route(self, rule: str, *methods):
        def _wrapper(handler):
            pattern, translator = self.parse(rule)
            self._route_table.append((methods, re.compile(pattern), translator, handler))
            return handler
        wrapper = _wrapper
        return wrapper

    def get(self, pattern: str):
        return self.route(pattern, "GET")

    def head(self, pattern: str):
        return self.route(pattern, "HEAD")

    def post(self, pattern: str):
        return self.route(pattern, "POST")

    def put(self, pattern: str):
        return self.route(pattern, "PUT")

    def delete(self, pattern: str):
        return self.route(pattern, "DELETE")

    def match(self, request: Request):
        if not request.path.startswith(self._prefix):
            return

        # 依次执行拦截请求
        for fn in self.pre_interceptor:
            request = fn(self.ctx, request)

        tmp = request.path.replace(self._prefix, "", 1)
        relative_path = tmp if tmp.startswith("/") else "/" + tmp
        for methods, pattern, translator, handler in self._route_table:
            if not methods or request.method.upper() in methods:
                if request.method == self.GET:
                    matcher = pattern.match(relative_path)
                    if matcher:
                        newdict = {}
                        for k, v in matcher.groupdict().items():
                            newdict[k] = translator[k](v)
                        request.vars = DictObject(newdict)
                        response = handler(self.ctx, request)
                        print(type(response))

                        # 依次执行拦截响应
                        for fn in self.post_interceptor:
                            response = fn(self.ctx, request, response)
                        return response

    @property
    def prefix(self):
        return self._prefix

    # 正则简化
    TYPE_PATTERNS = {
        "str": r"[^/]+",
        "word": r"\w+",
        "int": r"[+-]?\d+",
        "float": r"[+-]?\d+.\d+",
        "any": r".+"
    }
    TYPE_CASE = {
        "str": str,
        "word": str,
        "int": int,
        "float": float,
        "any": str
    }
    pattern = re.compile('/{([^{}:]+):?([^{}:]*)}')

    @classmethod
    def transform(cls, kv: str):
        name, _, _type = kv.strip("/{}").partition(":")
        return "/(?P<{}>{})".format(name, cls.TYPE_PATTERNS.get(_type, r'\w+')), name, cls.TYPE_CASE.get(_type, str)

    @classmethod
    def parse(cls, src: str):
        start = 0
        res = ''
        translator = {}
        while True:
            matcher = cls.pattern.search(src, start)
            if matcher:
                res += matcher.string[start: matcher.start()]
                tmp = cls.transform(matcher.group())
                res += tmp[0]
                translator[tmp[1]] = tmp[2]
                start = matcher.end()
            else:
                break
        if res:
            return res, translator
        else:
            return src, translator

    def reg_pre_interceptor(self, fn):
        self.pre_interceptor.append(fn)
        return fn

    def reg_post_interceptor(self, fn):
        self.post_interceptor.append(fn)
        return fn


class Gloo:

    Router = _Router
    Request = Request
    Response = Response

    _routes = {}
    ctx = Content()

    # 拦截器
    PRE_INTERCEPTOR = []
    POST_INTERCEPTOR = []

    def __init__(self, **kwargs):
        for k, v in kwargs:
            self.ctx.k = v
        self.ctx.app = self

    @classmethod
    def register(cls, router: Router):
        cls._routes[router.prefix] = router
        router.ctx.relate(cls.ctx)
        return router

    @classmethod
    def reg_pre_interceptor(cls, fn):
        cls.PRE_INTERCEPTOR.append(fn)
        return fn

    @classmethod
    def reg_post_interceptor(cls, fn):
        cls.POST_INTERCEPTOR.append(fn)
        return fn

    @classmethod
    def extend(cls, name):
        def _wrapper(ext):
            cls.ctx[name] = ext
            return ext
        return _wrapper

    @wsgify
    def __call__(self, request: Request, *args, **kwargs):
        # 全局拦截请求
        for fn in self.PRE_INTERCEPTOR:
            request = fn(self.ctx, request)

        request_prefix = "/" + request.path.split("/")[1]
        if request_prefix in self._routes:
            response = self._routes[request_prefix].match(request)
            print(type(response))
            # 全局拦截响应
            for fn in self.POST_INTERCEPTOR:
                response = fn(self.ctx, request, response)
            if response:
                return response
        raise HTTPNotFound


if __name__ == '__main__':
    ip = "127.0.0.1"
    port = 9999
    server = make_server(ip, port, Gloo())
    server.serve_forever()
