package com.ho.business.controller;

import com.ho.business.entity.*;
import com.ho.business.feignclient.FileCenterFeignClient;
import com.ho.business.service.PeakShavingService;
import com.ho.business.service.PlanningCurveIssueService;
import com.ho.business.service.StationSnService;
import com.ho.business.vo.Holiday;
import com.ho.business.vo.PolicyConfigPlanVo;
import com.ho.business.vo.req.PolicyConfigData;
import com.ho.business.vo.resp.planningCurve.PlanningIssueQueryVo;
import com.ho.common.tools.annotation.HzPermission;
import com.ho.common.tools.annotation.TokenIgnore;
import com.ho.common.tools.constant.*;
import com.ho.common.tools.entity.SimpleUser;
import com.ho.common.tools.entity.UserDetailRespVO;
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 io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
import org.apache.commons.compress.compressors.gzip.GzipCompressorOutputStream;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mock.web.MockMultipartFile;
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.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.math.BigDecimal;
import java.util.*;

/*
* @auther catkins
* @Date 10:50 2024/1/8
*  削峰填谷
*/
@RestController
@RequestMapping(ContextConstant.BUSINESS + "peakShaving")
@Api(tags = "削峰填谷")
@Slf4j
public class PeakShavingController {

    @Autowired
    private PeakShavingService peakShavingService;

    @Autowired
    RedisService redisService;

    @Autowired
    PlanningCurveIssueService planningCurveIssueService;

    public static final String JSON_FILE_NAME = "svc_plantemplate.json";

    public static final String TAR_GZ_FILE_PATH = "/usr/temporaryFiles/svc_plantemplate.tar.gz";

    public static final String FILE_PATH = "/deploy/sems/data";

    public static final String DEVICE_TYPE  = "plan";

    @Autowired
    StationSnService stationSnService;

    @Autowired
    FileCenterFeignClient fileCenterFeignClient;

    @PostMapping("/add")
    @ApiOperation(value = "新增计划曲线模板")
    @TokenIgnore
    public DataResult add(HttpServletRequest request, @RequestBody PlanningCurveTemplate template){
        String token = request.getHeader(RedisKeyConstant.User.ACCESS_TOKEN);
        SimpleUser simpleUser = redisService.getSimpleUserByToken(token);
        if (null != simpleUser && null != template) {
            template.setGroupId(simpleUser.getGroupId());
        }
        Map<String, Object> result = peakShavingService.addPlanningCurveTemplate(template);
        return DataResult.success(result);
    }

    @PostMapping("/modify")
    @ApiOperation(value = "修改计划曲线模板")
    @TokenIgnore
    public DataResult modify(@RequestBody PlanningCurveTemplate planningCurveTemplate){
        Map<String, Object> result = peakShavingService.modifyPlanningCurveTemplate(planningCurveTemplate);
        return DataResult.success(result);
    }

    @PostMapping("/delete")
    @ApiOperation(value = "删除计划曲线模板")
    @TokenIgnore
    @HzPermission(PermissionConstant.BUSINESS_PEAK_DELETE)
    public DataResult delete(@RequestBody PlanningCurveTemplate planningCurveTemplate){
        if( planningCurveTemplate == null || planningCurveTemplate.getTemId() == null ){
            throw new BusinessException(BaseResponseCode.NON_DATA);
        }
        Map<String, Object> result = peakShavingService.deletePlanningCurveTemplates(planningCurveTemplate);
        return DataResult.success(result);
    }

    @PostMapping("queryTemplates")
    @ApiOperation(value = "模板列表查询")
    @TokenIgnore
    public DataResult queryTemplates(@RequestBody PlanningCurveTemplate template) {
        List<PlanningCurveTemplate> planningCurveTemplates = peakShavingService.getPlanningCurveTemplates(template);
        return DataResult.success(planningCurveTemplates);
    }


    @PostMapping("queryTableTemplates")
    @ApiOperation(value = "模板列表查询")
    @TokenIgnore
    public DataResult queryTableTemplates(@RequestBody PlanningCurveTemplate template) {
        List<PlanningCurveTableTemplate> planningCurveTemplates = peakShavingService.getTableTemplates(template);
        return DataResult.success(planningCurveTemplates);
    }

    /**
     * 编辑页面 查看详情接口
     *
     * @param template
     * @return
     */
    @PostMapping("queryTemplateDetail")
    @ApiOperation(value = "计划曲线详情")
    @TokenIgnore
    public DataResult planningCurveTemplateDetail(@RequestBody PlanningCurveTemplate template) {
        PlanningCurveTemplate planningCurveTemplate = peakShavingService.getPlanningCurveTemplate(template);
        return DataResult.success(planningCurveTemplate);
    }

    @PostMapping("queryTemplateCurves")
    @ApiOperation(value = "计划曲线,echarts图数据")
    @TokenIgnore
    public DataResult queryTemplateCurves(@RequestBody PlanningCurveTemplate template) {
        if( null == template || null == template.getStationId() ){
            throw new BusinessException(BaseResponseCode.NON_DATA);
        }
        List<List<PlanningCurve>> curves = peakShavingService.queryTemplateCurves(template);
        return DataResult.success(curves);
    }

//    @PostMapping("sendTemplateByDay")
//    @ApiOperation(value = "发送计划曲线模板(此方法为一天执行一次)")
//    @TokenIgnore
//    public void sendTemplateByDay(){
//        log.error("定时任务调用开始>>>>>>>>>>>>>>>>{}","发送计划曲线模板(此方法为一天执行一次)");
//        int type = 1;
//        peakShavingService.sendData(type);
//    }

//    @PostMapping("sendTemplateByMonth")
//    @ApiOperation(value = "发送计划曲线模板(此方法为一个月执行一次)")
//    @TokenIgnore
//    public void sendTemplateByMonth(){
//        log.error("定时任务调用开始>>>>>>>>>>>>>>>>{}","发送计划曲线模板(此方法为一个月执行一次)");
//        int type = 2;
//        peakShavingService.sendData(type);
//    }


    @PostMapping("sendTemplateFile")
    @ApiOperation(value = "组装json文件并下发到计划曲线设备")
    @TokenIgnore
    public DataResult sendTemplateFile(HttpServletRequest request, HttpServletResponse response, @RequestBody PlanningIssueQueryVo vo){
        if( vo == null || vo.getStationId() == null){
            throw new BusinessException(BaseResponseCode.NON_DATA);
        }
        // 如果对象里的刷新时间都是空的,和前端确定的方式是立即执行,那么则获取服务器时间10分钟之后的时间做为参数
        if( vo.getPlanRefreshH() == -1 && vo.getPlanRefreshM() == -1 ){
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(new Date());
            calendar.add(Calendar.MINUTE,10);
            vo.setPlanRefreshH(calendar.get(Calendar.HOUR_OF_DAY));
            vo.setPlanRefreshM(calendar.get(Calendar.MINUTE));
        }

        Integer stationId = vo.getStationId();
        // 根据电站id查询设备srcId
        Integer srcId = peakShavingService.queryIssueDevice(stationId);
        // 根据电站id查询电站sn号
        String sn = peakShavingService.getSnByStationId(stationId);
        vo.setSrcId(srcId);
        vo.setSn(sn);
        // 查询下发参数
        List<Map<String, Object>> issueDatas = planningCurveIssueService.getPlanCurveIssueData(vo);
        // 判断下发参数是否为空,如果为空则不继续处理
        if( issueDatas == null || issueDatas.size() <= 0 ){
            throw new BusinessException(BaseResponseCode.SEND_DATA_IS_EXISTS);
        }
        PlanningTemplateVo planningTemplateVo = new PlanningTemplateVo();
        planningTemplateVo.setStationId(stationId);
        List<OrderIssuedVO> orderIssuedVOS = processOrderIssuedVO(issueDatas);
        planningTemplateVo.setOrderIssuedReqVO(orderIssuedVOS);
        Map<String, Object> result = new HashMap<String, Object>(0);
        //当前登陆人
        String token = request.getHeader(RedisKeyConstant.User.ACCESS_TOKEN);
        UserDetailRespVO userDetail = redisService.getUserDetailByToken(token);
        String json = peakShavingService.getJson(planningTemplateVo, userDetail);
        // json字符串写出json文件,方便后面压缩
        wirteFile(JSON_FILE_NAME,json);
        // 取得json文件
        File fileToCompress = new File(JSON_FILE_NAME);
        // 生成一个空的压缩文件
        File tarGzFile = new File(TAR_GZ_FILE_PATH);
//        File tarGzFile = new File("D:/svc_plantemplate.tar.gz");

        // 对json文件进行压缩
        result = compressFileToTarGz(fileToCompress, tarGzFile);

        if( fileToCompress.exists() ){
            if (fileToCompress.delete()) {
                System.out.println("临时文件删除成功！");
            } else {
                System.out.println("临时文件删除失败！");
            }
        } else {
            System.out.println("临时文件不存在！");
        }
        result = uploadFile(planningTemplateVo,tarGzFile);
        if( tarGzFile.exists() ){
            if (tarGzFile.delete()) {
                System.out.println("临时压缩包删除成功！");
            } else {
                System.out.println("临时压缩包删除失败！");
            }
        } else {
            System.out.println("临时压缩包不存在！");
        }
        return DataResult.success(result);
    }

    public static void wirteFile(String filePath,String json){
        try (FileWriter writer = new FileWriter(filePath, true)) {
            writer.write(json);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    // 处理下发参数,组装成对象
    private List<OrderIssuedVO> processOrderIssuedVO(List<Map<String, Object>> issueDatas){
        List<OrderIssuedVO> list = new ArrayList<>();
        OrderIssuedVO orderIssuedVO = null;
        for (Map<String, Object> issueData : issueDatas) {
            orderIssuedVO = new OrderIssuedVO();
            if( issueData.containsKey("col") && issueData.get("col") != null ){
                orderIssuedVO.setCol(issueData.get("col").toString());
            }
            if( issueData.containsKey("minValue") && issueData.get("minValue") != null ){
                orderIssuedVO.setMinValue(new BigDecimal(issueData.get("minValue").toString()));
            }
            if( issueData.containsKey("maxValue") && issueData.get("maxValue") != null){
                orderIssuedVO.setMaxValue(new BigDecimal(issueData.get("maxValue").toString()));
            }
            if( issueData.containsKey("modifyValue") && issueData.get("modifyValue") != null){
                orderIssuedVO.setModifyValue(new BigDecimal(issueData.get("modifyValue").toString()));
            }
            if( issueData.containsKey("sn") && issueData.get("sn") != null ){
                orderIssuedVO.setSn(issueData.get("sn").toString());
            }
            if( issueData.containsKey("srcId") && issueData.get("srcId") != null ){
                orderIssuedVO.setSrcId(Integer.parseInt(issueData.get("srcId").toString()));
            }
            if( issueData.containsKey("stationId") && issueData.get("stationId") != null ){
                orderIssuedVO.setStationId(Integer.parseInt(issueData.get("stationId").toString()));
            }
            list.add(orderIssuedVO);
        }
        return list;
    }

    public static Map<String, Object>  compressFileToTarGz(File fileToCompress, File tarGzFile){
        Map<String, Object> result = new HashMap<String, Object>(0);
        try (FileInputStream fis = new FileInputStream(fileToCompress);
             FileOutputStream fos = new FileOutputStream(tarGzFile);
             GzipCompressorOutputStream gzos = new GzipCompressorOutputStream(fos);
             TarArchiveOutputStream taos = new TarArchiveOutputStream(gzos)) {
            TarArchiveEntry entry = new TarArchiveEntry(fileToCompress);
            entry.setSize(fileToCompress.length());
            taos.putArchiveEntry(entry);
            byte[] buffer = new byte[1024];
            int bytesRead;
            while ((bytesRead = fis.read(buffer)) != -1) {
                taos.write(buffer, 0, bytesRead);
            }
            taos.closeArchiveEntry();
        } catch (IOException e) {
            e.printStackTrace();
            result.put("code", 500);
            result.put("msg", DefineConstant.PeakShaving.TAR_FILE_ISSUE_ERROR);
        }
        return result;
    }

    private Map<String, Object> uploadFile(PlanningTemplateVo template,File tarGzFile){
        Map<String, Object> result = new HashMap<String, Object>(0);
        Integer stationId = template.getStationId();
        List<StationSn> snList = stationSnService.getSnListByStationId(stationId);
        String serialNo = "";
        for (StationSn stationSn : snList) {
            serialNo = stationSn.getSn();
        }
        try {
            FileInputStream input = new FileInputStream(tarGzFile);
            MockMultipartFile multipartFile = new MockMultipartFile("file", tarGzFile.getName(), "multipart/form-data", input);
            DataResult<HeartbeatResp> heartbeatRespDataResult = fileCenterFeignClient.fileUploadForDevice(multipartFile, stationId, serialNo, FILE_PATH);
            HeartbeatResp data = heartbeatRespDataResult.getData();
            List<OrderIssuedVO> list = template.getOrderIssuedReqVO();
            OrderIssuedReqVO vo = new OrderIssuedReqVO();
            if( data.getHeartbeatStatus().equals(CommonConstant.ONE) && list != null && list.size() > 0 ){
                vo.setSn(serialNo);
                // 进来则表示成功,下发额外的指令
                vo.setList(list);
                sendYC(vo);
            } else {
                throw new BusinessException(BaseResponseCode.FILE_ISSUE_FAIL);
            }
        } catch (IOException e) {
            result.put("code", 500);
            result.put("msg", DefineConstant.PeakShaving.FILE_ISSUE_ERROR);
        }
        return result;
    }

    private void sendYC( OrderIssuedReqVO vo ){
        DataResult<HeartbeatResp> heartbeatRespDataResult = fileCenterFeignClient.orderIssued(vo);
        HeartbeatResp data = heartbeatRespDataResult.getData();
    }



    @PostMapping("/policyConfig")
    @ApiOperation(value = "策略配置")
    @TokenIgnore
    public DataResult policyConfig(@RequestBody List<PolicyConfig> policyConfigs){
        if( policyConfigs == null || policyConfigs.size() == 0 ){
            throw new BusinessException(BaseResponseCode.NON_DATA);
        }
        Map<String, Object> result = peakShavingService.policyConfig(policyConfigs);
        return DataResult.success( result );
    }

    @PostMapping("/queryPolicyConifgDay")
    @ApiOperation(value = "策略查询(上面部分,日)")
    @TokenIgnore
    public DataResult queryPolicyConifgDay(@RequestBody PolicyConfig policyConfig){
        if( policyConfig == null ){
            throw new BusinessException(BaseResponseCode.NON_DATA);
        }
        List<PolicyConfigData> policyConfigData = peakShavingService.queryPolicyConifg(policyConfig);
        return DataResult.success(policyConfigData);
    }

    @PostMapping("/queryPolicyConifgMonth")
    @ApiOperation(value = "策略查询(上面部分,月)")
    @TokenIgnore
    public DataResult queryPolicyConifgMonth(@RequestBody PolicyConfig policyConfig){
        if( policyConfig == null ){
            throw new BusinessException(BaseResponseCode.NON_DATA);
        }
        List<PolicyConfig> policyConfigData = peakShavingService.queryPolicyConifgMonth(policyConfig);
        return DataResult.success(policyConfigData);
    }

    @PostMapping("queryPlanList")
    @ApiOperation(value = "查询方案下拉框接口")
    @TokenIgnore
    public DataResult queryPlanList(@RequestBody PolicyConfigPlan policyConfigPlan){
        if( policyConfigPlan == null || policyConfigPlan.getStationId() == null ){
            throw new BusinessException(BaseResponseCode.NON_DATA);
        }
        return DataResult.success(peakShavingService.queryPlanList(policyConfigPlan));
    }

    @PostMapping("queryPeakPolicyList")
    @ApiOperation(value = "月下拉框查询接口(计划曲线模板+版本列表整合  用type类型区分)")
    @TokenIgnore
    public DataResult queryPeakPolicyList(@RequestBody PolicyConfigPlan policyConfigPlan){
        if( policyConfigPlan == null || policyConfigPlan.getStationId() == null ){
            throw new BusinessException(BaseResponseCode.NON_DATA);
        }
        return DataResult.success(peakShavingService.queryPeakPolicyList(policyConfigPlan));
    }

    @PostMapping("generateNewPlan")
    @ApiOperation(value = "生成新方案接口")
    @TokenIgnore
    public DataResult generateNewPlan(@RequestBody PolicyConfigPlanVo vo){
        // 只有在按日页面才有生成新方案,按月页面只能选择生成出来的方案
        PolicyConfig policyConfig = vo.getPolicyConfig();
        if( policyConfig == null ){
            throw new BusinessException(BaseResponseCode.NON_DATA);
        }
        PolicyConfigPlan policyConfigPlan = vo.getPolicyConfigPlan();
        if( policyConfigPlan == null || policyConfigPlan.getStationId() == null ){
            throw new BusinessException(BaseResponseCode.NON_DATA);
        }
        policyConfigPlan.setType(0);
        // 校验名称是否已经存在
        int i = peakShavingService.checkPlanName(policyConfigPlan);
        if( i > 0 ){
            throw new BusinessException(BaseResponseCode.PLAN_NAME_IS_EXISTS);
        }
        peakShavingService.generateNewPlan(vo,1);
        return DataResult.success();
    }

    @PostMapping("deletePlan")
    @ApiOperation(value = "删除方案接口")
    @TokenIgnore
    public DataResult deletePlan(@RequestBody PolicyConfigPlan policyConfigPlan){
        if( policyConfigPlan == null || policyConfigPlan.getId() == null ){
            throw new BusinessException(BaseResponseCode.NON_DATA);
        }
        peakShavingService.deletePlan(policyConfigPlan);
        return DataResult.success();
    }

    @PostMapping("queryPolicyConifgDetail")
    @ApiOperation(value = "查询方案内配置详情接口")
    @TokenIgnore
    public DataResult queryPolicyConifgDetail(@RequestBody PolicyConfig policyConfig){
        if( policyConfig == null || policyConfig.getPlanId() == null ){
            throw new BusinessException(BaseResponseCode.NON_DATA);
        }
        return DataResult.success(peakShavingService.queryPolicyConifgDetail(policyConfig));
    }

    @PostMapping("queryHolidayList")
    @ApiOperation(value = "查询节假日,工作日接口")
    @TokenIgnore
    public DataResult queryHolidayList(@RequestBody Holiday holiday){
        if( holiday == null || holiday.getMonth() == null ){
            throw  new BusinessException(BaseResponseCode.NON_DATA);
        }
        return DataResult.success(peakShavingService.queryHolidayList(holiday));
    }




}
