package com.github.wxiaoqi.security.common.log.Impl;

import com.alibaba.fastjson.JSON;
import com.github.wxiaoqi.security.common.log.CommonLogService;
import com.github.wxiaoqi.security.common.log.entity.LogEntity;
import com.github.wxiaoqi.security.common.log.entity.XxLogEntity;
import com.github.wxiaoqi.security.common.msg.BaseResponse;
import com.github.wxiaoqi.security.common.msg.ObjectRestResponse;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.PostMapping;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

@Service
public class CommonLogServiceImpl implements CommonLogService {

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

    // 获取当前cpu个数
    private static int  corePoolSize = Runtime.getRuntime().availableProcessors();
    // 设置任务队列，长度无限制
    private static BlockingQueue blockingQueue=new LinkedBlockingQueue<>();
    // 定义线程池，初始化线程数为cpu个数，最大线程数为cpu个数*2， 档队列类型为LinkedBlockingQueue，maximumPoolSize 参数无效
    private static ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(corePoolSize,  corePoolSize*2,  60L, TimeUnit.SECONDS, blockingQueue);

    @Autowired
    private MongoTemplate mongoTemplate;


    @Override
    public void log(LogEntity logEntity){
        threadPoolExecutor.execute(
                new SycnLog(logEntity)
        );
    }

    class SycnLog implements Runnable {

        private LogEntity logEntity;
        public SycnLog() {
            super();
        }

        public SycnLog(LogEntity logEntity) {
            super();
            this.logEntity = logEntity;
        }
        @Override
        public void run() {
            mongoTemplate.insert(logEntity);
        }
    }

    @Override
    public void commonLog(XxLogEntity xxLogEntity){
        threadPoolExecutor.execute(
                new SycnCommonLog(xxLogEntity)
        );
    }

    class SycnCommonLog implements Runnable {

        private XxLogEntity xxLogEntity;

        public SycnCommonLog() {
            super();
        }

        public SycnCommonLog(XxLogEntity xxLogEntity) {
            super();
            this.xxLogEntity = xxLogEntity;
        }
        @Override
        public void run() {
            mongoTemplate.insert(xxLogEntity, xxLogEntity.getMongoKey());
        }
    }

    @Override
    public void initCommonLogPrePart(XxLogEntity xxLogEntity, HttpServletRequest request, ProceedingJoinPoint pjp) {
        //request 获得头部
        xxLogEntity.setApp(request.getHeader("app"));
        LocalDateTime startTime= LocalDateTime.now();//开始时间
        xxLogEntity.setCreateDate(startTime.toString());
        xxLogEntity.setServletPath(request.getServletPath());
        MethodSignature signature = (MethodSignature) pjp.getSignature();
        xxLogEntity.setMethod(signature.getMethod().toString());
        xxLogEntity.setMongoKey(applicationName + ":" + request.getServletPath());
    }

    @Override
    public void initCommonLogLastPart(XxLogEntity xxLogEntity, Object result) {
        initCommonLogLastPart(xxLogEntity, JSON.toJSONString(result));
    }

    @Override
    public void initCommonLogLastPart(XxLogEntity xxLogEntity, String result) {
        LocalDateTime endTime = LocalDateTime.now();//结束时间
        xxLogEntity.setEndDate(endTime.toString());
        xxLogEntity.setResponseData(result);
    }

    @Override
    public void initFeignClientLogPrePart(XxLogEntity xxLogEntity, Method targetMethod) {
        PostMapping postMapping = targetMethod.getAnnotation(PostMapping.class);
        String header = postMapping.headers()[0];
        xxLogEntity.setApp(header.substring(header.lastIndexOf("app=") + 4, header.length()));
        LocalDateTime startTime= LocalDateTime.now();//开始时间
        xxLogEntity.setCreateDate(startTime.toString());
        xxLogEntity.setServletPath(postMapping.value()[0]);
        xxLogEntity.setMongoKey(applicationName + ":" + "feignClient");
    }

    @Override
    public void initMqLogPrePart(XxLogEntity xxLogEntity, Method targetMethod) {
        PostMapping postMapping = targetMethod.getAnnotation(PostMapping.class);
        String header = postMapping.headers()[0];
        LocalDateTime startTime= LocalDateTime.now();//开始时间
        xxLogEntity.setCreateDate(startTime.toString());
        xxLogEntity.setServletPath(postMapping.value()[0]);
        xxLogEntity.setMongoKey(applicationName + ":" + "mqSender");
    }
}
