package com.ho.business.service.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.ho.business.entity.*;
import com.ho.business.mapper.PlanningCurveMapper;
import com.ho.business.mapper.PlanningCurveTacticsMapper;
import com.ho.business.service.DynamicConfigService;
import com.ho.business.service.PlanningCurveService;
import com.ho.business.service.StationService;
import com.ho.common.tools.constant.DefineConstant;
import com.ho.common.tools.entity.UserDetailRespVO;
import jodd.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.YearMonth;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.zip.CRC32;

@Service
@Slf4j
public class PlanningCurveServiceImpl implements PlanningCurveService {

    // 配置文件里holiday字符串
    /*@Value("${holiday}")
    private String holidayStr;*/

    @Autowired
    private PlanningCurveMapper planningMapper;

    @Autowired
    private StationService stationService;

    @Autowired
    private PlanningCurveTacticsMapper planningCurveTacticsMapper;

    @Autowired
    private DynamicConfigService dynamicConfigService;

    @Override
    public List<Map<String, Object>> getPlanningCurveTemplates(PlanningCurveTemplate template) {
        return planningMapper.getPlanningCurveTemplates(template);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Map<String, Object> addPlanningCurveTemplate(PlanningCurveTemplate template) {
        Map<String, Object> result = new HashMap<String, Object>(0);
        result.put("code", 200);
        result.put("msg", DefineConstant.PeakShaving.ADD_TEMPLATE_SUCCESS);
        try {
            if (null != template) {

                if(StringUtil.isNotBlank(template.getTemplateName())){
                    // 摸版名字英文处理
                    TranslateName translate = dynamicConfigService.getNameLanguage(template.getTemplateName());
                    template.setTemplateNameEn(translate.getNameEn());
                    template.setTemplateNameFra(translate.getNameFra());
                    template.setTemplateNameSpa(translate.getNameSpa());
                    template.setTemplateNameDe(translate.getNameDe());
                    template.setTemplateNamePl(translate.getNamePl());
                    template.setTemplateNameAra(translate.getNameAra());
                }

                if (template.getPlanningCurves().size() <= 0) {
                    result.put("code", 500);
                    result.put("msg", DefineConstant.PeakShaving.TEMPLATE_CHECK_SIZE);
                    return result;
                }

                int id = planningMapper.getSeq();
                template.setTemId(id);
                Map<String, Object> check = this.checkData(template, id);
                if (null != check) {
                    return check;
                }
                //在入库前查询配了几段，将模板之外的剩余的值改为0
                int line = 0;
                List<PlanningCurve> curves = template.getPlanningCurves();
                if (curves.size() > 0) {
                    planningMapper.addPlanningCurveTemplate(template);
                    line = planningMapper.addPlanningCurve(curves, id);
                }
            } else {
                result.put("code", 500);
                result.put("msg", DefineConstant.PeakShaving.TEMPLATE_DATA_NOT_EXIST);
            }
        } catch (Exception e) {
            e.printStackTrace();
            result.put("code", 500);
            result.put("msg", DefineConstant.PeakShaving.ADD_TEMPLATE_FAIL);
        }
        return result;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Map<String, Object> modifyPlanningCurveTemplate(PlanningCurveTemplate template) {
        Map<String, Object> result = new HashMap<String, Object>(0);
        result.put("code", 200);
        result.put("msg", DefineConstant.PeakShaving.EDIT_TEMPLATE_SUCCESS);
        try {
            if (null != template && null != template.getTemId()) {
                if(StringUtil.isNotBlank(template.getTemplateName())){
                    // 摸版名字英文处理
                    TranslateName translate = dynamicConfigService.getNameLanguage(template.getTemplateName());
                    template.setTemplateNameEn(translate.getNameEn());
                    template.setTemplateNameFra(translate.getNameFra());
                    template.setTemplateNameSpa(translate.getNameSpa());
                    template.setTemplateNameDe(translate.getNameDe());
                    template.setTemplateNamePl(translate.getNamePl());
                    template.setTemplateNameAra(translate.getNameAra());
                }
                Integer templateId = template.getTemId();
                Map<String, Object> check = this.checkData(template, templateId);
                if (null != check) {
                    return check;
                }

                if (template.getPlanningCurves().size() <= 0) {
                    result.put("code", 500);
                    result.put("msg", DefineConstant.PeakShaving.TEMPLATE_CHECK_SIZE);
                    return result;
                }

                int modifyLine = planningMapper.modifyPlanningCurveTemplate(template);
                if (modifyLine > 0) {
                    int deleteLine = planningMapper.deleteCurves(templateId);
                }
                int addLine = 0;
                List<PlanningCurve> curves = template.getPlanningCurves();
                if (curves.size() > 0) {
                    addLine = planningMapper.addPlanningCurve(curves, templateId);
                }
            } else {
                result.put("code", 500);
                result.put("msg", DefineConstant.PeakShaving.TEMPLATE_DATA_NOT_EXIST);
            }
        } catch (Exception e) {
            e.printStackTrace();
            result.put("code", 500);
            result.put("msg", DefineConstant.PeakShaving.EDIT_TEMPLATE_FAIL);
        }
        return result;
    }

    private Map<String, Object> checkData(PlanningCurveTemplate template, Integer temId) {
        Map<String, Object> result = new HashMap<String, Object>(0);

        // 对模板编号和名称进行校验
        int i = 0;
        if (null != template.getTemplateNo() && !template.getTemplateNo().equals("")) {
            i = planningMapper.checkNo(template.getTemplateNo(), template.getStationId(), temId);
        } else {
            result.put("code", 400);
            result.put("msg", DefineConstant.PeakShaving.TEMPLATE_NO_NOT_NULL);
            return result;
        }

        if (i > 0) {
            result.put("code", 400);
            result.put("msg", DefineConstant.PeakShaving.TEMPLATE_NO_NOT_REPEAT);
            return result;
        }

        if (null != template.getTemplateNo() && !template.getTemplateNo().equals("")) {
            i = planningMapper.checkName(template.getTemplateName(), template.getStationId(), temId);
        } else {
            result.put("code", 400);
            result.put("msg", DefineConstant.PeakShaving.TEMPLATE_NAME_NOT_NULL);
            return result;
        }

        if (i > 0) {
            result.put("code", 400);
            result.put("msg", DefineConstant.PeakShaving.TEMPLATE_NAME_NOT_REPEAT);
            return result;
        }

        if (null != template.getTemplateNo() && template.getTemplateNo().length() > 10) {
            result.put("code", 400);
            result.put("msg", DefineConstant.PeakShaving.TEMPLATE_NO_TOO_LONG);
            return result;
        }

        if (null != template.getTemplateName() && template.getTemplateName().length() > 10) {
            result.put("code", 400);
            result.put("msg", DefineConstant.PeakShaving.TEMPLATE_NAME_TOO_LONG);
            return result;
        }

        if (null != template.getTemP() && template.getTemP() > 99999999) {
            result.put("code", 400);
            result.put("msg", DefineConstant.PeakShaving.TEMPLATE_P_ERROR);
            return result;
        }

        if (null != template.getSocUpper() && template.getSocUpper() > 99999999) {
            result.put("code", 400);
            result.put("msg", DefineConstant.PeakShaving.TEMPLATE_SOC_UPPER_ERROR);
            return result;
        }

        if (null != template.getSocLower() && template.getSocLower() > 99999999) {
            result.put("code", 400);
            result.put("msg", DefineConstant.PeakShaving.TEMPLATE_SOC_LOWER_ERROR);
            return result;
        }

        if (null != template.getCapacity() && template.getCapacity() > 99999999) {
            result.put("code", 400);
            result.put("msg", DefineConstant.PeakShaving.TEMPLATE_CAPACITY_ERROR);
            return result;
        }
        return null;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Map<String, Object> deletePlanningCurveTemplates(List<Integer> ids) {
        Map<String, Object> result = new HashMap<String, Object>(0);
        result.put("code", 200);
        result.put("msg", DefineConstant.PeakShaving.DELETE_SUCCESS);
        try {
            int i = planningMapper.deletePlanningCurveTemplates(ids);
            if (i > 0) {
                i = planningMapper.batchDeleteCurves(ids);
            } else {
                result.put("code", "400");
                result.put("msg", DefineConstant.PlanningCurve.DELETE_FAIL);
            }
        } catch (Exception e) {
            result.put("code", 500);
            result.put("msg", DefineConstant.PlanningCurve.SUCCESS);
        }
        return result;
    }


    @Override
    public Map<String, Object> batchImport(String fileName, MultipartFile file) throws Exception {
        Map<String, Object> result = new HashMap<String, Object>(0);
        if (!fileName.matches("^.+\\.(?i)(xls)$") && !fileName.matches("^.+\\.(?i)(xlsx)$")) {
            result.put("code", 500);
            result.put("msg", DefineConstant.PlanningCurve.FILE_FORMAT_ONLY);
            return result;
        }
        boolean isExcel2003 = true;
        if (fileName.matches("^.+\\.(?i)(xlsx)$")) {
            isExcel2003 = false;
        }
        InputStream is = file.getInputStream();
        Workbook wb = null;
        if (isExcel2003) {
            wb = new HSSFWorkbook(is);
        } else {
            wb = new XSSFWorkbook(is);
        }
        Sheet sheet = wb.getSheetAt(0);
        if (sheet != null) {
            result.put("code", 200);
            result.put("msg", DefineConstant.PlanningCurve.FILE_UPLOAD_SUCCESS);
        } else {
            result.put("code", 500);
            result.put("msg", DefineConstant.PlanningCurve.FILE_UPLOAD_ERROR_EMPTY_SHEET);
            return result;
        }

        List<PlanningCurveTemplate> templates = new ArrayList<PlanningCurveTemplate>(0);
        PlanningCurveTemplate template = new PlanningCurveTemplate();
        List<PlanningCurve> planningCurves = new ArrayList<>(0);
        PlanningCurve cur = null;

        try {
            int sheetLine = sheet.getLastRowNum();
            for (int r = 1; r <= sheetLine; r++) {
                cur = new PlanningCurve();
                Row row = sheet.getRow(r);
                // 如果row都取不到就认为下面根本没有数据，直接结束
                if (row == null) {
                    break;
                }

                if (row.getCell(8) != null) {
                    row.getCell(8).setCellType(CellType.STRING);
                    String startTime = row.getCell(8).getStringCellValue();
                    cur.setStartTime(startTime);
                }
                if (row.getCell(9) != null) {
                    row.getCell(9).setCellType(CellType.STRING);
                    String endTime = row.getCell(9).getStringCellValue();
                    cur.setEndTime(endTime);
                }
                if (row.getCell(10) != null) {
                    row.getCell(10).setCellType(CellType.STRING);
                    String p = row.getCell(10).getStringCellValue();
                    if (!p.equals("") && null != p) {
                        cur.setP(Double.valueOf(p));
                    }
                }

                planningCurves.add(cur);

                if ((null == sheet.getRow(r + 1) || isEmptyCell(sheet.getRow(r + 1).getCell(0))) && r != sheetLine) {
                    if (row.getCell(0) != null) {
                        row.getCell(0).setCellType(CellType.STRING);
                        String templateNo = row.getCell(0).getStringCellValue();
                        if (!templateNo.equals("") && null != templateNo) {
                            template.setTemplateNo(templateNo);
                        } else {
                            continue;
                        }
                    }

                    if ((row.getCell(1) != null && r != sheetLine) || sheet.getRow(r + 1) == null) {
                        row.getCell(1).setCellType(CellType.STRING);
                        String templateName = row.getCell(1).getStringCellValue();
                        if (!templateName.equals("") && null != templateName) {
                            template.setTemplateName(templateName);
                        } else {
                            continue;
                        }
                    }

                    //if (row.getCell(2) != null) {
                    //    row.getCell(2).setCellType(CellType.STRING);
                    //    String elecTemplateNo = row.getCell(2).getStringCellValue();
                    //    if (!elecTemplateNo.equals("") && null != elecTemplateNo) {
                    //        template.setElecTemplateId(Integer.valueOf(elecTemplateNo));
                    //    }
                    //}

                    if ((row.getCell(3) != null && r != sheetLine) || sheet.getRow(r + 1) == null) {
                        row.getCell(3).setCellType(CellType.STRING);
                        String status = row.getCell(3).getStringCellValue();
                        if (!status.equals("") && null != status) {
                            template.setStatus(Integer.valueOf(status));
                        } else {
                            continue;
                        }
                    }
                    if ((row.getCell(4) != null && r != sheetLine) || sheet.getRow(r + 1) == null) {
                        row.getCell(4).setCellType(CellType.STRING);
                        String temP = row.getCell(4).getStringCellValue();
                        if (!temP.equals("") && null != temP) {
                            template.setTemP(Double.valueOf(temP));
                        } else {
                            continue;
                        }
                    }
                    if ((row.getCell(5) != null && r != sheetLine) || sheet.getRow(r + 1) == null) {
                        row.getCell(5).setCellType(CellType.STRING);
                        String capacity = row.getCell(5).getStringCellValue();
                        if (!capacity.equals("") && null != capacity) {
                            template.setCapacity(Double.valueOf(capacity));
                        } else {
                            continue;
                        }
                    }
                    if ((row.getCell(6) != null && r != sheetLine) || sheet.getRow(r + 1) == null) {
                        row.getCell(6).setCellType(CellType.STRING);
                        String socUpper = row.getCell(6).getStringCellValue();
                        if (!socUpper.equals("") && null != socUpper) {
                            template.setSocUpper(Integer.valueOf(socUpper));
                        } else {
                            continue;
                        }
                    }
                    if ((row.getCell(7) != null && r != sheetLine) || sheet.getRow(r + 1) == null) {
                        row.getCell(7).setCellType(CellType.STRING);
                        String socLower = row.getCell(7).getStringCellValue();
                        if (!socLower.equals("") && null != socLower) {
                            template.setSocLower(Integer.valueOf(socLower));
                        } else {
                            continue;
                        }
                    }
                }

                if (r == sheetLine || (null != sheet.getRow(r + 1) && !isEmptyCell(sheet.getRow(r + 1).getCell(0)))) {
                    template.setPlanningCurves(planningCurves);
                    templates.add(template);
                    planningCurves = new ArrayList<>(0);
                    template = new PlanningCurveTemplate();
                }
            }
            // 组织好的数据入库
            for (PlanningCurveTemplate planningCurveTemplate : templates) {
                result = this.addPlanningCurveTemplate(planningCurveTemplate);
            }
        } catch (NumberFormatException e) {
            e.printStackTrace();
            result.put("code", 500);
            result.put("msg", DefineConstant.PlanningCurve.OPERATION_FAILED);
        }
        return result;
    }


    private boolean isEmptyCell(Cell cell) {
        if (cell == null || cell.getCellType().equals(CellType.BLANK)) {
            return true;
        }
        return false;
    }


    @Override
    public List<PlanningCurveTemplate> getPlanningCurveTemplate(PlanningCurveTemplate template) {
        List<PlanningCurveTemplate> planningCurveTemplates = planningMapper.getPlanningCurveTemplate(template);
        if (null != planningCurveTemplates && planningCurveTemplates.size() > 0) {
            for (PlanningCurveTemplate planningCurveTemplate : planningCurveTemplates) {
                if ( planningCurveTemplate.getStationId() != null ) {
                    Station station = stationService.selectById(planningCurveTemplate.getStationId());
                    planningCurveTemplate.setRatePower(station == null || station.getRatePower() == null ? null : station.getRatePower());
                }
            }
        }
        return planningCurveTemplates;
    }


    private List<PlanningCurve> processChartsDatas(List<PlanningCurve> planningCurves) {
        List<String> times = new ArrayList<String>();
        SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss");
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        for (int i = 0; i < 1440; i++) { // 1440 = 24 * 60，一天有 1440 分钟
            times.add(format.format(calendar.getTime()));
            calendar.add(Calendar.MINUTE, 1);
        }

        List<PlanningCurve> curves1 = new ArrayList<PlanningCurve>();
        PlanningCurve curveCopy = null;
        int index = 0;
        double p = 0.0;

        for (int i = 0; i < planningCurves.size(); i++) {
            for (int j = index; j < times.size(); j++) {
                curveCopy = new PlanningCurve();
                if (planningCurves.get(i).getStartTime().equals(times.get(j))) {
                    p = planningCurves.get(i).getP();
                }
                if (i + 1 < planningCurves.size() && j+1 < times.size()
                        && planningCurves.get(i + 1).getStartTime().equals(times.get(j+1))) {
                    index = j;
                    break;
                }
                curveCopy.setStartTime(times.get(j));
                curveCopy.setP(p);
                curves1.add(curveCopy);
            }
        }
        return curves1;
    }

    @Override
    public List<PlanningCurveTemplate> planningCurveTemplateChartData(PlanningCurveTemplate template) {
        List<PlanningCurveTemplate> planningCurveTemplates = planningMapper.getPlanningCurveTemplate(template);
        if (null != planningCurveTemplates && planningCurveTemplates.size() > 0) {
            for (PlanningCurveTemplate planningCurveTemplate : planningCurveTemplates) {
                Station station = stationService.selectById(planningCurveTemplate.getStationId());
                planningCurveTemplate.setRatePower(station == null || station.getRatePower() == null ? null : station.getRatePower());
                List<PlanningCurve> planningCurves = planningCurveTemplate.getPlanningCurves();
                List<PlanningCurve> planningCurves1 = processChartsDatas(planningCurves);
                System.out.println(planningCurves1);
                planningCurveTemplate.setPlanningCurves(planningCurves1);
            }
        }
        return planningCurveTemplates;
    }

    /**
     * 根据电站id生成计划曲线下发所需的json字符串
     * @param template
     * @return
     */
    @Override
    public String getJson(PlanningCurveTemplate template, UserDetailRespVO userDetail) {
        List<PlanningCurveTemplate> planningCurveTemplates = planningMapper.getPlanningCurveTemplate(template);
        StringBuilder sb = new StringBuilder();
        String version = "V1";
        sb.append("{");
        List<Map<String,Object>> data = new ArrayList<Map<String,Object>>(0);
        Map<String,Object> dataMap = null;
        LinkedList<LinkedHashMap<String,String>> curve = null;
        for (PlanningCurveTemplate planningCurveTemplate : planningCurveTemplates) {
            curve = new LinkedList<>();
            dataMap = new HashMap<>(0);
            List<PlanningCurve> planningCurves = planningCurveTemplate.getPlanningCurves();
            LinkedHashMap<String,String> map = null;
            for (int i = 0; i < planningCurves.size(); i++) {
                dataMap.put("temNo",planningCurves.get(i).getPlanningTemplateId());
                map = new LinkedHashMap<>(0);
                map.put("s",""+(i+1));
                String startTime = planningCurves.get(i).getStartTime();
                map.put("startHid",startTime.substring(0,2));
                map.put("startMid",startTime.substring(3,5));
                map.put("actvalueid",planningCurves.get(i).getP().toString());
                map.put("reavalueid",planningCurves.get(i).getQ().toString());
                curve.add(map);
            }
            if( curve.size() < 16 ){
                for (int i = curve.size()+1; i <= 16; i++) {
                    map = new LinkedHashMap<String,String>(0);
                    map.put("s",""+i);
                    map.put("startHid","0");
                    map.put("startMid","0");
                    map.put("actvalueid","0");
                    map.put("reavalueid","0");
                    curve.add(map);
                }
            }
            dataMap.put("curve",curve);
            data.add(dataMap);
        }
        String dataStr = JSON.toJSONString(data);
        // 文件版本号
        sb.append("\"version\":\""+version+"\",");
        // 当前时间(生成文件时间)
        sb.append("\"date\":\""+ DateUtil.now() +"\",");
        // 操作人(当前登陆人)
        if ( userDetail != null ) {
            sb.append("\"operator\":\""+userDetail.getUsername()+"\",");
        } else {
            sb.append("\"operator\":\"0\",");
        }
        // data数据长度
        sb.append("\"length\":\""+dataStr.length()+"\",");
        // 类型 0:使用文件  1:使用点号
        sb.append("\"planType\":\"0\",");
        sb.append("\"data\":"+dataStr+",");
        // 模板使用说明
        List<String> dateList = getDateList();
        List<Map<String,String>> dateMapping = new ArrayList<Map<String,String>>(0);

        /** todo: 用电站id查询已经配置好了策略信息 */
        List<PlanningCurveTactics> tactics = planningCurveTacticsMapper.getTacticsByStationId(template.getStationId());

        Map<String,String> mapping = null;
        Integer temId = 0;
        for (String date : dateList) {
            mapping = new HashMap<>(0);
            mapping.put("date",date);
            for (PlanningCurveTactics tactic : tactics) {
                DateTime parse = DateUtil.parse(date);
                if ( (tactic.getStartDate().before(parse) || tactic.getStartDate().compareTo(parse) == 0)
                        && (tactic.getEndDate().after(parse) || tactic.getEndDate().compareTo(parse) == 0) ) {
                    temId = tactic.getTemId();
                    break;
                }
            }
            mapping.put("temNo",temId.toString());
            dateMapping.add(mapping);
        }
        String mappingStr = JSONUtil.toJsonStr(dateMapping);
        // crc32校验
        sb.append("\"crc32\":\""+crc32(dataStr)+"\",");
        sb.append("\"dateMapping\":"+mappingStr+"");
        sb.append("}");
        System.err.println(sb.toString());
        //log.info("PlanningCurveService getJson:{}",sb.toString());
        return sb.toString();
    }

    private Long crc32(String data){
        // 创建CRC32对象
        CRC32 crc32 = new CRC32();
        // 提供要计算的数据
        byte[] bytes = data.getBytes();
        // 更新CRC32值
        crc32.update(bytes);
        // 获取最终CRC32值
        long crcValue = crc32.getValue();
        return crcValue;
    }

    private List<String> getDateList(){
        List<String> dateList = new ArrayList<String>(0);
        int year = DateUtil.year(new Date());
        for (int month = 1; month <= 12; month++) {
            YearMonth yearMonth = YearMonth.of(year, month);
            int daysInMonth = yearMonth.lengthOfMonth();
            List<LocalDate> dates = new ArrayList<>();
            for (int i = 1; i <= daysInMonth; i++) {
                LocalDate date = LocalDate.of(year, month, i);
                dates.add(date);
            }
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
            for (LocalDate date : dates) {
                String formattedDate = date.format(formatter);
                dateList.add(formattedDate);
            }
        }
        return dateList;
    }
}
