package com.chinaweal.aiccs.common.util;

import com.chinaweal.aiccs.common.base.controller.BaseController;
import com.chinaweal.aiccs.common.constant.Constant;
import com.chinaweal.aiccs.common.enums.OpPositionEnum;
import com.chinaweal.aiccs.org.entity.TOperationLog;
import com.chinaweal.aiccs.org.service.TOperationLogService;
import com.chinaweal.aicorg.model.AICUser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
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.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.UUID;

/**
 * 操作日志工具类
 * 使用demo：
 * OpLogUtil.selectLog(OpPositionEnum.LOGIN, MapUtils.createMap("userName", userName).add("password", password).build());
 * @author <a href="https://blog.lroyia.top">lroyia</a>
 * @since 2021/3/23 16:44
 **/
@Slf4j
@Component
public class OpLogUtil {

    private static OpLogUtil OP_LOGGER;

    /**操作类型（查询）**/
    private static final String LOG_TYPE_SELECT = "0";
    /**操作类型（插入/修改）**/
    private static final String LOG_TYPE_MODIFY = "1";
    /**操作类型（删除）**/
    private static final String LOG_TYPE_DELETE = "2";

    @Autowired
    private TOperationLogService operationLogService;

    @PostConstruct
    public void init(){
        OP_LOGGER = this;
    }

    /**
     * 《查询》操作日志
     * 使用demo：
     * OpLogUtil.selectLog(OpPositionEnum.LOGIN, MapUtils.createMap("userName", userName).add("password", password).build());
     * @param position  查询位置
     * @param params    查询参数
     * @param operatorId    操作人id
     * @param operatorIp    操作人ip
     * @author lroyia
     * @since 2021年3月25日 10:15:28
     */
    public static void selectLog(OpPositionEnum position, Object params, String operatorId, String operatorIp){
        saveLog(position, LOG_TYPE_SELECT, params, operatorId, operatorIp);
    }

    /**
     * 《查询》操作日志
     * @param position  查询位置
     * @param params    查询参数
     * @author lroyia
     * @since 2021年3月25日 10:15:28
     */
    public static void selectLog(OpPositionEnum position, Object params){
        OperatorMsg msg = getCurrentUserMsg();
        selectLog(position, params, msg.getOperatorPk(), msg.getOperatorIp());
    }

    /**
     * 《修改/插入》操作日志
     * @param position  修改位置
     * @param params    修改参数
     * @param operatorId    操作人id
     * @param operatorIp    操作人ip
     * @author lroyia
     * @since 2021年3月25日 10:15:28
     */
    public static void modifyLog(OpPositionEnum position, Object params, String operatorId, String operatorIp){
        saveLog(position, LOG_TYPE_MODIFY, params, operatorId, operatorIp);
    }

    /**
     * 《修改/插入》操作日志
     * @param position  修改/插入位置
     * @param params    修改/插入参数
     * @author lroyia
     * @since 2021年3月25日 10:15:28
     */
    public static void modifyLog(OpPositionEnum position, Object params){
        OperatorMsg msg = getCurrentUserMsg();
        modifyLog(position, params, msg.getOperatorPk(), msg.getOperatorIp());
    }

    /**
     * 删除操作日志
     * @param position  处理位置
     * @param params    参数
     * @param operatorId    操作人id
     * @param operatorIp    操作ip
     * @author lroyia
     * @since 2021年3月25日 10:12:26
     */
    public static void deleteLog(OpPositionEnum position, Object params, String operatorId, String operatorIp){
        saveLog(position, LOG_TYPE_DELETE, params, operatorId, operatorIp);
    }

    /**
     * 删除操作日志
     * @param position  处理位置
     * @param params    参数
     * @author lroyia
     * @since 2021年3月25日 10:12:26
     */
    public static void deleteLog(OpPositionEnum position, Object params){
        OperatorMsg msg = getCurrentUserMsg();
        deleteLog(position, params, msg.getOperatorPk(), msg.getOperatorIp());
    }



    /**
     * 保存日志
     * @param position  操作位置标识枚举
     * @param operateType   操作类型
     * @param params    操作参数
     * @param operator  操作人
     * @param ip    操作ip
     * @author lroyia
     * @since 2021年3月23日 19:49:16
     */
    private static void saveLog(OpPositionEnum position, String operateType, Object params, String operator, String ip){
        String uuid = UUID.randomUUID().toString().replace(Constant.LINE, StringUtils.EMPTY);
        String paramJson;
        if(params == null){
            paramJson = StringUtils.EMPTY;
        }else{
            try {
                paramJson = new ObjectMapper().writeValueAsString(params);
            } catch (JsonProcessingException e) {
                log.error("参数json转换失败，日志id：{}，参数：{}", uuid, params, e);
                paramJson = params.toString();
            }
        }
        OP_LOGGER.operationLogService.save(new TOperationLog()
                .setCreateTime(LocalDateTime.now())
                .setLogId(uuid)
                .setOperateType(operateType)
                .setOperatorIp(ip)
                .setOperator(operator)
                .setParamsJson(paramJson)
                .setPositionCode(position.getCode())
                .setPositionName(position.getDesc()));
        String typeName = LOG_TYPE_SELECT.equals(operateType) ? "查询" : (LOG_TYPE_MODIFY.equals(operateType) ? "插入/修改" : "删除");
        log.info("{}操作日志保存成功，id：{}，参数：{}，操作人：{}", typeName, uuid, paramJson, operator);
    }


    /**
     * 通过spring上下文获取当前用户信息
     * @return  用户信息
     * @author lroyia
     * @since 2021年3月25日 09:57:58
     */
    private static OperatorMsg getCurrentUserMsg(){
        try{
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
            String pk = StringUtils.EMPTY;
            AICUser loginUser = BaseController.getLoginUser(request);
            if(loginUser != null){
                pk = loginUser.getPrimaryKey();
            }
            return new OperatorMsg(pk, getIpAddress(request));
        }catch (Exception e){
            log.error("获取request失败", e);
            return OperatorMsg.EMPTY_INFO;
        }
    }

    /**
     * 获取ip地址
     * @param request 请求
     * @return 获取结果
     * @since 2021年3月25日 09:57:12
     */
    public static String getIpAddress(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.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }

    /**
     * 操作人信息
     */
    @Getter
    @AllArgsConstructor
    static class OperatorMsg{

        /**
         * 操作人主键
         */
        private final String operatorPk;

        /**
         *  操作人ip
         */
        private final String operatorIp;

        /**
         * 空信息
         */
        final static OperatorMsg EMPTY_INFO = new OperatorMsg(StringUtils.EMPTY, StringUtils.EMPTY);
    }


}
