package com.cnooc.expert.system.operatelog.aspect;

import com.alibaba.fastjson.JSON;
import com.cnooc.expert.common.utils.KafkaProducerUtil;
import com.cnooc.expert.common.utils.UserUtils;
import com.cnooc.expert.system.entity.pojo.ZhuanJiaUser;
import com.cnooc.expert.system.operatelog.dto.LogBody;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import com.cnooc.expert.common.exception.BusinessException;
import javax.servlet.http.HttpServletRequest;
import java.util.*;

@Aspect
@Component
@Order(1)
@Slf4j
public class LogAspectj {
    private static final String EXCEPTION_CODE = "500";
    private String host="";

    @Value("${app.info.appId}")
    private String appId;
    @Value("${app.info.appName}")
    private String appName;

    @Autowired
    private KafkaProducerUtil kafkaProducerUtil;

    @Pointcut("execution(* com.cnooc.expert.controller.auth.*.*(..)) ||"+
            "execution(* com.cnooc.expert.controller.expert.*.*(..)) || " +
            "execution(* com.cnooc.expert.controller.portal.*.*(..)) || " +
            "execution(* com.cnooc.expert.controller.workflow.*.*(..))")
    public void loginLog() {
    }
    /**
     * 抛出异常后通知（@AfterThrowing）：方法抛出异常退出时执行的通知
     * 注意在这里不能使用ProceedingJoinPoint
     * 不然会报错ProceedingJoinPoint is only supported for around advice
     * throwing注解为错误信息
     *
     * @param joinPoint
     * @param ex
     */
    @AfterThrowing(value = "loginLog()", throwing = "ex")
    public void afterThrowingMethod(JoinPoint joinPoint, Exception ex) throws Exception {
        Map<String,String> resp = new HashMap<>();
        if (ex instanceof BusinessException) {
            BusinessException BusinessEx = (BusinessException) ex;
            resp.put("HttpCode", BusinessEx.getErrorCode()+"");
            resp.put("Message", BusinessEx.getMessage());
        }else {
            resp.put("HttpCode", EXCEPTION_CODE);
            resp.put("Message", ex.getMessage());
        }
        System.out.println("进入afterThrowingMethod方法=========");
        this.sendLog( resp);
    }
    /**
     * 返回后通知（@AfterReturning）：在某连接点（joinpoint）
     * 正常完成后执行的通知：例如，一个方法没有抛出任何异常，正常返回
     * 方法执行完毕之后
     * 注意在这里不能使用ProceedingJoinPoint
     * 不然会报错ProceedingJoinPoint is only supported for around advice
     * crmAspect()指向需要控制的方法
     * returning  注解返回值
     *
     * @param joinPoint
     * @param returnValue 返回值
     * @throws Exception
     */
    @AfterReturning(value = "loginLog()", returning = "returnValue")
    public void doAfterReturning(JoinPoint joinPoint, Object returnValue) throws Exception {
        System.out.println("进入doAfterReturning方法========");
        this.sendLog(returnValue);
    }
    /**
     * 获取当前的request
     * 这里如果报空指针异常是因为单独使用spring获取request
     * 需要在配置文件里添加监听
     * <listener>
     * <listener-class>
     * org.springframework.web.context.request.RequestContextListener
     * </listener-class>
     * </listener>
     *
     * @return
     */
    private HttpServletRequest getHttpServletRequest() {
        RequestAttributes ra = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes sra = (ServletRequestAttributes) ra;
        HttpServletRequest request = sra.getRequest();
        return request;
    }
    private ZhuanJiaUser getCurrentUser() {
        //这里需要添加代码
        ZhuanJiaUser zhuanJiaUser = UserUtils.getUserId();
        System.out.println(zhuanJiaUser);
        return zhuanJiaUser;
    }
    /**
     * mysql
     * 新增 processRecord
     *
     * @param returnValue
     */
    private void sendLog(Object returnValue) {
        try {
            System.out.println("进入sendLog方法========");
            HttpServletRequest httpServletRequest = getHttpServletRequest();
            String method = httpServletRequest.getMethod();
            ZhuanJiaUser zhuanJiaUser = getCurrentUser();

            if( zhuanJiaUser == null ){
                log.info("用户为空，不记录日志");
                return;
            }

            LogBody logBody = new LogBody();

            Enumeration<String> headers = httpServletRequest.getHeaderNames();
            List<String> headerList = Collections.list(headers);
            log.info("[sendLog]enter, headerList:{}", headerList);

            logBody.setOperationTs(System.currentTimeMillis());

            logBody.setRequestMethod(method);
            logBody.setIp(this.getRemoteIP(httpServletRequest));

            //请求路径：域名+路径
            logBody.setRequestPath(host+httpServletRequest.getRequestURI());

            if(null != returnValue && JSON.toJSONString(returnValue).length() > 5000){
                logBody.setResponseContent("返回消息体大于5000字符");
            }else {
                logBody.setResponseContent(JSON.toJSONString(returnValue));
            }

            logBody.setAppId(appId);
            logBody.setAppName(appName);
//          用户id
            logBody.setUserId(zhuanJiaUser.getZhuanJiaGuid());
//          用户account
            logBody.setAccount(zhuanJiaUser.getAdAccount());
//            部门id
//            logBody.setDomainId();
//          部门名称
            logBody.setDomainName(zhuanJiaUser.getSuoShuBuMeng());
//            logBody.setRole();
            logBody.setRequestPath(httpServletRequest.getRequestURI());
            String uuidKey = UUID.randomUUID().toString();
            logBody.setOperateRecordId(uuidKey);

            System.out.println("logBody对象信息如下=========");
            System.out.println(logBody);

            //将数据发送到kafka,这里需要加代码逻辑
//          Kafka默认异步发送（Topic、key需要提供，如果有key的话这样写：kafkaProducerUtil.sendMessage("test-topic（topic值）", "key的值",logBody); ）
            //kafkaProducerUtil.sendMessage("test-topic", logBody);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public String getRemoteIP(HttpServletRequest request) {
        if (request == null) {
            return "unknown";
        }
        String ip = request.getHeader("x-Original-Forwarded-For");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("x-real-ip");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("X-Real-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("X-Forwarded-For");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }

        ip = "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : ip;
        if (ip.indexOf(":") > 0) {
            ip = ip.substring(ip.lastIndexOf(":"));
        }
        if (ip.indexOf(",") > 0) {
            ip = ip.substring(0, ip.indexOf(",")).trim();
        }
        return ip;
    }

}
