package com.ho.business.controller;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.fill.FillConfig;
import com.alibaba.excel.write.metadata.fill.FillWrapper;
import com.ho.business.entity.*;
import com.ho.business.service.EarningsCalculateMpptService;
import com.ho.business.service.EarningsCalculateService;
import com.ho.business.service.StationService;
import com.ho.business.util.QueuesUtil;
import com.ho.business.vo.OneKeyComputationVo;
import com.ho.business.vo.req.carbin.EarningsCalculateReq;
import com.ho.business.vo.resp.InverterResp.PowerGenerateRespVO;
import com.ho.business.vo.resp.cabin.EarningsCalculateResp;
import com.ho.common.tools.annotation.HzPermission;
import com.ho.common.tools.annotation.TokenIgnore;
import com.ho.common.tools.constant.CommonConstant;
import com.ho.common.tools.constant.ContextConstant;
import com.ho.common.tools.constant.PermissionConstant;
import com.ho.common.tools.constant.RedisKeyConstant;
import com.ho.common.tools.exception.BaseResponseCode;
import com.ho.common.tools.exception.BusinessException;
import com.ho.common.tools.exception.DataResult;
import com.ho.common.tools.service.RedisService;
import com.ho.common.tools.util.BigDecimalUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@RestController
@RequestMapping(ContextConstant.BUSINESS + "earningsCalculate")
@Api(tags = "尖峰平谷电量电价")
@Slf4j
public class EarningsCalculateController {
    public static final Integer PAGE_LIST_TYPE = 0;
    public static final Integer REPORT_LIST_TYPE = 1;

    @Autowired
    private RedisService redisService;

    DecimalFormat df = new DecimalFormat("#.00");

    @Autowired
    EarningsCalculateService earningsCalculateService;

    @Autowired
    EarningsCalculateMpptService earningsCalculateMpptService;

    @Autowired
    private StationService stationService;

    @Autowired
    BigDecimalUtil bigDecimalUtil;

    @PostMapping("/getTotal")
    @ApiOperation(value = "获取月发电量报表")
    @TokenIgnore
    public DataResult<EarningsCalculateResp> getTotal(@RequestBody EarningsCalculateReq earningsCalculateReq,HttpServletRequest request){
        earningsCalculateReq.setLang(request.getHeader(CommonConstant.LANG));
        EarningsCalculateResp total = earningsCalculateService.getTotal(earningsCalculateReq,PAGE_LIST_TYPE);
        if( earningsCalculateReq != null && earningsCalculateReq.getStationId() != null ){
            Integer stationId = earningsCalculateReq.getStationId();
            OneKeyProgress oneKeyProgress = (OneKeyProgress) redisService.hget(QueuesUtil.PROGRESS_REDIS_KEY, stationId.toString());
            if( oneKeyProgress != null && earningsCalculateReq.getTime() != null
                    && oneKeyProgress.getDate() != null
                    && oneKeyProgress.getDate().equals(earningsCalculateReq.getTime())){
                double progress = oneKeyProgress.getProgress()==null?1:oneKeyProgress.getProgress();
                String format = df.format(progress * 100);
                total.setProgress(format);
                total.setFinish(0);
                if ( format.equals("100.00") ) {
                    total.setFinish(1);
                }
            }
        }
        return DataResult.success(total);
    }

    @PostMapping("/getPvMonthData")
    @ApiOperation(value = "mppt月发电、收益(使用mppt计算)")
    public DataResult<List<PowerGenerateRespVO>> getPvMonthData(@RequestBody EarningsCalculateReq req) {
        //获取光伏放电、收益
        List<PowerGenerateRespVO> pvList = earningsCalculateService.getPvMonthData(req);
        for (PowerGenerateRespVO pcsElecData : pvList) {
            bigDecimalUtil.keepTwoDecimalPlaces(pcsElecData);
            bigDecimalUtil.ifIsNUll(pcsElecData);
        }
        return DataResult.success(pvList);
    }
    @TokenIgnore
    @PostMapping("/all")
    @ApiOperation(value = "查询所有电站接口")
    public void all(@RequestBody(required = false) String beginTime) {
        try {
            log.info("定时任务调用了/earningsCalculate/all方法:{}","执行了删除操作");
            /** todo: 先删除一下昨日数据 */
            /** start */
            DateTime yesterday = DateUtil.yesterday();
            String yesterdayStr = DateUtil.formatDate(yesterday);
            if ( beginTime != null  ) {
                int i = earningsCalculateService.deleteByDay(beginTime, null);
            } else {
                beginTime = yesterdayStr;
                int i = earningsCalculateService.deleteByDay(yesterdayStr, null);
            }
//            QueuesUtil.date = beginTime;
            /** end */
        } catch (Exception e) {
            log.error("删除昨日数据失败:{}",e.getMessage());
        }
        List<Station> stations = stationService.selectAll();
        //批量算的时候只计算
        stations = stations.stream().filter(i -> CommonConstant.ONE.equals(i.getStatus())).collect(Collectors.toList());
        earningsCalculateService.queryDeviceByStationId(stations,null,beginTime);
    }

    @TokenIgnore
    @PostMapping("/allMpptIncome")
    @ApiOperation(value = "计算所有电站Mppt电价收益")
    public void allMpptIncome(@RequestBody(required = false) String beginTime) {
        try {
            /*
             * 定时任务 如果没有时间参数 就每天跑昨日数据
             * 如果有 beginTime 参数不为空，则先清除beginTime 时间的收益数据重新计算
             */
            DateTime yesterday = DateUtil.yesterday();
            String yesterdayStr = DateUtil.formatDate(yesterday);
            if ( beginTime != null  ) {
                int i = earningsCalculateMpptService.deleteByDay(beginTime, null);
            } else {
                beginTime = yesterdayStr;
                int i = earningsCalculateMpptService.deleteByDay(yesterdayStr, null);
            }
        } catch (Exception e) {
            log.error("删除昨日数据失败:{}",e.getMessage());
        }
        List<Station> stations = stationService.selectAll();
        //批量算的时候只计算电站是在投的，且是接入光伏mppt的
        stations = stations.stream().filter(i -> CommonConstant.ONE.equals(i.getStatus())
                &&CommonConstant.ONE.equals(i.getInverterFlag())).collect(Collectors.toList());
        earningsCalculateMpptService.allMpptIncome(stations,beginTime);
    }
    @TokenIgnore
    @PostMapping("/allTodayMpptIncome")
    @ApiOperation(value = "计算所有电站Mppt-今日收益")
    public void allTodayMpptIncome(@RequestBody(required = false) String beginTime) {
        DateTime nowDay = DateUtil.date();
        String nowDayStr = DateUtil.formatDate(nowDay);
        if ( beginTime == null  ) {
            beginTime = nowDayStr;
        }
        List<Station> stations = stationService.selectAll();
        //批量算的时候只计算电站是在投的，且是接入光伏mppt的
        stations = stations.stream().filter(i -> CommonConstant.ONE.equals(i.getStatus())
                &&CommonConstant.ONE.equals(i.getInverterFlag())).collect(Collectors.toList());
        earningsCalculateMpptService.todayMpptIncome(stations,beginTime);
    }


    private List<String> getBetweenDate(String begin,String end){
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        List<String> betweenList = new ArrayList<String>();

        try{
            Calendar startDay = Calendar.getInstance();
            startDay.setTime(format.parse(begin));
            startDay.add(Calendar.DATE, -1);
            while(true){
                startDay.add(Calendar.DATE, 1);
                Date newDate = startDay.getTime();
                String newend=format.format(newDate);
                betweenList.add(newend);
                if(end.equals(newend)){
                    break;
                }
            }
        }catch (Exception e) {
            e.printStackTrace();
        }
        return betweenList;
    }

    @TokenIgnore
    @PostMapping("/export")
    @ApiOperation(value = "导出")
    public void export(HttpServletRequest req, HttpServletResponse response, @RequestBody EarningsCalculateReq earningsCalculateReq) {
        String lang = req.getHeader(CommonConstant.LANG);
        earningsCalculateReq.setLang(lang);
        EarningsCalculateResp total = earningsCalculateService.getTotal(earningsCalculateReq,PAGE_LIST_TYPE);
        if(total.getCharge()==null){
            total.setCharge(new ArrayList<>());
            total.setDischarge(new ArrayList<>());
        }
        ServletOutputStream out = null;
        try {
            out = response.getOutputStream();
            response.setContentType("multipart/form-data");
            response.setCharacterEncoding("UTF-8");
            //文件名字
            String fileName = "demo.xlsx";
            response.setHeader("Content-disposition", "attachment;filename=" +fileName);
            String path="template/earningsTemplate.xlsx";
            if(CommonConstant.langTemp.EN_US.equals(lang)){
                path="template/earningsTemplateen_US.xlsx";
            }else if(CommonConstant.langTemp.FR_FR.equals(lang)){
                path="template/earningsTemplateen_FRA.xlsx";
            }else if(CommonConstant.langTemp.ES_ES.equals(lang)){
                path="template/earningsTemplateen_SPA.xlsx";
            }else if(CommonConstant.langTemp.DE_DE.equals(lang)){
                path="template/earningsTemplateen_DE.xlsx";
            }else if(CommonConstant.langTemp.PL_PL.equals(lang)){
                path="template/earningsTemplateen_PL.xlsx";
            }else if(CommonConstant.langTemp.AR_EG.equals(lang)){
                path="template/earningsTemplateen_ARA.xlsx";
            }
            //文件模板输入流
            InputStream inputStream = new ClassPathResource(path).getInputStream();

            // 添加合并单元格地址
            //List<CellRangeAddress> list = new ArrayList<>();
            ////new CellRangeAddress(开始行，结束行，开始列，结束列)
            //list.add(new CellRangeAddress(4, 14, 0, 1));
            //list.add(new CellRangeAddress(4, 14, 2, 11));
            //list.add(new CellRangeAddress(4, 14, 12, 13));
            //ExcelWriter writer = EasyExcel.write(out).withTemplate(inputStream).build();
            //WriteSheet sheet = EasyExcel.writerSheet().registerWriteHandler(new MyHandler(0,list)).build();
            //填充列表开启自动换行,自动换行表示每次写入一条list数据是都会重新生成一行空行,此选项默认是关闭的,需要提前设置为true

            ExcelWriter writer = EasyExcel.write(out).withTemplate(inputStream).build();
            WriteSheet sheet = EasyExcel.writerSheet().build();
            FillConfig fillConfig = FillConfig.builder().forceNewRow(true).build();

            List<EarningsCalculate> charge = new ArrayList<EarningsCalculate>();
            List<EarningCalculateDischarge> discharge = new ArrayList<EarningCalculateDischarge>();
            EarningCalculateDischarge earningCalculateDischarge = null;

            /** todo: 拆分费率数据 */
            /** start */
            if( total != null && total.getList() != null ){
                List<EarningsCalculate> list = total.getList();
                for (EarningsCalculate earningsCalculate : list) {
                    if( earningsCalculate.getType() == 0 ){
                        charge.add(earningsCalculate);
                    } else {
                        earningCalculateDischarge = new EarningCalculateDischarge();
                        earningCalculateDischarge.setDischarge(earningsCalculate.getDigital());
                        earningCalculateDischarge.setDisElec(earningsCalculate.getElec());
                        earningCalculateDischarge.setDisRateType(earningsCalculate.getRateType());
                        discharge.add(earningCalculateDischarge);
                    }
                }
            }
            /** end */

            /** todo: 组装导出数据 */
            /** start */
            List<EarningsCalculate> newCharge = new ArrayList<EarningsCalculate>();
            EarningsCalculate earnings = null;
            int index = 0;
            if ( discharge.size() == charge.size() ) {
                for (EarningsCalculate earningsCalculate : charge) {
                    earningsCalculate.setDischarge(discharge.get(index).getDischarge());
                    earningsCalculate.setDisElec(discharge.get(index).getDisElec());
                    earningsCalculate.setDisRateType(discharge.get(index).getDisRateType());
                    index++;
                }
            } else if ( discharge.size() > charge.size() ){
                for (EarningCalculateDischarge calculateDischarge : discharge) {
                    if( index < charge.size() ){
                        charge.get(index).setDischarge(calculateDischarge.getDischarge());
                        charge.get(index).setDisElec(calculateDischarge.getDisElec());
                        charge.get(index).setDisRateType(calculateDischarge.getDisRateType());
                    } else {
                        earnings = new EarningsCalculate();
                        earnings.setDischarge(calculateDischarge.getDischarge());
                        earnings.setDisElec(calculateDischarge.getDisElec());
                        earnings.setDisRateType(calculateDischarge.getDisRateType());
                        newCharge.add(earnings);
                    }
                }
            } else if ( discharge.size() < charge.size() ){
                for (EarningsCalculate earningsCalculate : charge) {
                    if( index < discharge.size() ){
                        earningsCalculate.setDischarge(discharge.get(index).getDischarge());
                        earningsCalculate.setDisElec(discharge.get(index).getDisElec());
                        earningsCalculate.setDisRateType(discharge.get(index).getDisRateType());
                    }
                }
            }
            newCharge.addAll(charge);
            /** end */


            writer.fill(new FillWrapper("charge", newCharge), fillConfig, sheet);
            //填充数据
            writer.fill(total,fillConfig,sheet);
            //填充完成
            writer.finish();
            out.flush();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @TokenIgnore
    @PostMapping("/exportReport")
    @ApiOperation(value = "导出")
    public void exportReport(HttpServletRequest req, HttpServletResponse response, @RequestBody EarningsCalculateReq earningsCalculateReq) {
        String lang = req.getHeader(CommonConstant.LANG);
        earningsCalculateReq.setLang(lang);
        EarningsCalculateResp total = earningsCalculateService.getTotal(earningsCalculateReq,REPORT_LIST_TYPE);
        if(total.getCharge()==null){
            total.setCharge(new ArrayList<>());
            total.setDischarge(new ArrayList<>());
        }
        ServletOutputStream out = null;
        try {
            out = response.getOutputStream();
            response.setContentType("multipart/form-data");
            response.setCharacterEncoding("UTF-8");
            //文件名字
            String fileName = "demo.xlsx";
            response.setHeader("Content-disposition", "attachment;filename=" +fileName);
            String path="template/earningsUserTemplate.xlsx";
            if(CommonConstant.langTemp.EN_US.equals(lang)){
                path="template/earningsUserTemplateen_US.xlsx";
            }else if(CommonConstant.langTemp.FR_FR.equals(lang)){
                path="template/earningsUserTemplateen_FRA.xlsx";
            }else if(CommonConstant.langTemp.ES_ES.equals(lang)){
                path="template/earningsUserTemplateen_SPA.xlsx";
            }else if(CommonConstant.langTemp.DE_DE.equals(lang)){
                path="template/earningsUserTemplateen_DE.xlsx";
            }else if(CommonConstant.langTemp.PL_PL.equals(lang)){
                path="template/earningsUserTemplateen_Pl.xlsx";
            }else if(CommonConstant.langTemp.AR_EG.equals(lang)){
                path="template/earningsUserTemplateen_ARA.xlsx";
            }
            //文件模板输入流
            InputStream inputStream = new ClassPathResource(path).getInputStream();

            // 添加合并单元格地址
            //List<CellRangeAddress> list = new ArrayList<>();
            ////new CellRangeAddress(开始行，结束行，开始列，结束列)
            //list.add(new CellRangeAddress(4, 14, 0, 1));
            //list.add(new CellRangeAddress(4, 14, 2, 11));
            //list.add(new CellRangeAddress(4, 14, 12, 13));
            //ExcelWriter writer = EasyExcel.write(out).withTemplate(inputStream).build();
            //WriteSheet sheet = EasyExcel.writerSheet().registerWriteHandler(new MyHandler(0,list)).build();
            //填充列表开启自动换行,自动换行表示每次写入一条list数据是都会重新生成一行空行,此选项默认是关闭的,需要提前设置为true

            ExcelWriter writer = EasyExcel.write(out).withTemplate(inputStream).build();
            WriteSheet sheet = EasyExcel.writerSheet().build();
            FillConfig fillConfig = FillConfig.builder().forceNewRow(true).build();

            List<EarningsCalculate> charge = new ArrayList<EarningsCalculate>();
            List<EarningCalculateDischarge> discharge = new ArrayList<EarningCalculateDischarge>();
            EarningCalculateDischarge earningCalculateDischarge = null;

            /** todo: 拆分费率数据 */
            /** start */
            if( total != null && total.getList() != null ){
                List<EarningsCalculate> list = total.getList();
                for (EarningsCalculate earningsCalculate : list) {
                    if( earningsCalculate.getType() == 0 ){
                        charge.add(earningsCalculate);
                    } else {
                        earningCalculateDischarge = new EarningCalculateDischarge();
                        earningCalculateDischarge.setDischarge(earningsCalculate.getDigital());
                        earningCalculateDischarge.setDisElec(earningsCalculate.getElec());
                        earningCalculateDischarge.setDisRateType(earningsCalculate.getRateType());
                        discharge.add(earningCalculateDischarge);
                    }
                }
            }
            /** end */

            /** todo: 组装导出数据 */
            /** start */
            List<EarningsCalculate> newCharge = new ArrayList<EarningsCalculate>();
            EarningsCalculate earnings = null;
            int index = 0;
            if ( discharge.size() == charge.size() ) {
                for (EarningsCalculate earningsCalculate : charge) {
                    earningsCalculate.setDischarge(discharge.get(index).getDischarge());
                    earningsCalculate.setDisElec(discharge.get(index).getDisElec());
                    earningsCalculate.setDisRateType(discharge.get(index).getDisRateType());
                    index++;
                }
            } else if ( discharge.size() > charge.size() ){
                for (EarningCalculateDischarge calculateDischarge : discharge) {
                    if( index < charge.size() ){
                        charge.get(index).setDischarge(calculateDischarge.getDischarge());
                        charge.get(index).setDisElec(calculateDischarge.getDisElec());
                        charge.get(index).setDisRateType(calculateDischarge.getDisRateType());
                    } else {
                        earnings = new EarningsCalculate();
                        earnings.setDischarge(calculateDischarge.getDischarge());
                        earnings.setDisElec(calculateDischarge.getDisElec());
                        earnings.setDisRateType(calculateDischarge.getDisRateType());
                        newCharge.add(earnings);
                    }
                }
            } else if ( discharge.size() < charge.size() ){
                for (EarningsCalculate earningsCalculate : charge) {
                    if( index < discharge.size() ){
                        earningsCalculate.setDischarge(discharge.get(index).getDischarge());
                        earningsCalculate.setDisElec(discharge.get(index).getDisElec());
                        earningsCalculate.setDisRateType(discharge.get(index).getDisRateType());
                    }
                }
            }
            newCharge.addAll(charge);
            /** end */
            writer.fill(new FillWrapper("charge", newCharge), fillConfig, sheet);
            //填充数据
            writer.fill(total,fillConfig,sheet);
            //填充完成
            writer.finish();
            out.flush();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }


    @TokenIgnore
    @PostMapping("/freezeMonthTotalEle")
    @ApiOperation(value = "冻结月度总充总放")
    public void freezeMonthTotalEle(){
        /** todo: 查询所有电站,为所有电站进行月度总充总放做冻结(加上偏移量之后的冻结值) */
        List<Station> stations = stationService.selectAll();
        earningsCalculateService.freezeMonthTotalEle(stations);
    }

    @TokenIgnore
    @PostMapping("/testTemplateCurve")
    @ApiOperation(value = "测试获取电价模板")
    public DataResult<List<EarningsCalculateSub>> testTemplateCurve(){
        List<EarningsCalculateSub> earningsCalculateSubs = earningsCalculateService.queryElecTemplateSubByStationId(401, 0, DateUtil.now());
        return DataResult.success(earningsCalculateSubs);
    }

    @TokenIgnore
    @PostMapping("/testRateTemplateCurve")
    @ApiOperation(value = "测试获取电价模板")
    public DataResult<List<EarningsCalculateSub>> testRateTemplateCurve(){
        List<EarningsCalculateSub> earningsCalculateSubs = earningsCalculateService.queryElecRateTemplateSubByStationId(401, 0, DateUtil.now());
        return DataResult.success(earningsCalculateSubs);
    }

    @TokenIgnore
    @PostMapping("/oneKeyComputation")
    @ApiOperation(value = "一键重算")
    @HzPermission(PermissionConstant.ONEKEYCOMPUTATION)
    public DataResult<Map<String,Object>> oneKeyComputation( @RequestBody OneKeyComputationVo vo) {
        Map<String,Object> result = new HashMap<String,Object>(0);
        result.put("msg","");
        result.put("progress","");
        result.put("finish","");
        // 重算执行标识,防止重复触发
        if( vo == null || vo.getStationId() == null ){
            throw new BusinessException(BaseResponseCode.NON_DATA);
        }
        Integer stationId = vo.getStationId();
        // 判断队列里是否已经存在需要计算的数据,如果有则不继续计算,给页面扔出提示,阻止重复执行
        OneKeyProgress oneKeyProgress = (OneKeyProgress) redisService.hget(QueuesUtil.PROGRESS_REDIS_KEY, stationId.toString());
        if ( oneKeyProgress == null && vo.getStartTime() != null && vo.getEndTime() != null ) {
            List<Station> stations = stationService.selectAll();
            vo.setStations(stations);
            QueuesUtil.setOneKeyComputationMap(stationId,vo);
            result.put("msg","正在计算中!");
            result.put("progress",0);
            result.put("finish",0);
            OneKeyProgress progress = new OneKeyProgress();
            progress.setProgress(0.0);
            redisService.hset(QueuesUtil.PROGRESS_REDIS_KEY,vo.getStationId().toString(),progress);
        } else if( oneKeyProgress != null ){
            result.put("msg","正在计算中!");
            double progress = oneKeyProgress.getProgress()==null?1:oneKeyProgress.getProgress();
            String format = df.format(progress * 100);
            result.put("progress",format);
            result.put("finish",0);
            if ( format.equals("100.00") ) {
                result.put("finish",1);
                result.put("msg","计算完成!");
                redisService.hdel(QueuesUtil.PROGRESS_REDIS_KEY, stationId.toString());
            }
        }
        return DataResult.success(result);
    }


    @TokenIgnore
    @PostMapping("/getOneKeyComputationProgress")
    @ApiOperation(value = "一键重算进度查询")
    public DataResult<Map<String,Object>> getOneKeyComputationProgress( @RequestBody OneKeyComputationVo vo) {
        Map<String,Object> result = new HashMap<String,Object>(0);
        result.put("msg","");
        result.put("progress","");
        result.put("finish","");
        // 重算执行标识,防止重复触发
        if( vo == null || vo.getStationId() == null ){
            throw new BusinessException(BaseResponseCode.NON_DATA);
        }
        Integer stationId = vo.getStationId();
        // 判断队列里是否已经存在需要计算的数据,如果有则不继续计算,给页面扔出提示,阻止重复执行
        OneKeyProgress oneKeyProgress = (OneKeyProgress) redisService.hget(QueuesUtil.PROGRESS_REDIS_KEY, stationId.toString());
       if( oneKeyProgress != null ){
            result.put("msg","正在计算中!");
            double progress = oneKeyProgress.getProgress()==null?1:oneKeyProgress.getProgress();
            String format = df.format(progress * 100);
            result.put("progress",format);
            result.put("finish",0);
            if ( format.equals("100.00") ) {
                result.put("finish",1);
                result.put("msg","计算完成!");
                redisService.hdel(QueuesUtil.PROGRESS_REDIS_KEY, stationId.toString());
//                QueuesUtil.removeOneKeyProgress(stationId);
            }
        }
        return DataResult.success(result);
    }



}
