
import logging
import traceback
import inspect
import json
import sys

import raven

from django.conf import settings

import gm_logging
import gm_logging.utils
from gm_rpcd.all import context
from gm_rpcd.features.raven import get_raven_client
from gm_rpcd.internals.dynamic_scopes import DynamicVariableUnboundError
from gm_logging.utils import get_exception_logging_func

from engine.network import get_client_ip


info_logger = logging.getLogger('info_logger')
error_logger = logging.getLogger('error_logger')
profile_logger = logging.getLogger('profile_logger')
exception_logger = logging.getLogger('exception_logger')

cpc_click_consumer_logger = logging.getLogger('cpc_click_consumer_logger')
auth_logger = logging.getLogger('auth_logger')
wechat_logger = logging.getLogger('wechat_logger')
sensitive_logger = logging.getLogger('sensitive_logger')


def debug(view_func):
    """将POST请求数据存到log

    :param view_func:
    :return:
    """

    def wrap(request):
        info_logger.info(request.POST.dict())
        return view_func(request)

    return wrap


def _build_json_format(result):
    """
    创建json格式输出
    """
    return json.dumps(result, ensure_ascii=True, indent=2)


def _get_exception_info():
    """
    获取stacktrace
    """
    try:
        exc_type, exc_value, exc_traceback = sys.exc_info()
        exc = traceback.format_exception(exc_type, exc_value, exc_traceback)
        info = {'exception': exc}
        return info
    except:
        logging.error('_get_exception_info error')
        return {}


def _build_func_args_item(stack_info):
    """
    创建单调函数调用记录
    """
    try:
        func_name = stack_info[3]
        args_info = inspect.getargvalues(stack_info[0])
        frame = stack_info[0]
        item = {'function': func_name,
                'object': '%s' % frame.f_locals.get('self'),
                'arguments': inspect.formatargvalues(args_info.args, args_info.varargs, args_info.keywords,
                                                     args_info.locals)}
        return item
    except:
        logging.error('_build_func_args_item error')
        return {}


def _get_func_args():
    """
    获取外层函数调用参数，注意调用栈顺序，最多取最后3层调用
    """
    try:
        stacks = inspect.stack()[:3]
        result = []
        for stack in stacks:
            item = _build_func_args_item(stack)
            result.append(item)
        return result
    except:
        logging.error('_get_func_args error')
        return []


def print_exception():
    """
    直接输出异常信息
    """
    print(_build_json_format(_get_exception_info()))


_sentry_client = None
try:
    _sentry_client = get_raven_client()
except:
    pass

if _sentry_client is None:
    _sentry_client = raven.Client(settings.SENTRY_CELERY_ENDPOINT)

# 从gm-logging中取得通用的logging_exception方法，logging_excepiton的原型如下：
# logging_exception(exception_logger, sentry_client=None, send_to_sentry=True, **kwargs)
logging_exception = get_exception_logging_func(exception_logger, _sentry_client)


def get_logging_exception_json():
    func_args = _get_func_args()
    exc = _get_exception_info()
    error_json = _build_json_format({'stacktrace': exc, 'func_args': func_args})
    return error_json


class RequestInfoExtractor(gm_logging.RequestInfoExtractor):

    __cl_type_map = {
        'iPhone': 'ios',
        'android': 'android',
    }

    @classmethod
    def __get_cl_type(cls, cl_type):
        return cls.__cl_type_map.get(cl_type, cl_type)

    def __init__(self):
        self.__local_ip = gm_logging.utils.get_local_ip()
        self.__hostname = gm_logging.utils.get_hostname()

    def get_request_info(self, request):
        request_info = gm_logging.RequestInfo.create(
            log_host=self.__local_ip,
            hostname=self.__hostname,

            module='saturn',

            cl_type=self.__get_cl_type(request.GET.get('platform')),
            cl_ver=request.GET.get('version'),
            cl_os_ver=request.GET.get('os_version'),
            phone_model=request.GET.get('model'),
            cl_id=request.GET.get('device_id') or request.GET.get('idfa'),
            cl_ios_idfv=request.GET.get('idfv'),
            channel=request.GET.get('channel'),
            session_id=request.session.session_key,
            user_ip=get_client_ip(request),
            gm_request_id=request.META.get('HTTP_X_GM_REQUEST_ID'),

            http_verb=request.method,
            action=request.path,
        )

        extra = {
            'cl_longitude': request.GET.get('lng'),
            'cl_latitude': request.GET.get('lat'),
            'cl_city_id': request.GET.get('current_city_id'),
            'phone_id': request.GET.get('phone_id'),
        }
        try:
            # 兼容旧版 gm-logging
            request_info.update(**extra)
        except Exception:
            pass
        return request_info

