package com.bonus.system.service.impl;

import com.bonus.common.core.domain.R;
import com.bonus.common.core.utils.DateUtils;
import com.bonus.common.core.utils.StringUtils;
import com.bonus.common.core.utils.global.SystemGlobal;
import com.bonus.common.core.utils.ip.IpUtils;
import com.bonus.common.core.utils.uuid.IdUtils;
import com.bonus.common.core.web.domain.AjaxResult;
import com.bonus.common.security.utils.SecurityUtils;
import com.bonus.system.api.domain.SysLogsVo;
import com.bonus.system.api.model.LoginUser;
import com.bonus.system.mapper.SysLogMapper;
import com.bonus.system.service.ISysLogService;
import com.bonus.system.warning.SysWarning;
import com.bonus.system.warning.WaringLogEvent;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author：cwchen
 * @date：2024-02-28-14:02
 * @version：1.0
 * @description：系统日志-业务逻辑层
 */
@Service(value = "ISysLogService")
@Slf4j
public class SysLogServiceImpl implements ISysLogService {

    @Value("${sql.schemaName}")
    private String schemaName;

    @Resource(name = "SysLogMapper")
    private SysLogMapper mapper;

    @Autowired
    private ApplicationEventPublisher eventPublisher;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult saveLogs(SysLogsVo sysLog) {
        try {

            //如果是异常日志
            if(SystemGlobal.LOG_ERR.equals(sysLog.getErrType()) && StringUtils.isEmpty(sysLog.getModel())) {
                SysLogsVo  sysLog1=mapper.getModule(sysLog.getOperUri());
                if(sysLog1!=null){
                    sysLog.setModel(sysLog1.getModel());
                    sysLog.setOperateDetail(sysLog1.getOperateDetail());
                }else {
                    if(StringUtils.isEmpty(sysLog1.getModel())){
                        sysLog.setModel("未知的请求模块");
                    }
                }
            }
            if (sysLog.getLogType() == 2) {
                sysLog.setWarningStatus("0");
            }
            if (sysLog.getOperaUserName() != null) {
                String str = sysLog.getOperaUserName().replace("\\", "\\\\").replace("%", "\\%").replace("_", "\\_");
                sysLog.setOperaUserName(str);
            }
            if (sysLog.getIp() != null) {
                String str = sysLog.getIp().replace("\\", "\\\\").replace("%", "\\%").replace("_", "\\_");
                sysLog.setIp(str);
            }
            mapper.saveLogs(sysLog);
            if (sysLog.getLogType() == 2) {
                eventPublisher.publishEvent(new WaringLogEvent(new SysWarning(sysLog.getLogId(),sysLog.getErrType() ,sysLog.getIp(),sysLog.getOperaUserName(),sysLog.getOperTime(),"0")));
            }
        } catch (Exception e) {
            log.error("保存系统日志");
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        }
        return null;
    }

    @Override
    public void saveLogs(SysLogsVo sysLog, HttpServletRequest request) {
            try{
                String loginUuid = IdUtils.fastUUID();
                String ip = IpUtils.getIpAddr(request);
                sysLog.setIp(ip);
                sysLog.setLogId(loginUuid);
                sysLog.setGrade("高");
                sysLog.setErrType("越权访问");
                sysLog.setFailureReason("页面未授权");
                sysLog.setOperType("查询");
                sysLog.setOperateDetail("查看页面");
                String module=mapper.getModuleName(sysLog);
                sysLog.setLogType(2);
                sysLog.setResult("失败");
                sysLog.setOperTime(DateUtils.getTime());
                sysLog.setModel(module);
                LoginUser user= SecurityUtils.getLoginUser();
                sysLog.setUserId(String.valueOf(user.getUserid()));
                sysLog.setOperaUserName(user.getUsername());

                String modules=mapper.getModuleIsc(sysLog);
                if(StringUtils.isNotEmpty(module)){
                    if(StringUtils.isEmpty(module)){
                        sysLog.setModel(modules);
                    }
                }
                if (sysLog.getLogType() == 2) {
                    sysLog.setWarningStatus("0");
                }
                if (sysLog.getOperaUserName() != null) {
                    String str = sysLog.getOperaUserName().replace("\\", "\\\\").replace("%", "\\%").replace("_", "\\_");
                    sysLog.setOperaUserName(str);
                }
                if (sysLog.getIp() != null) {
                    String str = sysLog.getIp().replace("\\", "\\\\").replace("%", "\\%").replace("_", "\\_");
                    sysLog.setIp(str);
                }
                mapper.saveLogs(sysLog);
                if (sysLog.getLogType() == 2) {
                    eventPublisher.publishEvent(new WaringLogEvent(new SysWarning(loginUuid, "越权访问", ip, user.getUsername(), DateUtils.getTime(),"0")));
                }
            }catch (Exception e){
                log.error(e.toString(),e);
            }
    }

    @Override
    public List<SysLogsVo> getSystemLogs(SysLogsVo dto) {
     try{
         if (StringUtils.isEmpty(dto.getOperTime())) {
              dto.setStartTime(DateUtils.dateTimeNow());
              dto.setEndTime(DateUtils.dateTimeNow());
         }else {
             dto.setStartTime(dto.getOperTime().split(" - ")[0].trim());
             dto.setEndTime(dto.getOperTime().split(" - ")[1].trim());
         }
         return mapper.getSystemLogs(dto);
     }catch (Exception e){
         log.error(e.toString(),e);
     }
         return new ArrayList<>();
    }

    /**
     *
     * @return
     */
    @Override
    public R<String> getLogsSet() {
        try{
            String capacity=mapper.getLogsSet();
            if(StringUtils.isEmpty(capacity)){
                return R.ok("1");
            }
            return R.ok(capacity);
        }catch (Exception e){
            log.error(e.toString(),e);
        }
        return  R.ok(SystemGlobal.LOG_DEFEAT_SIZE+"");
    }

    /**
     * 系统日志 调试
     * @param capacity
     * @return
     */
    @Override
    public R<String> setLogsSet(String capacity) {
        try{
            if(StringUtils.isNotEmpty(capacity)){
                if(SystemGlobal.ERR_NUM.equals(capacity.toUpperCase())){
                    return R.fail("请输入数字");
                }
            }else{
                return R.fail("日志容量最低是"+SystemGlobal.LOG_DEFEAT_SIZE+"GB");
            }

            Double cap=Double.parseDouble(capacity);
            if(cap<SystemGlobal.LOG_DEFEAT_SIZE){
                return R.fail("日志容量最低是"+SystemGlobal.LOG_DEFEAT_SIZE+"GB");
            }
        }catch (Exception e){
            log.error(e.toString(),e);
            return R.fail("请输入数字");
        }
        try{
            String city=mapper.getLogsSet();
            if(StringUtils.isEmpty(city)){
                 mapper.setLogsSet(capacity);
            }else {
                mapper.updateLogsSet(capacity);
            }
        }catch (Exception e){
            log.error(e.toString(),e);
            return R.fail("系统异常");
        }
        return R.ok("设置成功","设置成功");
    }
     public  final static   String SUCCESS="成功";
    /**
     * @param dto
     * @return
     */
    @Override
    public R<Map<String, Object>> getLogStatistics(SysLogsVo dto) {
        Map<String,Object> map= Maps.newHashMap();
       try{
           if(StringUtils.isNotEmpty(dto.getOperTime())){
               dto.setStartTime(dto.getOperTime().split(" - ")[0].trim());
               dto.setEndTime(dto.getOperTime().split(" - ")[1].trim());
           }
            List<SysLogsVo> all=mapper.getAllLogs(dto);
           //先按操作结果查询
           if(StringUtils.isNotEmpty(all)){
               int allNum= all.stream().mapToInt(SysLogsVo::getNum).sum();
               map.put("allNum",allNum);
               all.forEach(vo->{
                   if(vo.getResult().contains("成功")){
                       map.put("sNum",vo.getNum());
                   }else {
                       map.put("eNum",vo.getNum());
                   }
               });
           }

           if (SystemGlobal.LOG_TYPE.equals(dto.getType())){
               //按日志类型查询
               List<Integer> type=new ArrayList<>();
               List<String> typeList=new ArrayList<>();
               typeList.add("系统日志");typeList.add("业务日志");typeList.add("异常日志");
               type.add(0);type.add(1);type.add(2);
               List<Integer> nums=new ArrayList<>();
               type.forEach(str->{
                   dto.setLogType(str);
                   int num=mapper.getLogStatistics(dto);
                   nums.add(num);
               });
               map.put("list",typeList);
               map.put("nums",nums);
           }else if("2".equals(dto.getType())){
               //按操作类型查询
               List<String> typeList=new ArrayList<>();
               List<Integer> nums=new ArrayList<>();
               List<SysLogsVo> list=mapper.getLogsListByOperType(dto);
               list.forEach(vo->{
                   typeList.add(vo.getOperType());
                   nums.add(vo.getNum());
               });
               map.put("list",typeList);
               map.put("nums",nums);
           }else if ("3".equals(dto.getType())){
               List<String> typeList=new ArrayList<>();
               List<Integer> nums=new ArrayList<>();
               List<SysLogsVo> list=mapper.getLogsListByOperUserName(dto);
               list.forEach(vo->{
                   typeList.add(vo.getOperaUserName());
                   nums.add(vo.getNum());
               });
               map.put("list",typeList);
               map.put("nums",nums);
           }
           return  R.ok(map);
           }catch (Exception e){
             log.error(e.toString(),e);
         }
        return  R.ok(map);
    }

    /**
     * 日志容量告警
     * @return
     */
    @Override
    public void logWarn() {
        try {
            double bfb=0.9;
            String rl=mapper.getLogsRl(schemaName);
            String city=mapper.getLogsSet();
            Double d=Double.parseDouble(rl);
            Double max=Double.parseDouble(city)*bfb;
            if(d>=max){
                String warningEvent = "日志容量告警,当日日志内存为" +d+ "GB,日志内存超过总内存的90%,请及时处理!";
                eventPublisher.publishEvent(new WaringLogEvent(new SysWarning("0",warningEvent,"",null,null, "1")));
            }
        }catch (Exception e){
            log.error(e.toString(),e);
        }
    }

    @Override
    @Async
    public void handleWarningLog(){
        List<SysLogsVo> list = mapper.getNotHandleWarningLog();
        // 使用for-each循环遍历List
        for (SysLogsVo item : list) {
            eventPublisher.publishEvent(new WaringLogEvent(new SysWarning(item.getLogId(),item.getErrType(), item.getIp(),item.getOperaUserName(),item.getOperTime(),"0")));
            log.info("*****系统管理员和审计管理员处理异常日志*******");
        }
    }

    @Override
    @Async
    public void updateLogsWithHandledStatus(String logId){
        mapper.updateLogsWithHandledStatus(logId);
    }

}
