package com.yfd.platform.system.service.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yfd.platform.annotation.Log;
import com.yfd.platform.system.domain.SysLog;
import com.yfd.platform.system.mapper.SysLogMapper;
import com.yfd.platform.system.service.ISysLogService;
import com.yfd.platform.utils.FileUtil;
import com.yfd.platform.utils.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.AnnotatedType;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * <p>
 * 系统操作日志 服务实现类
 * </p>
 *
 *
 * @since 2023-03-08
 */
@Service
public class SysLogServiceImpl extends ServiceImpl<SysLogMapper, SysLog> implements ISysLogService {

    @Resource
    private SysLogMapper sysLogMapper;

    /**********************************
     * 用途说明: 分页查询日志信息
     * 参数说明  pageNum(页码数)、pageSize（页大小，如果是固定页大小可不传）、username（用户名）、(optType)
     * 操作类型、startDate(开始日期)、endDate（结束日期）
     * 返回值说明: com.yfd.platform.config.ResponseResult 返回分页查询结果
     ***********************************/
    @Override
    public Page<SysLog> getLogList(String username, String optType, String requestip, String module, String type,
                                   String startDate,
                                   String endDate, String orderfield, Page<SysLog> page) {

        LambdaQueryWrapper<SysLog> queryWrapper = getQueryWrapper(username, optType, requestip, module, type,
                startDate, endDate, orderfield);
        //        sysLogMapper.getLogList(username, optType, requestip, module, type, startDate, endDate, orderfield);
        return sysLogMapper.selectPage(page, queryWrapper);
    }

    /**********************************
     * 用途说明: 导出日志数据
     * 参数说明  sysLogs  所需导出的字典项集合
     * 返回值说明: com.yfd.platform.config.ResponseResult 返回导出成功或者失败
     ***********************************/
    @Override
    public void exportExcel(String username, String optType,String requestip,String module,String type,
                            String startDate,
                            String endDate, String orderfield,
                            HttpServletResponse response) {
        try {
            LambdaQueryWrapper<SysLog> queryWrapper =getQueryWrapper(username,optType,requestip,module,type,startDate,endDate,orderfield);
            List<SysLog>  sysLogs=sysLogMapper.selectList(queryWrapper);
            List<Map<String, Object>> list = new LinkedList<>();
            for (SysLog sysLog : sysLogs) {
                Map<String, Object> map = new LinkedHashMap<>();
                map.put("操作账号", sysLog.getUsercode());
                map.put("用户姓名", sysLog.getUsername());
                map.put("IP地址", sysLog.getRequestip());
                map.put("浏览器", sysLog.getBrowser());
                map.put("日志类型", sysLog.getOpttype());
                map.put("模块名称", sysLog.getModule());
                map.put("日志描述", sysLog.getDescription());
                Timestamp logTime = sysLog.getLogtime();
                String dateTime = "";
                if (logTime != null) {
                    SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    dateTime = df.format(logTime);
                }
              map.put("操作日期", dateTime);
                list.add(map);
            }
            FileUtil.downloadExcel(list, response);
        } catch (Exception e) {
            log.error(e.getMessage());;
        }

    }

    //定义查询条件和排序字段
    private LambdaQueryWrapper<SysLog> getQueryWrapper(String username, String optType, String requestip,
                                                       String module, String type,
                                                       String startDate,
                                                       String endDate, String orderfield) {
        LambdaQueryWrapper<SysLog> queryWrapper = new LambdaQueryWrapper<>();
        // 没有传username就不按此条件查询
        if (StrUtil.isNotBlank(username)) {
            queryWrapper.like(SysLog::getUsername, username).or().like(SysLog::getUsercode, username);
        }
        //
        if (StrUtil.isNotBlank(requestip)) {
            queryWrapper.eq(SysLog::getRequestip, requestip);
        }
        //
        if (StrUtil.isNotBlank(module)) {
            queryWrapper.eq(SysLog::getModule, module);
        }
        if (StrUtil.isNotBlank(type)) {
            queryWrapper.eq(SysLog::getType, type);
        }
        //
        if (StrUtil.isNotBlank(optType)) {
            queryWrapper.eq(SysLog::getOpttype, optType);
        }

        if (StrUtil.isNotBlank(startDate) && StrUtil.isNotBlank(endDate)) {
            DateTime parseStartDate = DateUtil.parse(startDate);
            DateTime parseEndDate = DateUtil.parse(endDate);
            DateTime dateTime = DateUtil.offsetDay(parseEndDate, 1);
            queryWrapper.ge(SysLog::getLogtime, parseStartDate).lt(SysLog::getLogtime, dateTime);
        }
        if (StrUtil.isNotEmpty(orderfield)) {
            if (orderfield.equals("操作账号")) {
                queryWrapper.orderByDesc(SysLog::getUsercode);
            } else if (orderfield.equals("用户姓名")) {
                queryWrapper.orderByDesc(SysLog::getUsername);
            } else if (orderfield.equals("IP地址")) {
                queryWrapper.orderByDesc(SysLog::getRequestip);
            } else if (orderfield.equals("日志类型")) {
                queryWrapper.orderByDesc(SysLog::getOpttype);
            }else if(orderfield.equals("模块名称")){
                queryWrapper.orderByDesc(SysLog::getModule);
            }else if(orderfield.equals("操作时间")){
                queryWrapper.orderByDesc(SysLog::getLogtime);
            }
        }
        else{
            queryWrapper.orderByDesc(SysLog::getLogtime);
        }
        return queryWrapper;
    }

    /**********************************
     * 用途说明: 新增日志
     * 参数说明 nickname  用户名
     * 参数说明 username  用户账号
     * 参数说明 browser   浏览器
     * 参数说明 ip        本机Ip地址
     * 参数说明 joinPoint 连接点
     * 参数说明 log       日志信息
     * 返回值说明: void
     ***********************************/
    @Override
    public void save(String nickname, String username, String browser,
                     String ip,
                     ProceedingJoinPoint joinPoint, SysLog log) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        Log aopLog = method.getAnnotation(Log.class);
        // 方法路径
        String methodName =
                joinPoint.getTarget().getClass().getName() + "." + signature.getName() + "()";
        // 描述
        if (log != null) {
            log.setDescription(aopLog.value());
            log.setModule(aopLog.module());
            log.setType(aopLog.type());
        }
        assert log != null;
        log.setUsercode(username);
        log.setRequestip(ip);
        log.setMethod(methodName);
        log.setUsername(nickname);
        log.setParams(getParameter(method, joinPoint.getArgs()));
        log.setBrowser(browser);
        String operationtype = getOperationtype(signature.getName());
        log.setOpttype(operationtype);
        log.setLogtime(new Timestamp(System.currentTimeMillis()));
        sysLogMapper.insert(log);
    }

    @Override
    public void deleteLogs() {
        LambdaQueryWrapper<SysLog> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.lt(SysLog::getLogtime, DateUtil.offsetMonth(DateUtil.date(), -7));
        sysLogMapper.delete(queryWrapper);
    }

    /**
     * 根据方法和传入的参数获取请求参数
     */
    private String getParameter(Method method, Object[] args) {
        List<Object> argList = new ArrayList<>();
        Parameter[] parameters = method.getParameters();
        for (int i = 0; i < parameters.length; i++) {
            //将RequestBody注解修饰的参数作为请求参数
            AnnotatedType type = parameters[i].getAnnotatedType();

            RequestBody requestBody =
                    parameters[i].getAnnotation(RequestBody.class);
            if (requestBody != null) {
                argList.add(args[i]);
            }

            //将RequestParam注解修饰的参数作为请求参数
            RequestParam requestParam =
                    parameters[i].getAnnotation(RequestParam.class);
            if (requestParam != null) {
                Map<String, Object> map = new HashMap<>();
                String key = parameters[i].getName();
                if (!StringUtils.isEmpty(requestParam.value())) {
                    key = requestParam.value();
                }
                map.put(key, args[i]);
                argList.add(map);
            }
        }
        if (argList.size() == 0) {
            return "";
        }
        return argList.size() == 1 ? JSONUtil.toJsonStr(argList.get(0)) :
                JSONUtil.toJsonStr(argList);
    }

    public static String getOperationtype(String value) {
        String type = "";
        if (value.contains("get") || value.contains("select")) {
            type = "查询(select)";
        } else if (value.contains("add") || value.contains("insert")) {
            type = "添加(insert)";
        } else if (value.contains("update") || value.contains("upd") || value.contains("change") || value.contains("set")) {
            type = "修改(update)";
        } else if (value.contains("delete") || value.contains("del")) {
            type = "删除(delete)";
        } else if (value.contains("dowload")) {
            type = "下载(dowload)";
        } else if (value.contains("import")) {
            type = "导入(import)";
        } else if (value.contains("word")) {
            type = "word转pdf(wordToPdf)";
        } else {
            type = "其他(other)";
        }
        return type;
    }

}
