package com.ho.business.controller;

import cn.hutool.core.date.DateUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.ho.business.config.BizMergeStrategy;
import com.ho.business.entity.*;
import com.ho.business.feignclient.FileCenterFeignClient;
import com.ho.business.feignclient.UserFeignClient;
import com.ho.business.service.DynamicConfigService;
import com.ho.business.service.EarningsCalculateService;
import com.ho.business.service.ElecPriceCurveService;
import com.ho.business.service.StationSnService;
import com.ho.business.vo.EleRateFileVo;
import com.ho.business.vo.req.elecPriceCurve.BatchDeleteReq;
import com.ho.business.vo.req.elecPriceCurve.ElecPriceTemplateReq;
import com.ho.business.vo.req.elecPriceCurve.ElecPriceTemplateReqVO;
import com.ho.business.vo.resp.elecPriceCurve.ElecPriceData;
import com.ho.business.vo.resp.elecPriceCurve.ElecPriceTemplate;
import com.ho.business.vo.resp.elecPriceCurve.ElecPriceTemplateExcel;
import com.ho.business.vo.resp.elecPriceCurve.RowRangeDto;
import com.ho.common.tools.annotation.HzPermission;
import com.ho.common.tools.annotation.LogAnnotation;
import com.ho.common.tools.annotation.NotSportEnOperation;
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.entity.SimpleUser;
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.user.api.vo.req.SysSubDictVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import jodd.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.annotations.Param;
import org.springframework.beans.BeanUtils;
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 org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.*;
import java.net.URLEncoder;
import java.time.YearMonth;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description 电价曲线模板设置
 * Author yule
 * Date 2023/4/19 14:28
 */
@RequestMapping(ContextConstant.BUSINESS + "elecPriceCurve")
@RestController
@Slf4j
@Api(tags = "电价曲线模板设置")
public class ElecPriceCurveController {

    @Autowired
    ElecPriceCurveService elecPriceCurveService;

    @Autowired
    RedisService redisService;

    @Autowired
    EarningsCalculateService earningsCalculateService;

    @Autowired
    UserFeignClient userFeignClient;

    @Autowired
    DynamicConfigService dynamicConfigService;

    public static final String DICT_TYPE = "electrovalence_type";

    private static Map<String, String> staticMap = new HashMap<>(0);

    // 费率类型静态字典
    private static final Map<String,String> issuesMap = new HashMap<String,String>(){{
        put("1","001803");
        put("2","001802");
        put("3","001801");
        put("4","001800");
    }};

    // 生效月份列表
    public static final String MONTH ="25402";
    // 费率开始时间
    public static final String START_TIME ="25407";
    // 费率结束时间
    public static final String END_TIME ="25406";
    // 费率类型
    public static final String RATE_TYPE ="25405";

    @Autowired
    StationSnService stationSnService;

    @Autowired
    FileCenterFeignClient fileCenterFeignClient;

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

    public static final String FILE_PATH = "/deploy/fep/cfg";


    @PostMapping("add")
    @ApiOperation(value = "新增电价曲线模板")
    @LogAnnotation(title = "电价曲线模板设置", action = "新增电价曲线模板")
    @TokenIgnore
    @NotSportEnOperation
    public DataResult add(@RequestBody @Valid ElecPriceTemplate elecPriceTemplate, HttpServletRequest request) {
        String token = request.getHeader(RedisKeyConstant.User.ACCESS_TOKEN);
        SimpleUser user = redisService.getSimpleUserByToken(token);
        elecPriceTemplate.setGroupId(user.getGroupId());
        elecPriceCurveService.add(elecPriceTemplate);
        return DataResult.success();
    }

    @PostMapping("deleted")
    @LogAnnotation(title = "电价曲线模板设置", action = "删除电价曲线模板")
    @ApiOperation(value = "删除电价曲线模板")
    //@TokenIgnore
    @HzPermission(PermissionConstant.STRATEGY_ELECURVE_SINGLEDELETE)
    public DataResult deleted(@RequestBody ElecPriceTemplateReq elecPriceTemplateReq) {
        elecPriceCurveService.deleted(elecPriceTemplateReq);
        return DataResult.success();
    }

    @PostMapping("batchDelete")
    @LogAnnotation(title = "电价曲线模板设置", action = "批量删除电价曲线模板")
    @ApiOperation(value = "批量删除电价曲线模板")
    //@TokenIgnore
    @HzPermission(PermissionConstant.strategy_eleCurve_delete)
    public DataResult batchDelete(@RequestBody BatchDeleteReq elecPriceTemplateReq){
        elecPriceCurveService.batchDelete(elecPriceTemplateReq);
        return DataResult.success();
    }

    @PostMapping("update")
    @LogAnnotation(title = "电价曲线模板设置", action = "修改电价曲线模板")
    @ApiOperation(value = "修改电价曲线模板")
    @TokenIgnore
    public DataResult update(@RequestBody @Valid ElecPriceTemplate elecPriceTemplate) {
        elecPriceCurveService.update(elecPriceTemplate);
        return DataResult.success();
    }

    @PostMapping("one")
    @ApiOperation(value = "查询单个电价曲线模板")
    @HzPermission(PermissionConstant.STRATEGY_ELECURVE_EDIT)
    //@TokenIgnore
    public DataResult<ElecPriceTemplate> one(@RequestBody ElecPriceTemplateReq elecPriceTemplateReq) {
        ElecPriceTemplate elecPriceTemplate = elecPriceCurveService.getOne(elecPriceTemplateReq);
        return DataResult.success(elecPriceTemplate);
    }


    @PostMapping("all")
    @ApiOperation(value = "查询所有电价曲线模板")
    //@TokenIgnore
    public DataResult<List<ElecPriceData>> getAll(@RequestBody @Valid ElecPriceTemplateReqVO vo,HttpServletRequest request) {
        String lang = request.getHeader(CommonConstant.LANG);
        List<ElecPriceTemplate> list = elecPriceCurveService.getAll(vo);
        List<ElecPriceData> resultList = new ArrayList<>();
        for (ElecPriceTemplate elecTemplate : list) {
            if ( elecTemplate.getDiscount() != null ) {
                elecTemplate.setDiscount(elecTemplate.getDiscount()*100);
            }
            List<ElecTemplateSub> subList = elecTemplate.getList();
            if ( subList != null && subList.size() > 0 ) {
                for (ElecTemplateSub elecTemplateSub : subList) {
                    ElecPriceData data = new ElecPriceData();
                    BeanUtils.copyProperties(elecTemplate,data);
                    data.setPrice(elecTemplateSub.getPrice());
                    data.setBeginTime(elecTemplateSub.getBeginTime());
                    data.setEndTime(elecTemplateSub.getEndTime());
                    data.setType(elecTemplateSub.getType());
                    if(StringUtil.isNotBlank(data.getTemplateName())){
                        data.setTemplateName(dynamicConfigService.getNameByLang(data.getTemplateName(),lang));
                    }
                    if(StringUtil.isNotBlank(data.getType())){
                        data.setType(dynamicConfigService.getNameByLang(data.getType(),lang));
                    }

                    resultList.add(data);
                }
            }
        }
        return DataResult.success(resultList);
    }

    @PostMapping("exportTemplate")
    @LogAnnotation(title = "电价曲线模板设置", action = "导出模板")
    @ApiOperation(value = "导出模板")
    @HzPermission(PermissionConstant.STRATEGY_ELECURVE_EXPORTTEMPLATE)
    public void exportTemplate(HttpServletResponse response) {
        ServletOutputStream out = null;
        try {
            String fileName = URLEncoder.encode("elecPriceTemplate.xls", "utf-8");
            InputStream fis = getResourcesFileInputStream("template/elecPriceTemplate.xls");
            byte[] buffer = new byte[fis.available()];
            fis.read(buffer);
            fis.close();
            response.setHeader("Content-disposition", "attachment;fileName=" + fileName);
            response.setContentType("application/vnd.ms-excel;charset=utf-8");
            out = response.getOutputStream();
            out.write(buffer);
        } catch (Exception ex) {
            log.error("下载失败,{}", ex.getMessage());
        } finally {
            try {
                assert out != null;
                out.flush();
                out.close();
            } catch (Exception e) {
                log.error("下载模板失败,{}", e.getMessage());
                throw new BusinessException(BaseResponseCode.EXCEL_DATA_IMPORT_ERROR);
            }
        }
    }

    @PostMapping("importExcel")
    @LogAnnotation(title = "电价曲线模板设置", action = "导入电价曲线数据")
    @ApiOperation(value = "导入电价曲线数据")
    @HzPermission(PermissionConstant.STRATEGY_ELECURVE_IMPORT)
    @TokenIgnore
    public DataResult importExcel(@RequestBody MultipartFile file, @Param("stationId") Integer stationId, HttpServletRequest request) {
        String token = request.getHeader(RedisKeyConstant.User.ACCESS_TOKEN);
        SimpleUser user = redisService.getSimpleUserByToken(token);
        String msg = "";
        InputStream inputStream = null;
        try {
            String name = "";
            String isEnable = "";
            String updateTime = "";
            Date validityStartTime = null;
            Date validityEndTime = null;
            Double discount = 1.0;
            inputStream = file.getInputStream();
            List<ElecPriceTemplateExcel> excelList = EasyExcel.read(inputStream).head(ElecPriceTemplateExcel.class).sheet().doReadSync();
            //给合并单元格的值进行填充
            for (ElecPriceTemplateExcel elecPriceTemplateExcel : excelList) {
                elecPriceTemplateExcel.setStationId(stationId);
                elecPriceTemplateExcel.setGroupId(user.getGroupId());
                if (elecPriceTemplateExcel.getTemplateName() != null) {
                    name = elecPriceTemplateExcel.getTemplateName();
                } else {
                    elecPriceTemplateExcel.setTemplateName(name);
                }
                if (elecPriceTemplateExcel.getIsEnable() != null) {
                    isEnable = elecPriceTemplateExcel.getIsEnable();
                } else {
                    elecPriceTemplateExcel.setIsEnable(isEnable);
                }
                if (elecPriceTemplateExcel.getUpdateTime() != null) {
                    updateTime = elecPriceTemplateExcel.getUpdateTime();
                } else {
                    elecPriceTemplateExcel.setUpdateTime(updateTime);
                }
                if( elecPriceTemplateExcel.getValidityStartTime() != null ){
                    validityStartTime = elecPriceTemplateExcel.getValidityStartTime();
                } else {
                    elecPriceTemplateExcel.setValidityStartTime(validityStartTime);
                }
                if (elecPriceTemplateExcel.getValidityEndTime()!= null){
                    validityEndTime = elecPriceTemplateExcel.getValidityEndTime();
                } else {
                    elecPriceTemplateExcel.setValidityEndTime(validityEndTime);
                }
                if( elecPriceTemplateExcel.getDiscount() != null )  {
                    discount = elecPriceTemplateExcel.getDiscount();
                }else{
                    elecPriceTemplateExcel.setDiscount(discount);
                }
            }
            elecPriceCurveService.importExcel(excelList);
        } catch (Exception e) {
            log.error(e.getMessage());
            //出现自定义异常,直接抛出
            if (e.getClass().equals(BusinessException.class)){
                throw new BusinessException(((BusinessException) e).getMessageCode(),e.getMessage());
            }
            throw new BusinessException(BaseResponseCode.SJEKK_EXCEL_DATA);
        }finally {
            try {
                inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return DataResult.success(msg);
    }

    @PostMapping("exportExcel")
    @ApiOperation(value = "导出电价曲线数据")
    @LogAnnotation(title = "电价曲线模板设置", action = "导出电价曲线数据")
    @HzPermission(PermissionConstant.STRATEGY_ELECURVE_EXPORT)
    public void exportExcel(@RequestBody BatchDeleteReq batchDeleteReq ,HttpServletResponse response,HttpServletRequest request){
        String lang = request.getHeader(CommonConstant.LANG);
        List<Integer> ids = batchDeleteReq.getIds();
        if (ids == null || ids.isEmpty()){
            throw new BusinessException(BaseResponseCode.PLEASE_SELECT_ELECTRICITY_PRICE_TEMPLATE_DATA);
        }
        List<ElecPriceTemplate> list =  elecPriceCurveService.getListByIds(batchDeleteReq);
        List<ElecPriceTemplateExcel> excelList = new ArrayList<>();
        //转化为excel对象
        for (ElecPriceTemplate elecPriceTemplate : list) {
            List<ElecTemplateSub> elecPriceTemplateList = elecPriceTemplate.getList();
            for (ElecTemplateSub elecTemplateSub : elecPriceTemplateList) {
                //赋值
                ElecPriceTemplateExcel excel = new ElecPriceTemplateExcel();
                BeanUtils.copyProperties(elecTemplateSub,excel);
                excel.setPrice(elecTemplateSub.getPrice().toString());
                excel.setTemplateName(elecPriceTemplate.getTemplateName());
                excel.setUpdateTime(DateUtil.format(elecPriceTemplate.getUpdateTime(),CommonConstant.DATE));
                excel.setValidityStartTime(elecPriceTemplate.getValidityStartTime());
                excel.setValidityEndTime(elecPriceTemplate.getValidityEndTime());
                if ( elecPriceTemplate.getDiscount() != null ) {
                    excel.setDiscount(elecPriceTemplate.getDiscount()*100);
                }
                if (CommonConstant.ONE.equals(elecPriceTemplate.getIsEnable())){
                    excel.setIsEnable(CommonConstant.IS_ENABLE);
                }else {
                    excel.setIsEnable(CommonConstant.NOT_IS_ENABlE);
                }
                excel.setTemplateName(dynamicConfigService.getNameByLang(excel.getTemplateName(),lang));
                excel.setType(dynamicConfigService.getNameByLang(excel.getType(),lang));
                excel.setIsEnable(dynamicConfigService.getNameByLang(excel.getIsEnable(),lang));
                excelList.add(excel);
            }
        }

        Map<String, List<RowRangeDto>> strategyMap = BizMergeStrategy.addAnnualMerStrategy(excelList);
        try {
            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("utf-8");
            // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
            String filename = URLEncoder.encode("电价模板", "utf-8");
            response.setHeader("Content-disposition", "attachment;filename=" + filename + ".xlsx");

            EasyExcel.write(response.getOutputStream(), ElecPriceTemplateExcel.class)
                    .excelType(ExcelTypeEnum.XLSX).head(ElecPriceTemplateExcel.class)
                    //.registerWriteHandler(new TitleSheetWriteHandler("我是一个小标题",2)) // 标题及样式，lastCol为标题第0列到底lastCol列的宽度
                    //设置默认样式及写入头信息开始的行数
                    .registerWriteHandler(new BizMergeStrategy(strategyMap))    // 注册合并策略
                    // .registerWriteHandler(BizMergeStrategy.CellStyleStrategy()) // 设置样式
                    .sheet("电价曲线")
                    .doWrite(excelList);
        }catch (Exception e) {
            log.error("下载失败,{}", e.getMessage());
            throw new BusinessException(BaseResponseCode.EXCEL_DATA_IMPORT_ERROR);
        }
    }

    // 导出模板
    private static InputStream getResourcesFileInputStream(String fileName) {
        return Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName);
    }



    @PostMapping("addSearch")
    @ApiOperation(value = "新增模板查询电价(查询国网参考电价)")
    @LogAnnotation(title = "新增模板查询电价", action = "新增模板查询电价")
    @TokenIgnore
    public DataResult<ElecPriceTemplate> addSearch(@RequestBody ElecTemplate elecTemplate) {
        ElecPriceTemplate elecPriceTemplate = null;
        if( elecTemplate != null && elecTemplate.getStationId() != null ){
            elecPriceTemplate = elecPriceCurveService.addSearch(elecTemplate.getStationId());
        }
        return DataResult.success(elecPriceTemplate);
    }

    @PostMapping("sendEleRateFile")
    @ApiOperation(value = "下发电价曲线文件")
    @TokenIgnore
    public DataResult sendEleRateFile(@RequestBody EleRateFileVo vo){
        if( vo == null || vo.getStationId() == null ){
            throw new BusinessException(BaseResponseCode.NON_DATA);
        }
        // 查询字典表,拿到类型与value对应关系
        if (staticMap.size() == 0) {
            SysSubDictVO sysSubDictVO = new SysSubDictVO();
            sysSubDictVO.setType(DICT_TYPE);
            staticMap = userFeignClient.getSysSubDict(sysSubDictVO);
        }
        // 查询到电价模板配置信息,组装成json
        String jsonStr = parseJson(vo);
        // 生成文件
        wirteFile(JSON_FILE_NAME,jsonStr);
        // 取得json文件
        File fileToCompress = new File(JSON_FILE_NAME);
        Map<String, Object> result = uploadFile(vo, fileToCompress);
        if( fileToCompress.exists() ){
            if (fileToCompress.delete()) {
                System.out.println("临时文件删除成功！");
            } else {
                System.out.println("临时文件删除失败！");
            }
        } else {
            System.out.println("临时文件不存在！");
        }
        return DataResult.success();
    }

    /**
     * 组装json
     * @param vo
     * @return
     */
    private String parseJson(EleRateFileVo vo){
        JSONObject jsonStr = new JSONObject();
        JSONObject json = new JSONObject();
        String now = DateUtil.now();
        json.put("sdt",now);
        // 第二层
        JSONArray details = new JSONArray();
        JSONObject detail = null;
        // 最内层
        JSONArray timeDevisions = null;
        JSONObject timeDevision = null;
        List<String> yearMonth = getYearMonth();
        List<EarningsCalculateSub> baseData = new ArrayList<>(0);
        for (String month : yearMonth) {
            timeDevisions = new JSONArray();
            detail = new JSONObject();
            List<EarningsCalculateSub> earningsCalculateSubs = earningsCalculateService.queryElecTemplateSubByStationId(vo.getStationId(), null, month);
            if( earningsCalculateSubs != null && earningsCalculateSubs.size() > 0 ){
                baseData = earningsCalculateSubs;
            }
            for (EarningsCalculateSub earningsCalculateSub : baseData) {
                timeDevision = new JSONObject();
                String key = getKey(earningsCalculateSub.getType());
                timeDevision.put(RATE_TYPE,issuesMap.get(key));
                timeDevision.put(END_TIME,earningsCalculateSub.getEndTime());
                timeDevision.put(START_TIME,earningsCalculateSub.getBeginTime());
                timeDevisions.add(timeDevision);
            }
            detail.put(MONTH,month.substring(5,7));
            detail.put("timeDevisions",timeDevisions);
            details.add(detail);
        }
        JSONObject detailsStr = new JSONObject();
        detailsStr.put("details",details);
        // 实际数据的字段
//        json.put("con1",detailsStr);
        json.put("con",detailsStr.toString());
        json.put("uuid",UUID.randomUUID());
        json.put("det","254");
        json.put("dc","254000");
        jsonStr.put("ac","");
        jsonStr.put("bv","");
        jsonStr.put("cp","");
        jsonStr.put("dm","");
        jsonStr.put("dt","");
        jsonStr.put("ec","");
        jsonStr.put("mi","");
        jsonStr.put("pb","");
        jsonStr.put("pt",now);
        jsonStr.put("pv","");
        jsonStr.put("rt","");
//        jsonStr.put("bd1",json);
        jsonStr.put("bd",json.toString());
        System.err.println(jsonStr.toJSONString());
        return jsonStr.toJSONString();
    }


    /**
     * 根据value获取key
     * @param value
     * @return
     */
    private String getKey(String value){
        if( staticMap.size() == 0 ){
            return null;
        }
        return staticMap.entrySet().stream().collect(Collectors.toMap(entity-> entity.getValue(), entity-> entity.getKey())).get(value);
    }

    private List<String> getYearMonth(){
        List<String> yearMonth = new ArrayList<>();
        int year = YearMonth.now().getYear();
        for (int i = 1; i <= 12; i++) {
            YearMonth of = YearMonth.of(year, i);
            yearMonth.add(of+"-01");
        }
        return yearMonth;
    }

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

    private Map<String, Object> uploadFile(EleRateFileVo eleRateFileVo, File file){
        Map<String, Object> result = new HashMap<String, Object>(0);
        Integer stationId = eleRateFileVo.getStationId();
        List<StationSn> snList = stationSnService.getSnListByStationId(stationId);
        String serialNo = "";
        for (StationSn stationSn : snList) {
            serialNo = stationSn.getSn();
        }
        try {
            FileInputStream input = new FileInputStream(file);
            MockMultipartFile multipartFile = new MockMultipartFile("file", file.getName(), "multipart/form-data", input);
            DataResult<HeartbeatResp> heartbeatRespDataResult = fileCenterFeignClient.fileUploadForDevice(multipartFile, stationId, serialNo, FILE_PATH);
            HeartbeatResp data = heartbeatRespDataResult.getData();
            if( !data.getHeartbeatStatus().equals(CommonConstant.ONE) ){
                throw new BusinessException(BaseResponseCode.FILE_ISSUE_FAIL);
            }
        } catch (IOException e) {
            result.put("code", "500");
            result.put("msg", "下发JSON文件发生异常");
        }
        return result;
    }


}
