package com.njcn.serviceimpl.log;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

import javax.annotation.Resource;
import javax.security.auth.login.AccountException;
import javax.transaction.Transactional;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import com.njcn.enums.LogTypeEnum;
import com.njcn.mapper.configuration.DicDataMapper;
import com.njcn.mapper.configuration.SysMapper;
import com.njcn.mapper.log.UserLogDetailMapper;
import com.njcn.mapper.log.UserLogMapper;
import com.njcn.mapper.user.UserMapper;
import com.njcn.pojo.configuration.DicData;
import com.njcn.pojo.configuration.SysSet;
import com.njcn.pojo.log.UserLog;
import com.njcn.pojo.log.UserLogDetail;
import com.njcn.pojo.user.RoleGroup;
import com.njcn.service.configuration.DicDataService;
import com.njcn.service.log.UserLogDetailService;
import com.njcn.shiro.token.TokenManager;
import com.njcn.sso.pojo.user.User;
import com.njcn.utils.AppConfig;
import com.njcn.utils.PubUtils;
import com.njcn.utils.SendMail;
import com.njcn.utils.ThreeDes;
import com.njcn.utils.UserUtil;
import com.njcn.utils.redis.RedisCacheUtil;


@Service
public class UserLogDetailServiceImpl implements UserLogDetailService {
    private static final Logger logger = LoggerFactory.getLogger(UserLogDetailServiceImpl.class);

    @Autowired
    UserLogDetailMapper userLogDetailMapper;
    @Autowired
    DicDataService dataService;
    @Autowired
    UserLogMapper logMapper;
    @Autowired
    UserMapper userMapper;

    @Autowired
    UserUtil userUtil;
    @Autowired
    private AppConfig appConfig;
    @Resource
    SendMail sendmail;

    @Autowired
    private RedisCacheUtil redisCacheUtil;

    @Autowired
    private DicDataMapper dicDataMapper;

    @Autowired
    private SysMapper sysMapper;

    /**
     * 查询所有日志
     */

    @Override
    public List<List> getUserLog() {
        // TODO Auto-generated method stub
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        List<List> userLogList = new ArrayList<List>();
        List<UserLogDetail> details = userLogDetailMapper.getUserLog();
        if (details.isEmpty()) {
            return userLogList;
        } else {
            for (UserLogDetail detail : details) {
                List<String> temp = new ArrayList<String>();
                temp.add(detail.getUserLogIndex());
                temp.add(sdf.format(detail.getUpdateTime()));
                temp.add(detail.getName());
                temp.add(detail.getUserlogDescribe());
                temp.add(detail.getType());
                temp.add(detail.getIp());
                temp.add(detail.getLeval());
                userLogList.add(temp);
            }
        }
        return userLogList;
    }

    /***
     * dicName:用户新增、用户修改、用户删除、角色新增、角色修改、角色删除 等其他增删改
     *         当为查询时，统一为业务查询
     */
    @Transactional
    @Override
    public void getLog(String dicName, String result, String ip, String logType, int level) {  //增加异常处理
        try {
            saveUserLog(TokenManager.getToken().getUserIndex(), TokenManager.getToken().getLoginName(), dicName, result, appConfig.getSystemFlag(), ip, logType, level);
        } catch (AccountException e) {
            logger.error("保存用户操作日志记录异常，操作为：" + dicName + ",结果：" + result + ",异常为：" + e.toString());
        }
    }
    
    @Transactional
    @Override
    public void getLogSys(String dicName, String result, String ip, String logType, int level, String detail) {  //增加异常处理
        try {
            saveUserLogSys(TokenManager.getToken().getUserIndex(), TokenManager.getToken().getLoginName(), dicName, result, appConfig.getSystemFlag(), ip, logType, level, detail);
        } catch (AccountException e) {
            logger.error("保存用户操作日志记录异常，操作为：" + dicName + ",结果：" + result + ",异常为：" + e.toString());
        }
    }

    /**
     * 用户操作日记记录 --》只针对系统事件类型
     *
     * @param userIndex 用户索引
     * @param username  用户名
     * @param operate   操作内容
     * @param result    操作结果
     * @param system    系统类型
     * @param ip        操作用户的IP
     * @param logType   日志类型 business为业务类型 system为系统类型
     * @param level     严重度
     */
    @Override
    public void saveUserLog(String userIndex, String username, String operate, String result, String system, String ip, String logType, int level) throws AccountException {
        UserLog userLog = new UserLog();
        List<DicData> dicDatas;
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
        String businessLogFlag = PubUtils.readProperties(getClass().getClassLoader(),"java.properties").get("BUSINESS_LOG_FLAG").toString();
        if(businessLogFlag.equalsIgnoreCase("false")){
            //不输出业务日志 获取系统日志字典
            dicDatas = redisCacheUtil.getSystemEvents();
        }else{
            //获取业务类型的字典记录
            if (logType.equalsIgnoreCase(LogTypeEnum.BUSSINESS.toString())) {
                dicDatas = redisCacheUtil.getBusinessEvents();
            } else {
                dicDatas = redisCacheUtil.getSystemEvents();
            }
        }
        if (!CollectionUtils.isEmpty(dicDatas)) {
            try {
                String dicDataIndex = "";
                DicData dicDataTemp = null;
                for (DicData dicData : dicDatas) {
                    if (dicData.getDicName().equalsIgnoreCase(operate)) {
                        dicDataIndex = dicData.getDicIndex();
                        dicDataTemp = dicData;
                        break;
                    }
                }
                //判断数据字典是否有该类型，没有插入新的字典数据
                if (StringUtils.isEmpty(dicDataIndex)) {
                    dicDataIndex = insertNewDicData(dicDatas.get(0).getDicType(), operate, level);
                }
                //存在字典，但是严重度不符，更新严重度
                if (null != dicDataTemp && dicDataTemp.getDicLeave() != level) {
                    dicDataTemp.setDicLeave(level);
                    dicDataMapper.updateByPrimaryKeyBySql(dicDataTemp);
                }
                //根据字典索引，进行日志记录
                userLog.setUserLogIndex(UUID.randomUUID().toString());//日志guid
                userLog.setIp(ip);
                userLog.setUpdateTime(new Date());//添加日志的操作时间 默认为当前时间
                userLog.setUserIndex(userIndex);
                userLog.setType(dicDataIndex);
                userLog.setState(0);
                userLog.setSysType(system);
                userLog.setResult(result);
                String describe = "";
                RoleGroup role = userUtil.getRoleGroupByUserIndex(userIndex);
                describe += role.getRolegpDescription() + username + "在" + sdf.format(new Date()) + 
                		"在" + 	ip + "执行了" + operate+  ",结果为" + result;
                userLog.setDescribe(describe);
                Calendar c = Calendar.getInstance();
                c.setTime(new Date());
                c.add(Calendar.MONTH, -6);
                Date endTime = c.getTime();
                userLogDetailMapper.delExpireLog(endTime);
                logMapper.insert(userLog);
                //插入后，根据严重度判断是否发邮件
                if(level==2){
                    sendDangerousLog(userLog.getUserLogIndex());
                }
            } catch (Exception e) {
                logger.error("日志入库异常，异常为："+e.getMessage());
                throw new AccountException("插入" + operate + "日志操作异常");
            }
        } else {
            throw new AccountException("事件类型字典无数据");
        }
    }


    @Override
    public void saveUserLogSys(String userIndex, String username, String operate, String result, String system, String ip, String logType, int level, String detail) throws AccountException {
        UserLog userLog = new UserLog();
        List<DicData> dicDatas;
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
        String businessLogFlag = PubUtils.readProperties(getClass().getClassLoader(),"java.properties").get("BUSINESS_LOG_FLAG").toString();
        if(businessLogFlag.equalsIgnoreCase("false")){
            //不输出业务日志 获取系统日志字典
            dicDatas = redisCacheUtil.getSystemEvents();
        }else{
            //获取业务类型的字典记录
            if (logType.equalsIgnoreCase(LogTypeEnum.BUSSINESS.toString())) {
                dicDatas = redisCacheUtil.getBusinessEvents();
            } else {
                dicDatas = redisCacheUtil.getSystemEvents();
            }
        }
        if (!CollectionUtils.isEmpty(dicDatas)) {
            try {
                String dicDataIndex = "";
                DicData dicDataTemp = null;
                for (DicData dicData : dicDatas) {
                    if (dicData.getDicName().equalsIgnoreCase(operate)) {
                        dicDataIndex = dicData.getDicIndex();
                        dicDataTemp = dicData;
                        break;
                    }
                }
                //判断数据字典是否有该类型，没有插入新的字典数据
                if (StringUtils.isEmpty(dicDataIndex)) {
                    dicDataIndex = insertNewDicData(dicDatas.get(0).getDicType(), operate, level);
                }
                //存在字典，但是严重度不符，更新严重度
                if (null != dicDataTemp && dicDataTemp.getDicLeave() != level) {
                    dicDataTemp.setDicLeave(level);
                    dicDataMapper.updateByPrimaryKeyBySql(dicDataTemp);
                }
                //根据字典索引，进行日志记录
                userLog.setUserLogIndex(UUID.randomUUID().toString());//日志guid
                userLog.setIp(ip);
                userLog.setUpdateTime(new Date());//添加日志的操作时间 默认为当前时间
                userLog.setUserIndex(userIndex);
                userLog.setType(dicDataIndex);
                userLog.setState(0);
                userLog.setSysType(system);
                userLog.setResult(result);
                String describe = "";
                RoleGroup role = userUtil.getRoleGroupByUserIndex(userIndex);
                describe += role.getRolegpDescription() + username + "在" + sdf.format(new Date()) + 
                		"在" + 	ip + "执行了" + operate + "," + detail+  ",结果为" + result;
                userLog.setDescribe(describe);
                Calendar c = Calendar.getInstance();
                c.setTime(new Date());
                c.add(Calendar.MONTH, -6);
                Date endTime = c.getTime();
                userLogDetailMapper.delExpireLog(endTime);
                logMapper.insert(userLog);
                //插入后，根据严重度判断是否发邮件
                if(level==2){
                    sendDangerousLog(userLog.getUserLogIndex());
                }
            } catch (Exception e) {
                logger.error("日志入库异常，异常为："+e.getMessage());
                throw new AccountException("插入" + operate + "日志操作异常");
            }
        } else {
            throw new AccountException("事件类型字典无数据");
        }
    }


    /**
     * 严重的日志需要发送邮件
     * @param userLogIndex 严重日志的索引
     */
    private void sendDangerousLog(String userLogIndex) throws AccountException {
        UserLog userLog = new UserLog();
        userLog.setUserLogIndex(userLogIndex);
        User user =new User();
        userLog=logMapper.selectByPrimaryKey(userLog);

        if(null!=userLog){
            //不为空，则进行邮件发送，先获取邮箱地址
//            User user = userMapper.selectByIndex(userLog.getUserIndex());
//            String address = "";
//            if(user == null){
//                User usertmp = userMapper.selectByIndex("njcnsj");
//                address = usertmp.getEmail();
//            } else {
//                address = user.getEmail();
//            }
            user.setUserIndex(userLog.getUserIndex());
            user=userMapper.selectOne(user);
            String address="83944980@qq.com";
            try {
                sendmail.sendmail(address, userLog.getDescribe());
                //发送完邮件，更新邮件状态为已处理
//                userLog.setState(1);
//                logMapper.updateByPrimaryKey(userLog);
                saveUserLog(userLog.getUserIndex(), user.getLoginName(), "系统发送严重日志邮件", "成功", appConfig.getSystemFlag(), userLog.getIp(), LogTypeEnum.SYSTEM.toString(), 1);
            } catch (Exception e) {
                //发送邮件异常，提示邮箱连接超时异常日志入库
                saveUserLog(userLog.getUserIndex(), user.getLoginName(), "系统发送严重日志邮件，连接超时", "失败", appConfig.getSystemFlag(), userLog.getIp(), LogTypeEnum.SYSTEM.toString(), 1);
                logger.error(e.getMessage());
            }
        }

    }


    /**
     * 新增一个字典内容
     *
     * @param dicType 字典类型
     * @param operate 字典名称
     * @param level   严重度
     * @return 新建字典的索引
     */
    private String insertNewDicData(String dicType, String operate, int level) {
        //没有的话，先新增一个字典内容
        DicData dicData = new DicData();
        String dicDataIndex = UUID.randomUUID().toString();
        dicData.setDicIndex(dicDataIndex);
        dicData.setDicName(operate);
        dicData.setDicType(dicType);
        dicData.setDicNumber(dicDataMapper.selNumMax() + 1);
        dicData.setUpdateTime(new Date());
        dicData.setDicLeave(level);
        dicData.setState(1);//1为正常
        dicData.setTriphase(-1);
        dicData.setBackUp(operate.substring(0,2));
        dicData.setUserIndex("99434007-2253-4c42-8cc0-33d5e008ee10");
        dicDataMapper.insert(dicData);
        redisCacheUtil.clearDicData();
        redisCacheUtil.clearConData();
        return dicDataIndex;
    }


    @Override
    public List<List> getUserLogId(String username, String type, String name, Date startTime, Date endTime) {
        // TODO Auto-generated method stub
        List<UserLogDetail> result = new ArrayList<>();
        if (username == null) {
            username = "";
        }
//        username = "%" + username + "%";
        if (type == null) {
            type = "";
        }
        type = "%" + type + "%";
        if (name == null) {
            name = "";
        }
        name = "%" + name + "%";
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        List<List> userLogList = new ArrayList<List>();
        List<UserLogDetail> details = userLogDetailMapper.getUserLogId(username, type, name, startTime, endTime);
        if (details.isEmpty()) {
            return userLogList;
        } else {
            for (UserLogDetail detail : details) {
                List<String> temp = new ArrayList<String>();
                temp.add(detail.getUserLogIndex());
                temp.add(sdf.format(detail.getUpdateTime()));
                temp.add(detail.getUsername());
                temp.add(detail.getName());
                temp.add(detail.getUserlogDescribe());
                temp.add(detail.getType());
                temp.add(detail.getResult());
                temp.add(detail.getIp());
                temp.add(detail.getLeval());
                userLogList.add(temp);
            }
        }
        return userLogList;
    }

    /***
     * 统计事件类型
     */
    @Override
    public List<UserLogDetail> geteventtype(Date startTime, Date endTime) {
        List<UserLogDetail> result = new ArrayList<>();
        result = userLogDetailMapper.geteventtype(startTime, endTime);

        return result;
    }

    @Override
    public List<UserLogDetail> getdetailtype(Date startTime, Date endTime) {
        List<UserLogDetail> result = new ArrayList<>();
        result = userLogDetailMapper.getdetailtype(startTime, endTime);
        return result;
    }

    @Override
    public List<UserLogDetail> getUserStatistics(Date startTime, Date endTime) {
        List<UserLogDetail> result = new ArrayList<>();
        result = userLogDetailMapper.getUserStatistics(startTime, endTime);

        return result;
    }

    /***
     * 统计月份
     */
    @Override
    public List<UserLogDetail> getdetailmonth(Date startTime, Date endTime) {
        List<UserLogDetail> result = new ArrayList<>();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM");
        // 获取两个时间的之间的月份
        List<String> intervalTime = this.getIntervalTime(sdf.format(startTime), sdf.format(endTime));

        for (String month : intervalTime) {
            UserLogDetail inter = new UserLogDetail();
            inter.setMonth(month.substring(5));
            inter.setYear(month.substring(0, 4));
            // 从事件总汇表获取对应时间的所有事件数量
            Integer count = 0;

            count = userLogDetailMapper.getdetailmonth(month);

            if (null == count) {
                count = 0;
            }
            // 获取当前月的事件总数
            inter.setNum(count.longValue());
            result.add(inter);
        }

        return result;
    }

    /**
     * 根据用户选择的时间区间返回月份日期
     */
    public List<String> getIntervalTime(String startTime, String endTime) {
        List<String> times = new ArrayList<String>();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM");
        Date start = null;
        Date end = null;
        try {
            start = sdf.parse(startTime);
            end = sdf.parse(endTime);
        } catch (ParseException e) {
            logger.error("时间转化发生异常，异常是"+e.getMessage());
        }
        // 同月
        if (start.getTime() == end.getTime()) {
            String time = startTime.substring(0, 7);
            times.add(time);
        } else if (start.getYear() == end.getYear()) {
            // 同年
            int startM = start.getMonth() + 1;
            int endM = end.getMonth() + 1;
            int temp = endM - startM;
            for (int i = 0; i <= temp; i++) {
                String time = start.getYear() + 1900 + "";
                int month = startM + i;
                if (month < 10) {
                    time = time + "-0" + month;
                } else {
                    time = time + "-" + month;
                }
                times.add(time);
            }
        } else {
            // 不同年!!!!这里忽略了年份之间跨年的情况
            int startY = start.getYear() + 1900;
            int startM = start.getMonth() + 1;
            int endY = end.getYear() + 1900;
            int endM = end.getMonth() + 1;
            int tempS = 12 - startM;
            // 连续的年份
            if (endY - startY == 1) {
                // 第一年的时间获取
                for (int i = 0; i <= tempS; i++) {
                    int month = startM + i;
                    String time = startY + "-";
                    if (month < 10) {
                        time = time + "0" + month;
                    } else {
                        time = time + month;
                    }
                    times.add(time);
                }
                // 第二年的时间获取

                for (int i = 1; i <= endM; i++) {
                    String time = endY + "-";
                    if (i < 10) {
                        time = time + "0" + i;
                    } else {
                        time = time + i;
                    }
                    times.add(time);
                }
            } else {
                // 不连续的年份
                // 第一年的时间获取
                for (int i = 0; i <= tempS; i++) {
                    int month = startM + i;
                    String time = startY + "-";
                    if (month < 10) {
                        time = time + "0" + month;
                    } else {
                        time = time + month;
                    }
                    times.add(time);
                }
                int tempY = endY - startY;
                // 中间年份的时间
                for (int i = 1; i < tempY; i++) {
                    for (int j = 1; j <= 12; j++) {
                        String time = startY + i + "-";
                        if (j < 10) {
                            time = time + "0" + j;
                        } else {
                            time = time + j;
                        }
                        times.add(time);
                    }
                }
                // 最后一年的时间获取
                for (int i = 1; i <= endM; i++) {
                    String time = endY + "-";
                    if (i < 10) {
                        time = time + "0" + i;
                    } else {
                        time = time + i;
                    }
                    times.add(time);
                }
            }

        }
        return times;
    }

    /**
     * 查询报警日志
     */
    @Override
    public List<List> getWarnInfo(Long type) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        List<List> userLogList = new ArrayList<>();
        List<String> indexs = new ArrayList<>();
        List<UserLogDetail> details = userLogDetailMapper.getWarnInfo();
        if (details.isEmpty()) {
            return userLogList;
        } else {
            for (UserLogDetail detail : details) {
                List<String> temp = new ArrayList<>();
                temp.add(detail.getUserLogIndex());
                temp.add(sdf.format(detail.getUpdateTime()));
                temp.add(detail.getName());
                temp.add(detail.getUserlogDescribe());
                temp.add(detail.getType());
                temp.add(detail.getIp());
                temp.add(detail.getLeval());
                userLogList.add(temp);
                indexs.add(detail.getUserLogIndex());
            }
        }
        if (indexs.size() > 0) {
            userLogDetailMapper.changeState(indexs);
        }
        return userLogList;
    }

    /**
     * 查询报警日志
     */
    @Override
    public Integer getWarnInfoCounts(Long type) {
        List<UserLogDetail> details = userLogDetailMapper.getWarnInfo();
        if(CollectionUtils.isEmpty(details)){
            return 0;
        }
        return details.size();
    }



    /**
     * 获取userlog表存储空间
     */
    @Override
    public Integer getMemoInfo() {
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet;
        try {
            //读取配置文件
            Properties pros = PubUtils.readProperties(getClass().getClassLoader(),"jdbc.properties");
	        String driverClass = "oracle.jdbc.driver.OracleDriver";
	        String url = pros.get("oracle.jdbcUrl").toString();
	        String username = pros.get("oracle.user").toString();
	        username = ThreeDes.decryptThreeDes(username);
	        String pwd = pros.get("oracle.password").toString();
	        pwd = ThreeDes.decryptThreeDes(pwd);
	        Class.forName(driverClass);
	        connection = DriverManager.getConnection(url, username, pwd);
	        String sql = "analyze table PQS_USERLOG compute statistics";
	        preparedStatement = connection.prepareStatement(sql);
	        resultSet = preparedStatement.executeQuery();
		} catch (ClassNotFoundException | SQLException e) {
			logger.error(e.getMessage());
		}
        
        Float memo = userLogDetailMapper.getMemoInfo();
        List<SysSet> sys = sysMapper.selectAll();
        Integer logsize = sys.get(0).getLogSize();
        if (memo > logsize) {
            return logsize;
        } else {
            return null;
        }
    }

    @Override
    public List<List> getSjtj(String username, String type, String name, Date startTime, Date endTime) {
        // TODO Auto-generated method stub
        List<UserLogDetail> result = new ArrayList<>();
        if (username == null) {
            username = "";
        }
//        username = "%" + username + "%";
        if (type == null) {
            type = "";
        }
        type = "%" + type + "%";
        if (name == null) {
            name = "";
        }
        name = "%" + name + "%";
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        List<List> userLogList = new ArrayList<List>();
        List<UserLogDetail> details = userLogDetailMapper.getSjtj(username, type, name, startTime, endTime);
        if (details.isEmpty()) {
            return userLogList;
        } else {
            for (UserLogDetail detail : details) {
                List<String> temp = new ArrayList<String>();
                temp.add(detail.getUsername());
                temp.add(detail.getName());
                temp.add(detail.getNum().toString());
                userLogList.add(temp);
            }
        }
        return userLogList;
    }
    
    @Override
    public String updateSysSet(SysSet set){
    	String result = "";
    	
    	SysSet tmp = sysMapper.selectByPrimaryKey(set.getSysSetIndex());
    	if(!tmp.getLimitDate().equals(set.getLimitDate())){
    		result += "密码有效期改为" + String.valueOf(set.getLimitDate());
    	}
    	if(!tmp.getLimitTimes().equals(set.getLimitTimes())){
    		result += "密码错误次数改为" + String.valueOf(set.getLimitTimes());
    	}
    	if(!tmp.getLimitNumber().equals(set.getLimitNumber())){
    		result += "最大并发数改为" + String.valueOf(set.getLimitNumber());
    	}
    	if(!tmp.getLimitIdle().equals(set.getLimitIdle())){
    		result += "闲置用户修改密码改为" + String.valueOf(set.getLimitIdle());
    	}
    	if(!tmp.getLimitLogout().equals(set.getLimitLogout())){
    		result += "闲置用户注销改为" + String.valueOf(set.getLimitLogout());
    	}
    	if(!tmp.getCasualUserTime().equals(set.getCasualUserTime())){
    		result += "临时闲置用户注销改为" + String.valueOf(set.getCasualUserTime());
    	}
    	if(!tmp.getLogOutTime().equals(set.getLogOutTime())){
    		result += "休眠转注销改为" + String.valueOf(set.getLogOutTime());
    	}
    	if(!tmp.getLogSize().equals(set.getLogSize())){
    		result += "日志大小改为" + String.valueOf(set.getLogSize());
    	}
    	if(!tmp.getLockTime().equals(set.getLockTime())){
    		result += "用户锁定时长改为" + String.valueOf(set.getLockTime());
    	}
    	
    	sysMapper.updateByPrimaryKey(set);
    	
    	return result;
    }

}
