package com.shining.cloud.serviceImpl.report;

import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.UUID;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;

import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
import org.apache.poi.xssf.usermodel.XSSFDrawing;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
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 com.github.pagehelper.PageHelper;
import com.njcn.mapper.user.UserMapper;
import com.njcn.pojo.commons.EventEigDetail;
import com.njcn.pojo.commons.EventInfoDetail;
import com.njcn.pojo.commons.WaveData;
import com.njcn.pojo.pointInfo.PointInfo;
import com.njcn.pojo.wave.WaveDataDetail;
import com.njcn.pojo.weeklyreport.AreaPointInfoData;
import com.njcn.pojo.weeklyreport.SagRateData;
import com.njcn.service.commons.IWaveService;
import com.njcn.service.point.PointBaseInfoService;
import com.njcn.sso.pojo.user.User;
import com.njcn.utils.AppConfig;
import com.njcn.utils.PubUtils;
import com.njcn.utils.UserUtil;
import com.njcn.utils.WeeklyExcelUtil;
import com.shining.cloud.enums.information.EventMsgCodeEnum;
import com.shining.cloud.mapper.information.EventInfoMapper;
import com.shining.cloud.mapper.report.ShiningReportMapper;
import com.shining.cloud.pojo.information.EventInfo;
import com.shining.cloud.pojo.report.Info;
import com.shining.cloud.pojo.report.ReportData;
import com.shining.cloud.service.information.EventInfoService;
import com.shining.cloud.service.information.SteadyAssService;
import com.shining.cloud.service.report.ShiningReportService;
import com.shining.cloud.util.EchartsUtil;
import com.shining.cloud.util.ExcelUtil;
import com.shining.cloud.util.FreemarkerUtil;
import com.shining.cloud.util.WordUtil;

import freemarker.template.TemplateException;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

@Service
public class ShiningReportServiceImpl implements ShiningReportService {
    private static final Logger logger = LoggerFactory.getLogger(ShiningReportServiceImpl.class);
    public enum RESULTCODE {
        RESULT_SUCCESS(0, "成功"),
        RESULT_FAIL(1, "失败"),
        RESULT_NODATA(2, "事件暂无波形");

        private int code;
        private String msg;

        RESULTCODE(int code, String msg) {
            this.code = code;
            this.msg = msg;
        }

        public int getCode() {
            return code;
        }

        public void setCode(int code) {
            this.code = code;
        }

        public String getMsg() {
            return msg;
        }

        public void setMsg(String msg) {
            this.msg = msg;
        }
    }



    @Resource
    private ShiningReportMapper shiningReportMapper;

    @Autowired
    private EventInfoService eventInfoService;

    @Autowired
    private IWaveService waveService;

	@Autowired
	private IWaveService iWaveService;

    @Autowired
    private UserUtil userUtil;

    @Autowired
    private PointBaseInfoService pointBaseInfoService;

    @Resource
    private EventInfoMapper eventInfoMapper;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    AppConfig appConfig;

    @Autowired
    ShiningReport shiningReport;

    @Override
    public List<ReportData> reportList(String user_id, Integer system_type, Integer report_type, Integer page, Integer num, Long lineIndex, Long startTime, Long endTime) {

        List<Integer> lineList = new ArrayList<>();

        if (lineIndex != null) {
            lineList.add(lineIndex.intValue());
        } else {
            lineList.addAll(userUtil.ApplistLine(user_id));
        }

        if (lineList.size() == 0) {
            return new ArrayList<>();
        }

        Date start = null;
        Date end = null;

        if (startTime != null) {
            start = new Date(startTime);
            end = new Date(endTime);
        }

        PageHelper.offsetPage((page - 1) * num, num);

        if (EventMsgCodeEnum.STEADY_TYPE.getCode() == system_type) {//稳态系统查limit_rate越限次数
            List<Integer> list = new ArrayList<>();

            for (int i = 2; i < 26; i++) {
                list.add(i);
            }

            return shiningReportMapper.steadyReportList(user_id, lineList, system_type, report_type, list, start, end);
        } else if (EventMsgCodeEnum.TRANSIENT_TYPE.getCode() == system_type) {
            String deptsIndex = userUtil.getappDeptsIndex(user_id);
            return shiningReportMapper.transientReportList(user_id, lineList, system_type, report_type, deptsIndex, start, end);
        }

        return new ArrayList<>();
    }

    @Override
    public int eventDetailReportApply(String user_id, String eventDetail_index, HttpServletRequest request) {
        EventInfo eventInfo = eventInfoMapper.getEventInfoByUserIndex(eventDetail_index);

        if (eventInfo == null) {
            try {
                String path = createEventDetailReport(eventDetail_index, request);

                if (path.equals("nodata")) {
                    return RESULTCODE.RESULT_NODATA.getCode();
                }

                eventInfoMapper.insertEventInfoData(eventDetail_index, 0, user_id, new Date(), "", "", 1, path);
                return RESULTCODE.RESULT_SUCCESS.getCode();
            } catch (Exception e) {
            	e.printStackTrace();
                eventInfoMapper.insertEventInfoData(eventDetail_index, 0, user_id, new Date(), "", "", 2, "");
                return RESULTCODE.RESULT_FAIL.getCode();
            }
        } else if (eventInfo.getReportState() != 1) {
            try {
                String path = createEventDetailReport(eventDetail_index, request);

                if (path.equals("nodata")) {
                    return RESULTCODE.RESULT_NODATA.getCode();
                }

                eventInfoMapper.updateEventInfoData(eventDetail_index, new Date(), 1, user_id, path);
                return RESULTCODE.RESULT_SUCCESS.getCode();
            } catch (Exception e) {
            	e.printStackTrace();
                eventInfoMapper.updateEventInfoData(eventDetail_index, new Date(), 2, user_id, "");
                return RESULTCODE.RESULT_FAIL.getCode();
            }
        }

        return RESULTCODE.RESULT_SUCCESS.getCode();
    }

    @Override
    public int customReport(String userId, Long lineIndex, Integer sysType, Date startTime, Date endTime, Integer reportType, HttpServletRequest request) {
        String deptsIndex = sysType == 1 ? userUtil.getappDeptsIndex(userId) : null;
        ReportData reportData = shiningReportMapper.reportIsExist(lineIndex, startTime, endTime, reportType, deptsIndex);
        String name = "fail";

        try {
            name = sysType == 1 ? getFileName(userId, startTime, endTime) : getFileName(lineIndex.toString(), startTime, endTime);
        } catch (Exception e) {
            logger.error("获取报告名称发生异常，异常是"+e.getMessage());
        }

        if (reportData == null) {
            try {
                String path = createReport(userId, sysType, lineIndex, startTime, endTime, request);
                String uuid = UUID.randomUUID().toString();
                userId = reportType == 5 ? userId : "";

                if (path.equals("")) {
                    shiningReportMapper.insertReportData(uuid, name, lineIndex, userId, new Date(), startTime, endTime, sysType, reportType, "", 2, 1, deptsIndex);
                    return RESULTCODE.RESULT_FAIL.getCode();
                } else {
                    shiningReportMapper.insertReportData(uuid, name, lineIndex, userId, new Date(), startTime, endTime, sysType, reportType, path, reportType == 5 ? 3 : 1, 0, deptsIndex);
                    return RESULTCODE.RESULT_SUCCESS.getCode();
                }
            } catch (Exception e) {
                String uuid = UUID.randomUUID().toString();
                shiningReportMapper.insertReportData(uuid, name, lineIndex, userId, new Date(), startTime, endTime, sysType, reportType, "", 2, 1, deptsIndex);
                return RESULTCODE.RESULT_FAIL.getCode();
            }
        } else if (reportData.getState() == 2) {
            if (reportData.getErrorCount() > 2) {
                return RESULTCODE.RESULT_FAIL.getCode();
            } else {
                try {
                    String path = createReport(userId, sysType, lineIndex, startTime, endTime, request);

                    if (reportData.getUserIndex().equals(userId)) {
                        if (path.equals("")) {
                            shiningReportMapper.updateReportData(reportData.getReportIndex(), new Date(), reportData.getErrorCount() + 1, reportData.getState(), "");
                            return RESULTCODE.RESULT_FAIL.getCode();
                        } else {
                            shiningReportMapper.updateReportData(reportData.getReportIndex(), new Date(), 0, reportType == 5 ? 3 : 1, path);
                            return RESULTCODE.RESULT_SUCCESS.getCode();
                        }
                    } else {
                        String uuid = UUID.randomUUID().toString();
                        userId = reportType == 5 ? userId : "";

                        if (path.equals("")) {
                            shiningReportMapper.insertReportData(uuid, name, lineIndex, userId, new Date(), startTime, endTime, sysType, reportType, "", 2, 1, deptsIndex);
                            return RESULTCODE.RESULT_FAIL.getCode();
                        } else {
                            shiningReportMapper.insertReportData(uuid, name, lineIndex, userId, new Date(), startTime, endTime, sysType, reportType, path, reportType == 5 ? 3 : 1, 0, deptsIndex);
                            return RESULTCODE.RESULT_SUCCESS.getCode();
                        }
                    }
                } catch (Exception e) {
                    if (reportData.getUserIndex().equals(userId)) {
                        shiningReportMapper.updateReportData(reportData.getReportIndex(), new Date(), reportData.getErrorCount() + 1, reportData.getState(), "");
                    } else {
                        String uuid = UUID.randomUUID().toString();
                        userId = reportType == 5 ? userId : "";

                        shiningReportMapper.insertReportData(uuid, name, lineIndex, userId, new Date(), startTime, endTime, sysType, reportType, "", 2, 1, deptsIndex);
                    }

                    return RESULTCODE.RESULT_FAIL.getCode();
                }
            }
        }

        return RESULTCODE.RESULT_SUCCESS.getCode();
    }

    @Override
    public EventInfo getDownLoadPath(String userId, String eventDetailIndex) {
        return shiningReportMapper.getDownLoadPath(userId, eventDetailIndex);
    }

    private String getPath(HttpServletRequest request) {
        return request.getSession().getServletContext().getRealPath("/appfiles");
    }

    private String path() {
        String serverpath = ShiningReportServiceImpl.class.getResource("/").getPath().replace("%20", " ").replace('/', '\\');//得到工程名WEB-INF/classes/路径 
        String path = serverpath.substring(1, serverpath.indexOf("WEB-INF"));
        path += "appfiles";
        return path;
    }

    private String getFilePath(String file, String lineId, Date startTime, Date endTime, HttpServletRequest request) throws Exception {
        String path = request == null ? path() : getPath(request);
        path += file;

        File tmpfile = new File(path);
        if (!tmpfile.exists()) {
            tmpfile.mkdir();
        }

        path = path + "\\" + getFileName(lineId, startTime, endTime);

        return path;
    }

    private String getFileName(String lineId, Date stratTime, Date endTime) throws Exception {
        String start = PubUtils.date2String(stratTime, "yyyy-MM-dd");
        String end = PubUtils.date2String(endTime, "yyyy-MM-dd");

        return lineId + "_" + start + "_" + end + ".xlsx";
    }

    private String createReport(String userId, int type, Long lineId, Date startTime, Date endTime, HttpServletRequest request) throws Exception {
        if (type == 2) { //稳态系统
            Integer result = shiningReport.createReport(lineId.intValue(), startTime, endTime).getCode();

            switch (result) {
                case 0:
                    String start = PubUtils.date2String(startTime, "yyyy-MM-dd HH:mm:ss");
                    String end = PubUtils.date2String(endTime, "yyyy-MM-dd HH:mm:ss");
                    writeReport(getFilePath("\\steadyExcelReport", lineId.toString(), startTime, endTime, request), setInfo(lineId.intValue(), start, end), setJson(lineId.intValue()));
                    return appConfig.getReportPath() + "steadyExcelReport/" + getFileName(lineId.toString(), startTime, endTime);
                case 1:
                case 2:
                case 3:
                    return "";
            }
        } else if (type == 1) { //暂态系统
            Integer result = shiningReport.createTransientReport(userId, startTime, endTime).getCode();

            switch (result) {
                case 0:
                    writeTransientReport(getFilePath("\\transientExcelReport", userId, startTime, endTime, request));
                    return appConfig.getReportPath() + "transientExcelReport/" + getFileName(userId, startTime, endTime);
                case 3:
                    return "";
            }
        }

        return "";
    }

    private JSONObject setInfo(Integer lineId, String start, String end) {
        JSONObject jsonObject = new JSONObject();

        PointInfo pointInfo = pointBaseInfoService.getInfo(lineId);

        jsonObject.put("bdName", pointInfo.getBdName());
        jsonObject.put("pName", pointInfo.getpName());
        jsonObject.put("time", "起始时间:" + start + " 结束时间:" + end);
        jsonObject.put("exceptTime", "");
        jsonObject.put("Name", pointInfo.getName());
        return jsonObject;
    }

    private JSONObject setJson(Integer lineId) {
        JSONObject jsonObject = new JSONObject();
        PointInfo pointInfo = pointBaseInfoService.getPointInfo(lineId);
        jsonObject.put("voltageClasses", pointInfo.getVoltageClasses());
        jsonObject.put("pt1", pointInfo.getPt1());
        jsonObject.put("pt2", pointInfo.getPt2());
        jsonObject.put("ct1", pointInfo.getCt1());
        jsonObject.put("ct2", pointInfo.getCt2());
        jsonObject.put("jzcmp", pointInfo.getJzcmp());
        jsonObject.put("dlcmp", pointInfo.getDlcmp());
        jsonObject.put("xycmp", pointInfo.getXycmp());
        jsonObject.put("devcmp", pointInfo.getDevcmp());
        return jsonObject;
    }

    private void writeTransientReport(String path) throws IOException {
        String[] sheetName = {"暂降总体概况", "暂降严重度统计", "暂降原因统计", "详细事件列表"};
        WeeklyExcelUtil weeklyExcelUtil = new WeeklyExcelUtil(sheetName);

        // 解析图片流
        try {
            weeklyExcelUtil.translate(setPointInfoPic("区域统计", "(区域)", 25, shiningReport.getListPointInfo()),
                    setPointInfoPic("电压等级统计", "(电压等级)", 0, shiningReport.getListVoltageInfo()), setSags("区域统计", "(区域)", 25, shiningReport.getListPointInfo()),
                    setSags("电压等级统计", "(电压等级)", 0, shiningReport.getListVoltageInfo()), setPie());
        } catch (Exception e) {
            logger.error("解析图片发生异常，异常是"+e.getMessage());
        }
        weeklyExcelUtil.writePointInfo(weeklyExcelUtil.getListSheet().get(0), shiningReport.getListPointInfo(), shiningReport.getListVoltageInfo());
        weeklyExcelUtil.writeSagData(weeklyExcelUtil.getListSheet().get(1), shiningReport.getListSag(), 1);
        weeklyExcelUtil.writeSagReason(weeklyExcelUtil.getListSheet().get(2), shiningReport.getListSagReason());
        weeklyExcelUtil.writeSagData(weeklyExcelUtil.getListSheet().get(3), shiningReport.getListSagEvents(), 2);
        drawPicInExcel(weeklyExcelUtil);

        File exportFile = new File(path);
        exportFile.createNewFile();
        FileOutputStream fileOut = new FileOutputStream(path);
        weeklyExcelUtil.getWorkbook().write(fileOut);
        fileOut.flush();
    }

    private void drawPicInExcel(WeeklyExcelUtil weeklyExcelUtil) throws IOException {
        for (int i = 0, j = 0; i < weeklyExcelUtil.getListPic().size() - 1; i++, j += 13) {
            ByteArrayOutputStream outStreamdd = new ByteArrayOutputStream();
            BufferedImage bufferedImage = ImageIO.read(new ByteArrayInputStream(weeklyExcelUtil.getListPic().get(i)));
            ImageIO.write(bufferedImage, "PNG", outStreamdd);
            XSSFDrawing xssfDrawing = weeklyExcelUtil.getListSheet().get(0).createDrawingPatriarch();
            XSSFClientAnchor clientAnchor = new XSSFClientAnchor(1, 1, 1, 1, 5, j, 13, j + 12);
            xssfDrawing.createPicture(clientAnchor,
                    weeklyExcelUtil.getWorkbook().addPicture(outStreamdd.toByteArray(), XSSFWorkbook.PICTURE_TYPE_PNG));
        }

        // 贴图(暂降原因统计)
        ByteArrayOutputStream outStreamdd = new ByteArrayOutputStream();
        BufferedImage bufferedImage = ImageIO.read(new ByteArrayInputStream(weeklyExcelUtil.getListPic().get(4)));
        ImageIO.write(bufferedImage, "PNG", outStreamdd);
        XSSFDrawing xssfDrawing = weeklyExcelUtil.getListSheet().get(2).createDrawingPatriarch();
        XSSFClientAnchor clientAnchor = new XSSFClientAnchor(1, 1, 1, 1, 0, 5, 3, 17);
        xssfDrawing.createPicture(clientAnchor,
                weeklyExcelUtil.getWorkbook().addPicture(outStreamdd.toByteArray(), XSSFWorkbook.PICTURE_TYPE_PNG));
    }

    private String setPointInfoPic(String subName, String xName, Integer rotate, List<AreaPointInfoData> list) throws IOException, TemplateException {
        List<String> listName = new ArrayList<>();
        List<Integer> listOnline = new ArrayList<>();
        List<Integer> listOffLine = new ArrayList<>();

        for (AreaPointInfoData areaPointInfoData : list) {
            listName.add(areaPointInfoData.getName());
            listOnline.add(areaPointInfoData.getOnLine());
            listOffLine.add(areaPointInfoData.getOffLine());
        }

        HashMap<String, Object> datas = new HashMap<>();
        datas.put("subName", subName);
        datas.put("rotate", rotate);
        datas.put("name", JSONArray.fromObject(listName).toString());
        datas.put("xName", xName);
        datas.put("onLine", JSONArray.fromObject(listOnline).toString());
        datas.put("offLine", JSONArray.fromObject(listOffLine).toString());
        String option = FreemarkerUtil.generateString("bar.ftl", "com/shining/cloud/template", datas);

        return EchartsUtil.generateEchartsBase64(option, "6666");
    }

    private String setSags(String subName, String xName, Integer rotate, List<AreaPointInfoData> list) throws IOException, TemplateException {
        List<String> listName = new ArrayList<>();
        List<Integer> listEvents = new ArrayList<>();

        for (AreaPointInfoData areaPointInfoData : list) {
            listName.add(areaPointInfoData.getName());
            listEvents.add(areaPointInfoData.getEventCount());
        }

        HashMap<String, Object> datas = new HashMap<>();
        datas.put("subName", subName);
        datas.put("rotate", rotate);
        datas.put("name", JSONArray.fromObject(listName).toString());
        datas.put("xName", xName);
        datas.put("xData", JSONArray.fromObject(listEvents).toString());
        String option = FreemarkerUtil.generateString("sagEvents.ftl", "com/shining/cloud/template", datas);

        return EchartsUtil.generateEchartsBase64(option, "6666");
    }

    private String setPie() throws IOException, TemplateException {
        List<String> listReaArray = new ArrayList<>();
        List<Info> listValueArray = new ArrayList<>();

        for (SagRateData sagRateData : shiningReport.getListSagReason()) {
            listReaArray.add(sagRateData.getName());
            Info info = new Info();
            info.setName(sagRateData.getName());
            info.setValue(sagRateData.getCount());
            listValueArray.add(info);
        }


        HashMap<String, Object> datas = new HashMap<>();
        datas.put("reaArray", JSONArray.fromObject(listReaArray).toString());
        datas.put("valueArray", JSONArray.fromObject(listValueArray).toString());
        String option = FreemarkerUtil.generateString("pie.ftl", "com/shining/cloud/template", datas);

        return EchartsUtil.generateEchartsBase64(option, "6666");
    }


    private void writeReport(String path, JSONObject jsonObject, JSONObject json) throws IOException {
        ExcelUtil excelUtil = new ExcelUtil();
        excelUtil.createWorkBook();
        excelUtil.createSheet("非谐波");
        excelUtil.createSheet("谐波电压");
        excelUtil.createSheet("谐波电流");
        excelUtil.createSheet("合格率");
        excelUtil.setOverLimitInfo(shiningReport.getOverLimitInfoData());

        for (XSSFSheet sheet : excelUtil.getListSheet()) {
            excelUtil.createHeader(jsonObject, json, sheet);
        }

        //非谐波电流
        excelUtil.writeNonHarmonics(excelUtil.getListSheet().get(0), shiningReport.getListVirtual(), shiningReport.getListPower(), shiningReport.getListFlicker(),
                shiningReport.getListDistortion(), shiningReport.getListVdeviation(), shiningReport.getListFrequency(), shiningReport.getListThreephase());
        //谐波电压
        excelUtil.writeHarmonics(excelUtil.getListSheet().get(1), shiningReport.getListVoltageRate(), true);
        //谐波电流
        excelUtil.writeHarmonics(excelUtil.getListSheet().get(2), shiningReport.getListICurrent(), false);
        //合格率
        excelUtil.writeFpyData(excelUtil.getListSheet().get(3), shiningReport.getListFpy());

        File exportFile = new File(path);
        exportFile.createNewFile();
        FileOutputStream fileOut = new FileOutputStream(path);
        excelUtil.getWorkbook().write(fileOut);
        fileOut.flush();
    }

    private String createEventDetailReport(String eventIndex, HttpServletRequest request) throws Exception {
        WaveData waveData = waveService.getWavedata(eventIndex, 2);

        if (waveData.getSunData().size() == 0) {
            return "nodata";
        }

        //数据筛选,如果是双路电压的话，会存在2个波形数据
        List<WaveDataDetail> waveDataDetails = waveService.filteWaveData(waveData);

        String time = waveData.getTime();
        time = time.replace(" ", "%20");
        String title = "监测点名称：" + waveData.getLineName() + "%20发生时刻：" + time + "%20特征幅值：" + waveData.getEventValue() + "%25%20持续时间：" + waveData.getPersistTime() + "s";

        WordUtil wordUtil = new WordUtil();
        if(waveDataDetails.size() == 1){
            wordUtil.translate(iWaveService.createShunTitle(title,waveDataDetails.get(0)), iWaveService.createRMSTitle(title,waveDataDetails.get(0)));
        }else{
            wordUtil.translate(iWaveService.createShunTitle(title,waveDataDetails.get(0)),iWaveService.createShun(waveDataDetails.get(1)),
                    iWaveService.createRMSTitle(title,waveDataDetails.get(0)),iWaveService.createRMS(waveDataDetails.get(1)));
        }
        List<EventEigDetail> eventDetailEigenvalue = eventInfoService.reportEigen(eventIndex,waveData);
        wordUtil.setEventDetailEigenvalue(eventDetailEigenvalue);
        EventInfoDetail eventInfoList = eventInfoService.eventDetailBaseInfoByIndex(eventIndex);
        wordUtil.setEventInfoList(eventInfoList);
        wordUtil.createReport();

        String path = getPath(request) + "\\transientWordReport";

        File tmpfile = new File(path);

        if (!tmpfile.exists()) {
            tmpfile.mkdir();
        }

        path += "\\" + eventIndex + ".docx";
        File exportFile = new File(path);
        exportFile.createNewFile();
        FileOutputStream fileOut = new FileOutputStream(path);
        wordUtil.getDocument().write(fileOut);
        fileOut.flush();

        return appConfig.getReportPath() + "transientWordReport/" + eventIndex + ".docx";
    }

    @Override
    public User getmarketingUserInfo(String userId) {
        return userMapper.getAppBaseUser(userId);
    }
}
