# coding=utf8
from __future__ import unicode_literals, absolute_import, print_function
import sys
import logging
import traceback
import inspect
import json
import uuid
import time
import datetime
from contextlib import contextmanager

from raven.contrib.django.raven_compat.models import client as _sentry_client

from gm_types.utils.enum import Enum, unique
from gm_tracer.context import register_tracer, purge_current_tracer
from gm_tracer.context import current_tracer
from gm_tracer.tracer import generate_traceid, GMTracer
from gm_logging.py_logging import AppHandler, InspectHandler

from gm_logging.utils import get_exception_logging_func

__author__ = 'leaf'
"""
封装日志相关操作
"""

# 一般情况下不要使用这个 logger
_error_logger = logging.getLogger('err_logger')

exception_logger = logging.getLogger('exception_logger')
elapsed_logger = logging.getLogger('elapsed_logger')
info_logger = logging.getLogger('info_logger')
personal_slide_logger = logging.getLogger('personal_slide')
ai_logger = logging.getLogger('ai_logger')
auth_logger = logging.getLogger('auth_logger')
profile_logger = logging.getLogger("profile")
push_logger = logging.getLogger('push_logger')
user_push_logger = logging.getLogger('user_push_logger')
doctor_push_logger = logging.getLogger('doctor_push_logger')
push_block_logger = logging.getLogger('push_block_logger')
search_logger = logging.getLogger('search_logger')
conversation_logger = logging.getLogger('conversation_logger')
period_task_logger = logging.getLogger('period_task_logger')
pay_logger = logging.getLogger('pay_logger')
wechat_pay_logger = logging.getLogger('wechat_pay_logger')
wechat_refund_logger = logging.getLogger('wechat_refund_logger')
alipay_pay_logger = logging.getLogger('alipay_pay_logger')
alipay_refund_logger = logging.getLogger('alipay_refund_logger')
repeat_refund_logger = logging.getLogger('repeat_refund_logger')
recommend_logger = logging.getLogger('recommend_logger')
apple_pay_logger = logging.getLogger('apple_pay_logger')
apple_refund_logger = logging.getLogger('apple_refund_logger')
device_record_logger = logging.getLogger('device_record_logger')
installment_logger = logging.getLogger('installment_logger')
installment_callback_logger = logging.getLogger('installment_callback_logger')
sms_logger = logging.getLogger('sms_logger')
doctor_switch_logger = logging.getLogger('doctor_switch_logger')
doctor_unread_logger = logging.getLogger('doctor_unread_logger')
doctor_stats_logger = logging.getLogger('doctor_stats_logger')
yinuo_logger = logging.getLogger('yinuo_logger')
qiniu_logger = logging.getLogger('qiniu_logger')
merchant_logger = logging.getLogger('merchant_logger')
channel_logger = logging.getLogger('channel_logger')
momo_stat_logger = logging.getLogger("momo_stat_logger")
cache_skus_logger = logging.getLogger("cache_skus_logger")
user_logger = logging.getLogger('user_logger')
user_transfer_logger = logging.getLogger('user_transfer_logger')
price_logger = logging.getLogger('price_logger')
goods_logger = logging.getLogger('goods_logger')
user_activity_logger = logging.getLogger('user_activity_logger')
hera_feed_logger = logging.getLogger('hera_feed_logger')
smart_rank_logger = logging.getLogger('smart_rank_logger')
locate_city_logger = logging.getLogger('locate_city_logger')
cache_logger = logging.getLogger('cache_logger')
wechat_account_logger = logging.getLogger('wechat_account_logger')
order_logger = logging.getLogger('order_logger')
yibao_pay_logger = logging.getLogger('yibao_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, encoding='utf-8')


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()))


# 从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 log_elapsed_info(content):
    elapsed_logger.info(content)


def log_audit_hera(log_data):
    try:
        logger_name = 'gm-general-audit.hera'
        audit_logger = logging.getLogger(logger_name)
        audit_logger.addHandler(AppHandler(logger_name))
        audit_logger.setLevel(logging.INFO)
        audit_logger.info(log_data)
    except:
        logging_exception()


def setup_elasticsearch_logging():
    logger = logging.getLogger('elasticsearch.trace')
    handler = InspectHandler()
    handler.setLevel(logging.INFO)
    logger.addHandler(handler)
    if not logger.isEnabledFor(logging.INFO):
        logger.setLevel(logging.INFO)


setup_elasticsearch_logging()

message_trace_logger = None


def setup_message_trace_logging():
    global message_trace_logger
    message_trace_logger_name = 'gm-logging-message-trace.gaia'
    message_trace_logger = logging.getLogger(message_trace_logger_name)
    message_trace_logger.addHandler(AppHandler(message_trace_logger_name))
    message_trace_logger.setLevel(logging.INFO)


def log_message_trace(event_type, data={}):
    """ 记录链路日志到Kafka """

    payload = {
        "trace_id": current_trace_id(),
        "event_id": uuid.uuid4().hex,
        "event_type": event_type,
        "event_time": int(round(time.time() * 1000)),
        "data": data
    }
    message_trace_logger.info(payload)


def current_trace_id():
    tracer = current_tracer()
    return tracer.trace_id if tracer else generate_traceid()


@contextmanager
def trace_context(trace_id):
    """ trace 上下文管理 """
    tracer = GMTracer(trace_id=trace_id)
    register_tracer(tracer)
    yield
    purge_current_tracer()
