/*
 *  Copyright 2019-2020 Zheng Jie
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package com.youchain.aspect;

import cn.hutool.json.JSONUtil;
import com.youchain.utils.RequestHolder;
import com.youchain.utils.SecurityUtils;
import com.youchain.utils.StringUtils;
import com.youchain.utils.ThrowableUtil;
import lombok.extern.slf4j.Slf4j;
import com.youchain.domain.Log;
import com.youchain.service.LogService;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.security.web.context.HttpRequestResponseHolder;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;

/**
 * @author Liu Xue
 * @date 2018-11-24
 */
@Component
@Aspect
@Slf4j
public class LogAspect {

    private final LogService logService;

    ThreadLocal<Long> currentTime = new ThreadLocal<>();

    public LogAspect(LogService logService) {
        this.logService = logService;
    }

    /**
     * 配置切入点
     */
    @Pointcut("@annotation(com.youchain.annotation.Log)")
    public void logPointcut() {
        // 该方法无方法体,主要为了让同类中其他方法使用此切入点
    }

    /**
     * 配置环绕通知,使用在方法logPointcut()上注册的切入点
     *
     * @param joinPoint join point for advice
     */
    @Around("logPointcut()")
    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
        Object result;
        currentTime.set(System.currentTimeMillis());
        result = joinPoint.proceed();
        String result_data = handlerResult(result);
        //log.error("----结束了---"+result_data);
        Log log_data = new Log("INFO",System.currentTimeMillis() - currentTime.get());
        currentTime.remove();
        HttpServletRequest request = RequestHolder.getHttpServletRequest();
        String url=request.getRequestURL().toString();
        String parm=request.getQueryString();
        if(parm!=null&&parm.length()>0){
            url=url+"?"+parm;
        }

        logService.save(url,result_data,getUsername(), StringUtils.getBrowser(request), StringUtils.getIp(request),joinPoint, log_data);

        return result;
    }


    private String handlerResult(Object result) {
        if (result == null) {
            return null;
        }
        String resultStr;
        try {
            if (result instanceof String) {
                resultStr = (String) result;
            } else {
                resultStr = JSONUtil.toJsonStr(result);// 如果返回结果非String类型，转换成JSON格式的字符串
            }

            if (resultStr.length() > 10000) {
                resultStr = resultStr.substring(0, 10000);
            }
        } catch (Exception e) {
            resultStr = result.toString();
            log.error("接口出入参日志打印切面处理返回参数异常", e);
        }
        return resultStr;
    }

    @AfterReturning(returning = "returnValue", pointcut = "logPointcut()")
    public void doAfterReturning(JoinPoint joinPoint,Object returnValue) throws Throwable {
        // 处理完请求，返回内容
      /*  log.info("类名:"+joinPoint.getSignature().getDeclaringTypeName()+
                "、方法名: "+joinPoint.getSignature().getName()+"()、====>@Before：请求参数为：{}", Arrays.toString(joinPoint.getArgs()));
*/
    }



    /**
     * 配置异常通知
     *
     * @param joinPoint join point for advice
     * @param e exception
     */
    @AfterThrowing(pointcut = "logPointcut()", throwing = "e")
    public void logAfterThrowing(JoinPoint joinPoint, Throwable e) {
        Log log = new Log("ERROR",System.currentTimeMillis() - currentTime.get());
        currentTime.remove();
        log.setExceptionDetail(ThrowableUtil.getStackTrace(e).getBytes());
        HttpServletRequest request = RequestHolder.getHttpServletRequest();

        String url=request.getRequestURL().toString();
        String parm=request.getQueryString();
        if(parm!=null&&parm.length()>0){
            url=url+"?"+parm;
        }
        logService.save(url,"",getUsername(), StringUtils.getBrowser(request), StringUtils.getIp(request), (ProceedingJoinPoint)joinPoint, log);
    }

    public String getUsername() {
        try {
            return SecurityUtils.getCurrentUsername();
        }catch (Exception e){
            return "";
        }
    }
}
