package com.foreverwin.mesnac.common.aspect;

import cn.hutool.core.exceptions.ExceptionUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.foreverwin.mesnac.common.constant.SystemRuleConstant;
import com.foreverwin.mesnac.common.model.HttpLog;
import com.foreverwin.mesnac.common.model.SystemRule;
import com.foreverwin.mesnac.common.service.HttpLogService;
import com.foreverwin.mesnac.common.service.SystemRuleService;
import com.foreverwin.modular.core.util.CommonMethods;
import com.foreverwin.modular.core.util.R;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.UUID;

/**
 *  controller操作拦截记录日志
 * @author Syngna
 * @since 2020-01-13
 */
//@Aspect
@Component
public class HttpLogAspect {

    @Autowired
    ObjectMapper objectMapper;

    @Autowired
    HttpLogService httpLogService;

    @Autowired
    SystemRuleService systemRuleService;

    @Pointcut("@within(org.springframework.web.bind.annotation.RestController)")
    public void log() {

    }

    @Around("log()")
    public Object doLog(ProceedingJoinPoint joinPoint) throws Throwable {
        String site = CommonMethods.getSite();
        String user = CommonMethods.getUser();
        String httpLogRetentionPeriod = SystemRuleConstant.DEFAULT_HTTP_LOG_RETENTION_PERIOD;

        //记录起始时间
        long begin = System.currentTimeMillis();

        String localAddr = null;
        String url = null;
        String method = null;
        String classMethod = null;
        JSONArray paramList = new JSONArray();
        String exception = null;
        Object result = "";
        long runTime = 0;

        /** 执行目标方法 */
        try {
            //日志保留时间（天）
            SystemRule httpLogRetentionPeriodRule = systemRuleService.selectOneBySiteNameGroup(site, SystemRuleConstant.HTTP_LOG_RETENTION_PERIOD, SystemRuleConstant.RULE_GROUP_ME_SYSTEM);
            if(httpLogRetentionPeriodRule != null){
                httpLogRetentionPeriod = httpLogRetentionPeriodRule.getRuleValue();
            }

            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = attributes.getRequest();
            localAddr = getIpAddr(request);
            url = request.getRequestURL().toString();
            method = request.getMethod();
            classMethod = joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName();

            Object[] args = joinPoint.getArgs();
            MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
            String[] paramNames = methodSignature.getParameterNames();
            for (int i = 0; i < args.length; i++) {
                JSONObject param = new JSONObject();
                JSONObject paramValue = null;
                try{
                    paramValue = JSONObject.parseObject(objectMapper.writeValueAsString(args[i]));
                    param.put(paramNames[i], paramValue);
                }catch (Exception e){
                    param.put(paramNames[i], args[i]);
                }
                paramList.add(param);
            }

            result = joinPoint.proceed();

            /** 记录操作时间 */
            runTime = System.currentTimeMillis() - begin;
        } catch (Exception e) {
            runTime = System.currentTimeMillis() - begin;
            exception = ExceptionUtil.stacktraceToString(e);
            result = R.failed(e.getMessage());
            throw e;
        } finally {
            //清理日志
            QueryWrapper<HttpLog> queryWrapper = new QueryWrapper<>();
            queryWrapper.and(wrapper -> wrapper.eq(HttpLog.SITE, site).or().isNull(HttpLog.SITE).or().eq(HttpLog.SITE, "null"));
            queryWrapper.le(HttpLog.CREATED_DATE_TIME, LocalDateTime.now().minusDays(Long.valueOf(httpLogRetentionPeriod)));
            httpLogService.remove(queryWrapper);

            //记录日志
            HttpLog httpLog = new HttpLog();
            httpLog.setHandle(UUID.randomUUID().toString());
            httpLog.setSite(site);
            httpLog.setLocalAddr(localAddr);
            httpLog.setUrl(url);
            httpLog.setMethod(method);
            httpLog.setClassMethod(classMethod);
            httpLog.setParamList(paramList.toString());
            httpLog.setError(exception);
            httpLog.setResults(objectMapper.writeValueAsString(result));
            httpLog.setRunTime(runTime);
            httpLog.setCreateUser(user);
            httpLog.setCreatedDateTime(LocalDateTime.now());
            httpLogService.save(httpLog);
        }

        return result;
    }

    @After("log()")
    public void doAfter(JoinPoint joinPoint) {

    }

    public String getIpAddr(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        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.getRemoteAddr();
        }
        return ip;
    }
}