package com.pqs9900.controller.configuration;

import cn.hutool.core.io.FileUtil;
import com.njcn.enums.LogTypeEnum;
import com.njcn.pojo.commons.DatePojo;
import com.njcn.pojo.commons.HttpResult;
import com.njcn.pojo.commons.RedisDB;
import com.njcn.pojo.commons.WaveData;
import com.njcn.pojo.configuration.Line;
import com.njcn.service.commons.IWaveService;
import com.njcn.service.configuration.DeviceService;
import com.njcn.service.configuration.LineService;
import com.njcn.service.data.EventDetailService;
import com.njcn.service.log.UserLogDetailService;
import com.njcn.shiro.cache.VCache;
import com.njcn.shiro.token.TokenManager;
import com.njcn.utils.AppConfig;
import com.njcn.utils.PubUtils;
import com.njcn.utils.ZipUtils;
import com.njcn.utils.redis.JedisManager;
import com.pqs9900.service.DataInfo.DownEventService;
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.*;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.zip.ZipOutputStream;


/**
 * @author hongawen
 * @Date: 2018/11/5 19:32
 */
@Controller
@RequestMapping("offdata")
public class OffDataController {

    private static final Logger logger = LoggerFactory.getLogger(OffDataController.class);

    @Autowired
    private EventDetailService eventDetailService;

    @Autowired
    private JedisManager jedisManager;

    static VCache cache;

    @Autowired
    private AppConfig appConfig;

    @Autowired
    private DeviceService deviceService;

    @Autowired
    private LineService lineService;

    @Autowired
    private IWaveService waveService;

    @Autowired
    private DownEventService downEventService;

    @Autowired
    private UserLogDetailService userLog;


    /**
     * 准备离线数据，包括基础配置数据以及日志数据、波形文件数据
     *
     * @param startTime 起始时间
     * @param endTime   截止时间
     * @param area      区域
     */
    @PostMapping("/waveData")
    @ResponseBody
    public HttpResult waveData(String startTime, String endTime, String area) {
        HttpResult result;
        DatePojo datePojo;
        datePojo = PubUtils.validateDate(startTime, endTime, "waveData");
        if (!datePojo.getValidity()) {
            result = PubUtils.assignmentResult(null, 500, "解析前台传递的时间有误");
            return result;
        }
        try {
            //下载前，清空备份的两个文件夹
            String item = "njcntemp" + File.separator + "waveTemp9900";
            String itemExcel = "njcntemp" + File.separator + "excel9900";
            FileUtil.clean(new File(appConfig.getTmppath() + item));
            FileUtil.clean(new File(appConfig.getTmppath() + itemExcel));
            //表格数据
            Boolean flag = eventDetailService.getEventDetailList(area, datePojo.getStartTime(), datePojo.getEndTime());
            if (!flag) {
                result = PubUtils.assignmentResult(null, 500, "准备配置信息出错");
            } else {
                Map<String, List<String>> indexList = eventDetailService.getEventDetailIndexList(area, datePojo.getStartTime(), datePojo.getEndTime());
                if (CollectionUtils.isEmpty(indexList)) {
                    result = PubUtils.assignmentResult(null, 500, "没有波形数据");
                } else {
                    result = PubUtils.assignmentResult(indexList, 200, "波形数据准备完毕");
                    cache.set(TokenManager.getUserId() + TokenManager.getSysType() + "waveFiles", indexList);
                }
            }
        } catch (Exception e) {
            logger.error("后台获取数据出错，方法名为：waveData，异常为：" + e);
            result = PubUtils.assignmentResult(null, 500, "获取暂降事件数据出错，请联系管理员");
        }
        return result;
    }


    /**
     * 下载波形文件
     */
    @RequestMapping("downWaveZip")
    public void downZIPFile(HttpServletResponse response) throws Exception {
        Map<String, List<String>> files = cache.get(TokenManager.getUserId() + TokenManager.getSysType() + "waveFiles");
        if (CollectionUtils.isEmpty(files)) {
            return;
        }
        String key = TokenManager.getUserId() + TokenManager.getSysType();
        String excelPath = jedisManager.getValueByKey(RedisDB.SHORT_TIME_QUERY, key);
        //清除缓存
        jedisManager.deleteByKey(RedisDB.SHORT_TIME_QUERY, key);
        String zipName = "Comtrade.zip";
        response.setContentType("APPLICATION/OCTET-STREAM");
        response.setHeader("Content-Disposition", "attachment; filename=" + zipName);
        ZipOutputStream out = new ZipOutputStream(response.getOutputStream());
        try {
            String item = "njcntemp" + File.separator + "waveTemp9900";
            String itemExcel = "njcntemp" + File.separator + "excel9900";
            Iterator<Map.Entry<String, List<String>>> it = files.entrySet().iterator();
            File comtrade = new File(appConfig.getTmppath() + item);
            FileUtil.clean(comtrade);
            while (it.hasNext()) {
                Map.Entry<String, List<String>> entry = it.next();
                List<String> filePaths = entry.getValue();
                File directoryFile = new File(appConfig.getTmppath() + item + File.separator + entry.getKey());
                for (String path : filePaths) {
                    FileUtils.copyFileToDirectory(new File(path), directoryFile);
                }
            }
            FileUtils.copyFileToDirectory(new File(excelPath), comtrade);
            ZipUtils.doCompress(comtrade.getPath(), out);
            //压缩完毕后，清除这个文件夹下的所有的文件
            FileUtil.clean(comtrade);
            FileUtil.clean(new File(appConfig.getTmppath() + itemExcel));
            response.flushBuffer();
        } catch (Exception e) {
            logger.error("下载波形文件发生异常，异常是" + e.getMessage());
        } finally {
            out.close();
        }
    }


    /**
     * 上传表格数据，保存入库
     *
     * @param file 上传的表格
     */
    @PostMapping("uploadExcelData")
    @ResponseBody
    public HttpResult uploadExcelData(@RequestParam(value = "file", required = false) MultipartFile file) throws Exception {
        HttpResult result;
        /**
         * ---------------------------------------------------------------------------------------------------
         * xuyang 2020.08.27
         * 修改：对上传文件做判断
         * 文件大小
         */
        //文件大小(此大小为kb)
        Long fileSize = file.getSize() / 1024;
        //判断文件大小
        if (fileSize > 3072) {
            result = PubUtils.assignmentResult(null, 500, "上传失败,上传文件超过3M，文件过大!");
            return result;
        }
        /**
         * over
         * ---------------------------------------------------------------------------------------------------
         */
        String fileName = file.getOriginalFilename();//获取文件名
        if (!fileName.matches("^.+\\.(?i)(xlsx)$")) {
            result = PubUtils.assignmentResult(null, 500, "文件类型不对");
            return result;
        }
        Boolean flag;
        try {
            flag = eventDetailService.dealWithData(file);
            if (!flag) {
                result = PubUtils.assignmentResult(null, 500, "数据导入失败");
            } else {
                result = PubUtils.assignmentResult(null, 200, "数据导入成功");
            }
        } catch (Exception e) {
            logger.error(e.toString());
            if (e.getMessage().equalsIgnoreCase("读取数据过程有误")) {
                result = PubUtils.assignmentResult(null, 500, "读取数据过程有误");
            } else if (e.getMessage().equalsIgnoreCase("清洗数据过程有误")) {
                result = PubUtils.assignmentResult(null, 500, "清洗数据过程有误");
            } else {
                result = PubUtils.assignmentResult(null, 500, "数据导入失败");
            }
        }
        return result;
    }


    /**
     * 上传波形数据、监测点索引，保存入库
     *
     * @param multfile 上传的波形CFG文件
     */
    @PostMapping("uploadWaveData")
    @ResponseBody
    public HttpResult uploadWaveData(@RequestParam(value = "file", required = false) MultipartFile multfile, String deviceIndex, String lineIndex, HttpServletRequest request) {
        HttpResult result;
        //首先根据deviceIndex获取IP，确定文件需要保存的文件夹路径
        if (StringUtils.isEmpty(deviceIndex) || StringUtils.isEmpty(lineIndex)) {
            return PubUtils.assignmentResult(null, 500, "装置或检测点索引为空");
        }
        String ip = deviceService.getIPByIndex(deviceIndex);
        if (StringUtils.isEmpty(ip)) {
            return PubUtils.assignmentResult(null, 500, "装置IP为空");
        }
        //拷贝文件到指定文件夹下
        String path;
        try {
            String filePath = appConfig.getWavePath() + File.separator + ip + File.separator + multfile.getOriginalFilename();
            File file = new File(filePath);
            FileUtils.copyInputStreamToFile(multfile.getInputStream(), file);
            path = file.getPath();
        } catch (Exception e) {
            logger.error("拷贝上传文件过程出错，原因：" + e.toString());
            return PubUtils.assignmentResult(null, 500, "拷贝文件流出错");
        }
        //文件拷贝成功后，需要将路径保存起来，以便后面分析事件日志参考,注：只需要CFG文件的路径
        try {
            if (!StringUtils.isEmpty(path) & path.toUpperCase(Locale.ENGLISH).endsWith("CFG")) {
                String key = "uploadWave" + TokenManager.getUserId();
                Map<String, List<String>> pathsTemp = cache.get(key);
                List<String> paths;
                if (pathsTemp == null) {
                    paths = new ArrayList<>();
                    pathsTemp = new HashMap<>();
                } else {
                    paths = pathsTemp.get(key);
                    if (CollectionUtils.isEmpty(paths)) {
                        paths = new ArrayList<>();
                    }
                }
                paths.add(path);
                pathsTemp.put(key, paths);
                cache.set(key, pathsTemp);
            }
            result = PubUtils.assignmentResult(null, 200, "保存文件路径成功");
            userLog.getLog("上传离线波形文件", "成功", PubUtils.getIpAddr(request), LogTypeEnum.BUSSINESS.toString(), 0);
        } catch (Exception e) {
            logger.error("保存文件路径出错，原因：" + e.toString());
            result = PubUtils.assignmentResult(null, 500, "保存文件路径出错");
            userLog.getLog("上传离线波形文件", "失败", PubUtils.getIpAddr(request), LogTypeEnum.BUSSINESS.toString(), 0);
        }
        return result;
    }

    /**
     * 根据上面存的路径，录入波形日志
     *
     * @param lineIndex 监测点索引
     */
    @PostMapping("saveWaveDetail")
    @ResponseBody
    public HttpResult saveWaveDetail(String lineIndex) {
        HttpResult result;
        //首先根据deviceIndex获取IP，确定文件需要保存的文件夹路径
        if (StringUtils.isEmpty(lineIndex)) {
            return PubUtils.assignmentResult(null, 500, "检测点索引为空");
        }
        String key = "uploadWave" + TokenManager.getUserId();
        Map<String, List<String>> pathsTemp = cache.get(key);
        List<String> paths = pathsTemp.get(key);
        //用完就删
        cache.set(key, new HashMap<String, List<String>>());
        if (CollectionUtils.isEmpty(paths)) {
            return PubUtils.assignmentResult(null, 500, "没有事件需要保存");
        }
        try {
            eventDetailService.saveEventDetail(lineIndex, paths);
            result = PubUtils.assignmentResult(null, 200, "全部保存成功");
        } catch (Exception e) {
            logger.error("事件存库出现异常，原因：" + e.toString());
            result = PubUtils.assignmentResult(null, 500, "事件存库出现异常");
        }
        return result;
    }


    /**
     * @param multfile 上传的波形CFG文件
     */
    @PostMapping("viewWave")
    @ResponseBody
    public HttpResult viewWave(@RequestParam(value = "file", required = false) MultipartFile multfile) {
        String originalFilename = multfile.getOriginalFilename();
        originalFilename = originalFilename.substring(originalFilename.length() - 4);
        if (!originalFilename.equalsIgnoreCase(".CFG") && !originalFilename.equalsIgnoreCase(".DAT")) {
            return PubUtils.assignmentResult(null, 500, "文件类型有误");
        }
        HttpResult result;
        //首先根据deviceIndex获取IP，确定文件需要保存的文件夹路径
        //拷贝文件到指定文件夹下
        String path;
        try {
            String filePath = appConfig.getTmppath() + File.separator + "waveTemp" + File.separator + multfile.getOriginalFilename();
            File file = new File(filePath);
            FileUtils.copyInputStreamToFile(multfile.getInputStream(), file);
            path = file.getPath();
        } catch (Exception e) {
            logger.error("拷贝上传文件过程出错，原因：" + e.toString());
            return PubUtils.assignmentResult(null, 500, "拷贝文件流出错");
        }
        //文件拷贝成功后，需要将路径保存起来，以便后面分析事件日志参考,注：只需要CFG文件的路径
        try {
            if (!StringUtils.isEmpty(path) & path.toUpperCase(Locale.ENGLISH).endsWith("CFG")) {
                String key = "viewWave" + TokenManager.getUserId();
                jedisManager.saveValueByKey(RedisDB.SHORT_TIME_QUERY, key, path, RedisDB.SHORT_TIME);
            }
            result = PubUtils.assignmentResult(null, 200, "保存文件路径成功");
        } catch (Exception e) {
            logger.error("保存文件路径出错，原因：" + e.toString());
            result = PubUtils.assignmentResult(null, 500, "保存文件路径出错");
        }
        return result;
    }


    /**
     * 根据上面存的路径，显示波形数据
     */
    @PostMapping("showWave")
    @ResponseBody
    public HttpResult showWave(HttpServletRequest request) {
        HttpResult result = PubUtils.initResult(TokenManager.getToken().getLoginName(), request, LogTypeEnum.SYSTEM.toString(), 1);
        String key = "viewWave" + TokenManager.getUserId();
        String path = jedisManager.getValueByKey(RedisDB.SHORT_TIME_QUERY, key);
        if (StringUtils.isEmpty(path)) {
            return PubUtils.assignmentResultLog(null, 500, "没有波形展示", "离线波形查看", "失败", result);
        }
        WaveData waveData;
        try {
            waveData = waveService.getWavedataByPath(path);
            if (CollectionUtils.isEmpty(waveData.getSunData())) {
                result = PubUtils.assignmentResultLog(null, 500, "没有波形数据", "离线波形查看", "失败", result);
            } else {
                result = PubUtils.assignmentResultLog(waveData, 200, "获取波形数据成功", "离线波形查看", "成功", result);
            }

        } catch (Exception e) {
            logger.error("获取波形数据异常，原因：" + e.toString());
            result = PubUtils.assignmentResultLog(null, 500, "获取波形数据失败", "离线波形查看", "失败", result);
        }
        return result;
    }


    /**
     * 新增暂降事件及上传波形文件
     *
     * @author cdf
     * @date 2021/9/29
     */
    @PostMapping("addEvent")
    @ResponseBody
    public HttpResult addEventAndWave(@RequestParam(value = "file") MultipartFile[] multfile, Integer lineIndex, String time, Integer ms, String describe, Integer waveType, Integer persistime,Float eventValue,String eventReason,String eventType) {
        //首先根据deviceIndex获取IP，确定文件需要保存的文件夹路径
        if (StringUtils.isEmpty(lineIndex)) {
            return PubUtils.assignmentResult(null, 500, "监测点索引为空");
        }
        if (StringUtils.isEmpty(time) || Objects.isNull(ms)) {
            return PubUtils.assignmentResult(null, 500, "暂态发生时间不可为空");
        }
        if (Objects.isNull(waveType)) {
            return PubUtils.assignmentResult(null, 500, "事件类型不可为空");
        }
        if (Objects.isNull(persistime)) {
            return PubUtils.assignmentResult(null, 500, "事件持续时间不可为空");
        }
        if (Objects.isNull(eventValue)) {
            return PubUtils.assignmentResult(null, 500, "特征幅值不可为空");
        }
        if(StringUtils.isEmpty(eventReason)){
            return PubUtils.assignmentResult(null, 500, "暂态原因不可为空");
        }
        if(StringUtils.isEmpty(eventType)){
            return PubUtils.assignmentResult(null, 500, "暂态类型不可为空");
        }
        Line line = lineService.selectLineByIndex(lineIndex.longValue());
        if (Objects.isNull(line)) {
            return PubUtils.assignmentResult(null, 500, "获取监测点信息失败,请联系管理员");
        }
        String ip = deviceService.getIPByIndex(line.getDevIndex().toString());
        if (StringUtils.isEmpty(ip)) {
            return PubUtils.assignmentResult(null, 500, "装置IP为空");
        }

        Date times;
        SimpleDateFormat sdfs = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        try {
            times = sdfs.parse(time);
        } catch (ParseException e) {
            return PubUtils.assignmentResult(null, 500, "时间格式有误");
        }

        for (MultipartFile multipartFile : multfile) {
            //文件大小(此大小为kb)
            Long fileSize = multipartFile.getSize() / 1024;
            //判断文件大小
            if (fileSize > 3072) {
                return PubUtils.assignmentResult(null, 500, "上传失败,上传文件超过3M，文件过大!");

            }
            String originalFilename = multipartFile.getOriginalFilename();
            originalFilename = originalFilename.substring(originalFilename.length() - 4);
            if (!originalFilename.equalsIgnoreCase(".CFG") && !originalFilename.equalsIgnoreCase(".DAT")) {
                return PubUtils.assignmentResult(null, 500, "文件类型有误");
            }
        }
        String res;
        try {
            res = downEventService.addEventAndWave(multfile, lineIndex, times, ms, describe, waveType, persistime, eventValue, eventReason, eventType, ip);
        }catch (Exception e){
            res = e.getMessage();
        }
        if ("新增成功".equals(res)) {
            return PubUtils.assignmentResult(null, 200, res);
        }else {
            return PubUtils.assignmentResult(null, 500, res);
        }

    }

    /**
     * 新增波形文件
     * @author cdf
     * @date 2021/10/8
     */
    @PostMapping("uploadWaveDetail")
    @ResponseBody
    public synchronized HttpResult uploadWaveDetail(@RequestParam("file") MultipartFile multfile,String lineIndex, HttpServletRequest request) {
        HttpResult result;
        //首先根据deviceIndex获取IP，确定文件需要保存的文件夹路径
        Line line = lineService.selectLineByIndex(Long.parseLong(lineIndex));
        if (Objects.isNull(line)) {
            return PubUtils.assignmentResult(null, 500, "获取监测点信息失败,请联系管理员");
        }
        String ip = deviceService.getIPByIndex(line.getDevIndex().toString());
        if (StringUtils.isEmpty(ip)) {
            return PubUtils.assignmentResult(null, 500, "装置IP为空");
        }

        //文件大小(此大小为kb)
        Long fileSize = multfile.getSize() / 1024;
        //判断文件大小
        if (fileSize > 3072) {
            return PubUtils.assignmentResult(null, 500, "上传失败,上传文件超过3M，文件过大!");

        }
        String originalFilename = multfile.getOriginalFilename();
        originalFilename = originalFilename.substring(originalFilename.length() - 4);
        if (!originalFilename.equalsIgnoreCase(".CFG") && !originalFilename.equalsIgnoreCase(".DAT")) {
            return PubUtils.assignmentResult(null, 500, "文件类型有误");
        }

        //拷贝文件到指定文件夹下
        try {
            String filePath = appConfig.getWavePath() + File.separator + ip + File.separator + multfile.getOriginalFilename();
            File file = new File(filePath);
            File parentFile = file.getParentFile();
            if (!parentFile.exists()) {
                System.out.println("父文件"+parentFile.exists());
                parentFile.mkdirs();

            }
            if(!file.exists()){
                file.createNewFile();
                FileUtils.copyInputStreamToFile(multfile.getInputStream(), file);
            }else{
                return PubUtils.assignmentResult(null, 500, "已存在文件，请勿重复上传");
            }

        } catch (Exception e) {
            logger.error("拷贝上传文件过程出错，原因：" + e.toString());
            return PubUtils.assignmentResult(null, 500, "拷贝文件流出错");
        }



        result = PubUtils.assignmentResult(null, 200, "保存文件路径成功");
        userLog.getLog("上传波形文件", "成功", PubUtils.getIpAddr(request), LogTypeEnum.BUSSINESS.toString(), 0);

        return result;
    }


    /**
     * 修改数据库暂态波形标识
     * @author cdf
     * @date 2021/10/8
     */
    @GetMapping("updateWaveFlag")
    @ResponseBody
    public HttpResult updateWaveFlag(String evenDetailIndex){
        //首先根据deviceIndex获取IP，确定文件需要保存的文件夹路径
        if (StringUtils.isEmpty(evenDetailIndex)) {
            return PubUtils.assignmentResult(null, 500, "事件索引不可为空");
        }

        Integer res = downEventService.updateWaveFlag(evenDetailIndex);
        if(res == 1){
            return PubUtils.assignmentResult(null, 200, null);
        }else{
            return PubUtils.assignmentResult(null, 500, null);
        }

    }



}
