# note: https://responder.kennethreitz.org/en/latest/search.html?q=resp.content
from hub import methods

import traceback
import requests
import importlib


def generate_app():
    """"""

    # --- define app --- see: https://responder.kennethreitz.org/en/latest/tour.html#cors
    import responder
    app = responder.API(
        # cors=True,
        # allow_methods=['*'],
        # allow_credentials=True,
    )

    async def coroutine_method(method, _params):
        """协程方法"""
        # run_at = time.time()
        result = await method(**_params)
        # methods.debug_log(f"app.coroutine_method", f"use time {round(time.time() - run_at, 2)}s")
        return result

    def foreground_method(method, _params):
        """等待返回"""
        # run_at = time.time()
        result = method(**_params)
        # methods.debug_log(f"app.foreground_method", f"use time {round(time.time() - run_at, 2)}s")
        return result

    @app.background.task
    def background_method(method, _params):
        """不等返回"""
        # run_at = time.time()
        result = method(**_params)
        # methods.debug_log(f"app.background_method", f"use time {round(time.time() - run_at, 2)}s")
        return result

    async def run_method(code, _params):

        config_dict = {
            7000: ('v1', 'f7000', 'IsAsync'),
            70000: ('v1', 'f70000', 'IsBack'),
        }

        if code not in config_dict:
            return dict(code=2, detail=f"{code} not found!")
        else:

            script_name, method_name, method_type = config_dict[code]
            script = importlib.import_module(f"api.httpapi.{script_name}")
            method = getattr(script, method_name)
            del _params['code']

            if method_type == 'IsAsync':
                return await coroutine_method(method, _params)
            elif method_type == 'IsBack':
                return foreground_method(method, _params)
            elif method_type == 'NoBack':
                return background_method(method, _params)

    @app.route('/httpapi')
    async def httpapi(request, response):
        try:
            # --- fill ---
            if request.params:
                params = dict(request.params.items())
            else:
                params = await request.media()

            # --- debug ---
            methods.debug_log('app.httpapi92', f"#params: {params}")

            # --- check ---
            if 'code' not in params:
                response.media = dict(code=-1, reason="error98", detail=f"参数缺失")
            else:
                code = params.get('code')
                result = await run_method(code, params)
                methods.debug_log('app.httpapi102', f"#result: {result}")
                if result.__class__.__name__ == 'bytes':
                    response.content = result
                elif result.__class__.__name__ == 'str':
                    response.text = result
                elif result.__class__.__name__ == 'dict':
                    response.media = result
                elif result.__class__.__name__ == 'Future':
                    response.media = dict(code=0, detail=f"{result} is running.")
                elif not result:
                    response.media = dict(code=0, detail=f"return is null.")
                else:
                    response.media = dict(code=0, detail=f"return type is {result.__class__.__name__}.")

        except Exception as exception:

            methods.debug_log("app.httpapi118", f"#exception: {exception.__class__.__name__}")
            methods.debug_log("app.httpapi118", f"#traceback: {traceback.format_exc()}")
            response.media = dict(code=-1, reason=exception.__class__.__name__, detail=f"{methods.trace_log()}")

    @app.route('/wsapi', websocket=True)
    async def wsapi(client):
        """
        let wsuri = `${location.protocol === 'https' ? 'wss' : 'ws'}://${location.host}:8801/wsapi`;
        connect_json_text = {
            line_id: 连接id,暂为token
        }
        )
        send_json_text_1 = {
            face_uuid: 匹配到的人脸id
            face_name: 人脸名称
            input_face_b64: 抓拍图片(b64格式字符串)
        }
        """
        try:
            await client.accept()
            while True:

                # --- check ---
                data = await client.receive_text()  # 消息接受方法 receive_{text/json/bytes}
                if not data:
                    methods.debug_log('app.wsapi140', f"#reason: error140")
                    await client.send_json({'code': -1, 'reason': 'error140'})
                    break

                # --- debug ---
                # methods.debug_log('app.wsapi145', f"#data: {data} | {type(data)}")

                # --- check ---
                if not methods.is_json(data):
                    methods.debug_log('app.wsapi133', f"#reason: error146")
                    await client.send_json({'code': -1, 'reason': 'error146'})
                    break

                # --- check ---
                data = methods.json_loads(data)
                if not data.get('code'):
                    methods.debug_log('app.wsapi144', f"#reason: error157")
                    await client.send_json({'code': -1, 'reason': 'error157'})
                    break

                # --- debug ---
                if data.get('code') not in [2008]:
                    methods.debug_log('app.wsapi160', f"#data: {data}")

                # --- check 2000 ---
                code = data.get('code')
                if code == 2000:

                    # --- check ---
                    if 'acct' not in data or 'pw' not in data:
                        methods.debug_log('app.wsapi166', f"#reason: error164")
                        await client.send_json({'code': -1, 'reason': 'error164'})
                        break

                    # --- check ---
                    username = data.get('acct')
                    password = data.get('pw')
                    url = 'http://58.34.98.13:8099/api/ar/user/login'
                    data = {
                        "acct": username,
                        "pw": password,
                        "method": "1"  # 客户端类型 1 安卓 2 PC端
                    }
                    methods.debug_log('app.wsapi179', f"#url: {url}")
                    response = requests.post(url=url, json=data)
                    data = response.json()
                    if data.get('msg') and data.get('msg') == 'success':
                        data['code'] = 4000
                        await client.send_json(data)
                    else:
                        methods.debug_log('app.wsapi186', f"#reason: error186")
                        await client.send_json({'code': -1, 'reason': 'error186'})

                    # --- save ---
                    # methods.debug_log('app.wsapi179', f"{dir(client)}")
                    # methods.debug_log('app.wsapi179', f"#id: {id(client)} | {type(id(client))}")
                    methods.debug_log('app.wsapi179', f"{type(client)} | {methods.now_ts()} | {id(client)}")
                    LineManage.line_dict[username] = client, methods.now_ts(), id(client)

                # --- check 2008 ---
                if code == 2008:

                    # --- 判断该连接是否是已保存的链接 ---
                    is_ok = False
                    for key in list(LineManage.line_dict.keys()):

                        ws, ts, _id = LineManage.line_dict.get(key)
                        if _id == id(client):
                            LineManage.line_dict[username] = client, methods.now_ts(), id(client)
                            is_ok = True

                    await client.send_json({'code': 4008, 'result': is_ok})



        except Exception as exception:

            if exception.__class__.__name__ == 'WebSocketDisconnect':
                await client.close()
            else:
                methods.debug_log("app.wsapi163", f"#exception: {exception.__class__.__name__}")
                methods.debug_log("app.wsapi163", f"#traceback: {traceback.format_exc()}")

    # --- return ---
    return app