package com.yonge.toolset.log.interceptor;

import com.alibaba.fastjson.JSONObject;
import io.swagger.annotations.ApiOperation;

import java.io.IOException;
import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import com.yonge.toolset.log.dal.model.AuditLog;
import com.yonge.toolset.log.model.AuditLogAnnotation;
import com.yonge.toolset.log.service.AuditLogService;
import com.yonge.toolset.utils.json.JsonUtil;
import com.yonge.toolset.utils.web.WebUtil;

/**
 * 日志审计的拦截器
 */
public class AuditLogInterceptor extends HandlerInterceptorAdapter {
    private final static Logger log = LoggerFactory.getLogger(AuditLogInterceptor.class);

    @Autowired
    private AuditLogService auditLogService;

    @Value("${spring.application.name}")
    private String clientName;

    private String username;

    private Long userId;

    private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    private static List<String> ignoreLogUrl;

    /**
     * 异步线程池配置
     */
    @Bean("syncSaveLog")
    public Executor asyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // 设置核心线程数
        executor.setCorePoolSize(10);
        // 设置最大线程数
        executor.setMaxPoolSize(100);
        // 设置队列容量
        executor.setQueueCapacity(1000);
        // 设置线程活跃时间（秒）
        executor.setKeepAliveSeconds(60);
        // 设置默认线程名称
        executor.setThreadNamePrefix("syncSaveLog-");
        // 设置拒绝策略
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        // 等待所有任务结束后再关闭线程池
        executor.setWaitForTasksToCompleteOnShutdown(true);
        executor.initialize();
        return executor;
    }


    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws ServletException, IOException {
        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        syncSaveLog(request, handler);
    }

    public void syncSaveLog(HttpServletRequest request, Object handler) {

        try {
            String servletPath = request.getServletPath();
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            AuditLogAnnotation anno = handlerMethod.getMethodAnnotation(AuditLogAnnotation.class);
            ApiOperation apiOperation = handlerMethod.getMethodAnnotation(ApiOperation.class);
            String operateName = null;
            if (StringUtils.isEmpty(operateName) && apiOperation != null) {
                operateName = apiOperation.value();
            }
            if (StringUtils.isEmpty(operateName) && anno != null) {
                operateName = anno.operateName();
            }
            if (anno != null) {
                saveLog(operateName, servletPath, request);
                return;
            }
            if (servletPath.contains("/task/") || servletPath.contains("/import/")) {
                return;
            }
            String substring = servletPath.substring(servletPath.lastIndexOf("/") + 1).toLowerCase();
            if (ignoreLogUrl == null) {
                ignoreLogUrl = new ArrayList<>();
                ignoreLogUrl.add("query");
                ignoreLogUrl.add("get");
                ignoreLogUrl.add("find");
                ignoreLogUrl.add("list");
                ignoreLogUrl.add("detail");
                ignoreLogUrl.add("hasindexerrdata");
                ignoreLogUrl.add("newindex");
            }
            for (String e : ignoreLogUrl) {
                if (substring.contains(e)) {
                    return;
                }
            }
            //saveLog(operateName, servletPath, request);
        } catch (Exception e) {
            String servletPath = request.getServletPath();
            log.error("日志记录异常： servletPath is {}，handler is {}", servletPath, handler);
            e.printStackTrace();
        }
    }

    private void saveLog(String operateName, String servletPath, HttpServletRequest request) throws IOException {
        AuditLog auditLog = new AuditLog();
        auditLog.setOperateName(operateName);
        auditLog.setInterfaceUrl(servletPath);
        auditLog.setToken(request.getHeader("Authorization"));
        auditLog.setService(clientName);
        auditLog.setUserIp(WebUtil.getRemoteIp(request));

        Map<String, Object> params = WebUtil.getParameterMap(request);
        if (params == null || params.size() == 0) {
            auditLog.setInputParams(IOUtils.toString(request.getInputStream(), Charset.defaultCharset()));
        } else {
            auditLog.setInputParams(JsonUtil.toJSONString(WebUtil.getParameterMap(request)));
        }
        // 操作人
        auditLog.setUsername(username);
        auditLog.setUserId(userId);
        auditLog.setOperateTime(sdf.format(new Date()));
        //auditLogService.insert(auditLog);
    }

    public void setUsername(String username, Long userId) {
        this.username = username;
        this.userId = userId;
    }
}
