package com.ho.business.service.impl;


import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.ho.business.entity.IndustrialElecPrice;
import com.ho.business.entity.IndustrialElecRegion;
import com.ho.business.feignclient.UserFeignClient;
import com.ho.business.mapper.IndustrialElecPriceMapper;
import com.ho.business.mapper.IndustrialElecRegionMapper;
import com.ho.business.service.IndustrialElecPriceService;
import com.ho.business.util.BaiduImageIdentifyUtil;
import com.ho.business.util.region.Region;
import com.ho.business.vo.req.industrialElec.IndustrialElecPriceReqVo;
import com.ho.business.vo.resp.industrialElec.DiffPriceRspVo;
import com.ho.business.vo.resp.industrialElec.IndustrialElecPriceRspVo;
import com.ho.common.tools.constant.DefineConstant;
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.util.PageResult;
import com.ho.common.tools.util.PageUtils;
import com.ho.user.api.vo.req.SysSubDictVO;
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 org.apache.commons.io.IOUtils;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Service
public class IndustrialElecPriceServiceImpl implements IndustrialElecPriceService {

    @Autowired
    private IndustrialElecPriceMapper industrialElecPriceMapper;
    @Autowired
    private UserFeignClient userFeignClient;

    @Autowired
    private IndustrialElecRegionMapper industrialElecRegionMapper;

    public static final String DEEP_VALLEY_PRICE_INTERVAL="deep_valley_price_interval";
    public static final String PEAK_PRICE_INTERVAL="peak_price_interval";
    public static final String REGULAR_PRICE_INTERVAL="regular_price_interval";
    public static final String LOW_VALLEY_PRICE_INTERVAL="low_valley_price_interval";
    public static final String SPIKE_PRICE_INTERVAL="spike_price_interval";

    @Override
    public DataResult<PageResult<IndustrialElecPrice>> getElecPriceList(IndustrialElecPriceReqVo reqVo) {
        PageHelper.startPage(reqVo.getPageNum(), reqVo.getPageSize());
        List<IndustrialElecPrice> industrialElecPrices = industrialElecPriceMapper.selectPriceByCondition(reqVo);
        List<IndustrialElecRegion> list = industrialElecRegionMapper.findAllList();
        Map<Integer, String> map = list.stream().collect(Collectors.toMap(IndustrialElecRegion::getId, IndustrialElecRegion::getRegionName));
        SysSubDictVO voltageVO = new SysSubDictVO();
        voltageVO.setType("voltage_level");
        SysSubDictVO customerVO = new SysSubDictVO();
        customerVO.setType("customer_type");
        SysSubDictVO electricityVO = new SysSubDictVO();
        electricityVO.setType("electricity_type");
        Map<String, String> voltage = userFeignClient.getSysSubDict(voltageVO);
        Map<String, String> customer = userFeignClient.getSysSubDict(customerVO);
        Map<String, String> electricity = userFeignClient.getSysSubDict(electricityVO);
        for (IndustrialElecPrice industrial : industrialElecPrices) {
            industrial.setRegionName(map.get(industrial.getRegionId()));
            industrial.setVoltageLevelLabel(voltage.get(industrial.getVoltageLevel()+""));
            industrial.setCustomerTypeLabel(customer.get(industrial.getCustomerType()+""));
            industrial.setElectricityTypeLabel(electricity.get(industrial.getElectricityType()+""));
        }
        return DataResult.success(PageUtils.getPageResult(new PageInfo<>(industrialElecPrices)));
    }
    @Override
    public void add(IndustrialElecPrice industrialElecPrice) {
        IndustrialElecPriceReqVo industrialElecPriceReqVo = new IndustrialElecPriceReqVo();
        BeanUtil.copyProperties(industrialElecPrice,industrialElecPriceReqVo);
        IndustrialElecPrice elecPrice = industrialElecPriceMapper.findByCondition(industrialElecPriceReqVo);
        //根据客户类型、电压等级、用电类型、执行日期来判断是否重复录入
        if(elecPrice==null){
            industrialElecPriceMapper.insert(industrialElecPrice);
        }else{
            throw new BusinessException(BaseResponseCode.PEER_EXISTENCE_SAME_NAME);
        }
    }

    @Override
    public void deleteById(Long id) {
        industrialElecPriceMapper.deleteById(id);
    }

    @Override
    public IndustrialElecPrice findById(Long id) {
        SysSubDictVO voltageVO = new SysSubDictVO();
        voltageVO.setType("voltage_level");
        SysSubDictVO customerVO = new SysSubDictVO();
        customerVO.setType("customer_type");
        SysSubDictVO electricityVO = new SysSubDictVO();
        electricityVO.setType("electricity_type");
        Map<String, String> voltage = userFeignClient.getSysSubDict(voltageVO);
        Map<String, String> customer = userFeignClient.getSysSubDict(customerVO);
        Map<String, String> electricity = userFeignClient.getSysSubDict(electricityVO);
        IndustrialElecPrice industrialElecPrice=industrialElecPriceMapper.findById(id);
        if(industrialElecPrice!=null){
            industrialElecPrice.setVoltageLevelLabel(voltage.get(industrialElecPrice.getVoltageLevel()+""));
            industrialElecPrice.setCustomerTypeLabel(customer.get(industrialElecPrice.getCustomerType()+""));
            industrialElecPrice.setElectricityTypeLabel(electricity.get(industrialElecPrice.getElectricityType()+""));
        }
        return industrialElecPrice;
    }

    @Override
    public void updateById(IndustrialElecPrice industrialElecPrice) {
        industrialElecPriceMapper.updateById(industrialElecPrice);
    }


    @Override
    public List<Map<String, Object>> getTouLineById(Long id) {
        IndustrialElecPrice industrialElecPrice = industrialElecPriceMapper.findById(id);
        List<Map<String, Object>> listData = new ArrayList<>();
        if (industrialElecPrice != null) {
            //开始组装折线图
            //谷电
            BigDecimal lowValleyPrice = industrialElecPrice.getLowValleyPrice();
            String lowValleyPriceInterval = industrialElecPrice.getLowValleyPriceInterval();
            ArrayList<BigDecimal> lowList = list(lowValleyPrice, lowValleyPriceInterval);
            if (lowList != null) {
                Map lowMap = new HashMap<>();
                lowMap.put("name", DefineConstant.VALLEY);
                lowMap.put("list", lowList);
                listData.add(lowMap);
            }

            //平电
            BigDecimal regularPrice = industrialElecPrice.getRegularPrice();
            String regularPriceInterval = industrialElecPrice.getRegularPriceInterval();
            ArrayList<BigDecimal> regularList = list(regularPrice, regularPriceInterval);
            if (regularList != null) {
                Map regularMap = new HashMap<>();
                regularMap.put("name", DefineConstant.FLAT);
                regularMap.put("list", regularList);
                listData.add(regularMap);
            }

            //峰电
            BigDecimal peakPrice = industrialElecPrice.getPeakPrice();
            String peakPriceInterval = industrialElecPrice.getPeakPriceInterval();
            ArrayList<BigDecimal> peakList = list(peakPrice, peakPriceInterval);
            if (peakList != null) {
                Map peakMap = new HashMap<>();
                peakMap.put("name", DefineConstant.PEAK);
                peakMap.put("list", peakList);
                listData.add(peakMap);
            }
            //深谷
            BigDecimal deepValleyPrice = industrialElecPrice.getDeepValleyPrice();
            String deepValleyPriceInterval = industrialElecPrice.getDeepValleyPriceInterval();
            ArrayList<BigDecimal> deepList = list(deepValleyPrice, deepValleyPriceInterval);
            if (deepList != null) {
                Map deepMap = new HashMap<>();
                deepMap.put("name", DefineConstant.DEEP_VALLEY);
                deepMap.put("list", deepList);
                listData.add(deepMap);
            }
            //尖峰
            BigDecimal spikePrice = industrialElecPrice.getSpikePrice();
            String spikePriceInterval = industrialElecPrice.getSpikePriceInterval();
            ArrayList<BigDecimal> pikeList = list(spikePrice, spikePriceInterval);
            if (pikeList != null) {
                Map spikeMap = new HashMap<>();
                spikeMap.put("name", DefineConstant.SHARP);
                spikeMap.put("list", pikeList);
                listData.add(spikeMap);
            }
        }
        return listData;
    }

    @Override
    public Map<String, Object> getTouLineHistoryById(Long id) {
        List<IndustrialElecPriceRspVo> tableData = getData(industrialElecPriceMapper, id);
        Map<String, Object> map=new HashMap<>();
        List<Map<String, Object>> lineData = new ArrayList<>();
        List<Map<String, Object>> peakPriceList = new ArrayList<>();
        List<Map<String, Object>> regularPriceList = new ArrayList<>();
        List<Map<String, Object>> deepValleyPriceList = new ArrayList<Map<String, Object>>();
        List<Map<String, Object>> spikePriceList = new ArrayList<>();
        List<Map<String, Object>> lowValleyPriceList = new ArrayList<>();
        if (tableData != null) {
            for (int i = 0; i < tableData.size(); i++) {
                IndustrialElecPriceRspVo elecPrice = tableData.get(i);
                String dataStr = elecPrice.getExecutionTime();

                Map<String, Object> pMap = new HashMap<>();
                pMap.put("date", dataStr);
                pMap.put("value", elecPrice.getPeakPrice());
                peakPriceList.add(pMap);

                Map<String, Object> rMap = new HashMap<>();
                rMap.put("date", dataStr);
                rMap.put("value", elecPrice.getRegularPrice());
                regularPriceList.add(rMap);

                Map<String, Object> dMap = new HashMap<>();
                dMap.put("date", dataStr);
                dMap.put("value", elecPrice.getDeepValleyPrice());
                deepValleyPriceList.add(dMap);

                Map<String, Object> sMap = new HashMap<>();
                sMap.put("date", dataStr);
                sMap.put("value", elecPrice.getSpikePrice());
                spikePriceList.add(sMap);

                Map<String, Object> lMap = new HashMap<>();
                lMap.put("date", dataStr);
                lMap.put("value", elecPrice.getLowValleyPrice());
                lowValleyPriceList.add(lMap);
            }
        }
        Map spikeMap = new HashMap<>();
        spikeMap.put("name", DefineConstant.SHARP);
        spikeMap.put("list", spikePriceList);
        lineData.add(spikeMap);

        Map peakMap = new HashMap<>();
        peakMap.put("name", DefineConstant.PEAK);
        peakMap.put("list", peakPriceList);
        lineData.add(peakMap);

        Map regularMap = new HashMap<>();
        regularMap.put("name", DefineConstant.FLAT);
        regularMap.put("list", regularPriceList);
        lineData.add(regularMap);

        Map lowMap = new HashMap<>();
        lowMap.put("name", DefineConstant.VALLEY);
        lowMap.put("list", lowValleyPriceList);
        lineData.add(lowMap);

        Map deepMap = new HashMap<>();
        deepMap.put("name", DefineConstant.DEEP_VALLEY);
        deepMap.put("list", deepValleyPriceList);
        lineData.add(deepMap);

        map.put("line",lineData);
        map.put("table",tableData);
        return map;
    }


    @Override
    public Map<String,Object> getMaxPriceDiffById(Long id) {
        Map dataMap=new HashMap<>();
        List<IndustrialElecPriceRspVo> data = getData(industrialElecPriceMapper, id);
        List<Map<String, Object>> lineList = new ArrayList<>();
        List<DiffPriceRspVo> tableList=new ArrayList<>();
        if (data != null) {
            for (int i = 0; i < data.size(); i++) {
                IndustrialElecPriceRspVo industrialElecPriceRspVo = data.get(i);
                BigDecimal regularPrice = industrialElecPriceRspVo.getRegularPrice();
                BigDecimal spikePrice = industrialElecPriceRspVo.getSpikePrice();
                BigDecimal peakPrice = industrialElecPriceRspVo.getPeakPrice();
                BigDecimal lowValleyPrice = industrialElecPriceRspVo.getLowValleyPrice();
                BigDecimal deepValleyPrice = industrialElecPriceRspVo.getDeepValleyPrice();
                BigDecimal maxPrice = null;
                BigDecimal minPrice = null;
                DiffPriceRspVo diffPriceRspVo = new DiffPriceRspVo();
                //尖>峰>平>谷>深谷
                if (spikePrice != null) {
                    maxPrice = spikePrice;
                } else {
                    if (peakPrice != null) {
                        maxPrice = peakPrice;
                    } else {
                        if (regularPrice != null) {
                            maxPrice = regularPrice;
                        } else {
                            if (lowValleyPrice != null) {
                                maxPrice = lowValleyPrice;
                            } else {
                                if (deepValleyPrice != null){
                                    maxPrice = deepValleyPrice;
                                }

                            }
                        }
                    }
                }
                if (deepValleyPrice != null) {
                    minPrice = deepValleyPrice;
                } else {
                    if (lowValleyPrice != null) {
                        minPrice = lowValleyPrice;
                    } else {
                        if (regularPrice != null) {
                            minPrice = regularPrice;
                        } else {
                            if (peakPrice != null) {
                                minPrice = peakPrice;
                            } else {
                                if (spikePrice != null) {
                                    minPrice = spikePrice;
                                }
                            }
                        }
                    }
                }
                diffPriceRspVo.setMaxPrice(maxPrice);
                diffPriceRspVo.setMinPrice(minPrice);
                diffPriceRspVo.setExecutionTime(industrialElecPriceRspVo.getExecutionTime());
                if (minPrice != null && maxPrice != null) {
                    Map map = new HashMap<>();
                    map.put("date", industrialElecPriceRspVo.getExecutionTime());
                    map.put("value", maxPrice.subtract(minPrice));
                    diffPriceRspVo.setDiffPrice(maxPrice.subtract(minPrice));
                    lineList.add(map);
                }
                tableList.add(diffPriceRspVo);
            }
        }
        dataMap.put("line",lineList);
        dataMap.put("table",tableList);
        return dataMap;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public DataResult collectPrice(MultipartFile file,Integer regionId, String executionTime) {
        InputStream inputStream = null;
        JSONObject imageObject = null;
        try {
            inputStream = file.getInputStream();
            byte[] bytes = IOUtils.toByteArray(inputStream);
            imageObject = BaiduImageIdentifyUtil.getImageObject(bytes);
        } catch (IOException e) {
            return DataResult.getResult(BaseResponseCode.BAIDU_PIC_NOTIFY_TIME_OUT);
        }
        if(imageObject.containsKey("error_msg")){
            return DataResult.getResult(BaseResponseCode.BAIDU_PIC_NOTIFY_USE_UP);
        }
        IndustrialElecRegion industrialElecRegion = industrialElecRegionMapper.findById(regionId);
        String spike=null;
        String peak=null;
        String regular=null;
        String low=null;
        String deep=null;
        if(industrialElecRegion!=null){
            Map<String, String> interval = getInterval(industrialElecRegion.getInterval(), executionTime);
            spike=interval.get(SPIKE_PRICE_INTERVAL);
            peak=interval.get(PEAK_PRICE_INTERVAL);
            regular=interval.get(REGULAR_PRICE_INTERVAL);
            low=interval.get(LOW_VALLEY_PRICE_INTERVAL);
            deep=interval.get(DEEP_VALLEY_PRICE_INTERVAL);
        }
        JSONArray jsonArray = imageObject.getJSONArray("tables_result");
        JSONObject bodyObject = jsonArray.getJSONObject(0);
        JSONArray array = bodyObject.getJSONArray("body");
        System.out.println(array);
        List<IndustrialElecPrice> list = null;
        try {
            Integer type = industrialElecRegion.getType();
            if(type!=null){
                Region p2 = (Region)Class.forName("com.ho.business.util.region.Region"+type).newInstance();
                list= p2.getList(array,regionId,spike,peak,regular,low,deep,executionTime);
            }
        } catch (Exception e) {
            e.printStackTrace();
            return DataResult.getResult(BaseResponseCode.PARSING_FAILED);
        }
        industrialElecPriceMapper.deleteByRegionIdAndDate(regionId,executionTime);
        industrialElecPriceMapper.insertCollectList(list);
        return DataResult.success();
    }

    public static Map<String,String> getInterval(String interval,String executionTime){
        Map<String,String> map=new HashMap<>();
            if(interval!=null){
                JSONObject jsonObject = JSON.parseObject(interval);
                Integer type = jsonObject.getInteger("type");
                if (type.equals(1)){
                    //表示不分月份
                    JSONArray arr = jsonObject.getJSONArray("interval");
                    for (int i = 0; i <arr.size() ; i++) {
                        JSONObject o = arr.getJSONObject(i);
                        if(o.containsKey(PEAK_PRICE_INTERVAL)){
                            map.put(PEAK_PRICE_INTERVAL,o.getString(PEAK_PRICE_INTERVAL));
                        }
                        if(o.containsKey(REGULAR_PRICE_INTERVAL)){
                            map.put(REGULAR_PRICE_INTERVAL,o.getString(REGULAR_PRICE_INTERVAL));
                        }
                        if(o.containsKey(LOW_VALLEY_PRICE_INTERVAL)){
                            map.put(LOW_VALLEY_PRICE_INTERVAL,o.getString(LOW_VALLEY_PRICE_INTERVAL));
                        }
                        if(o.containsKey(SPIKE_PRICE_INTERVAL)){
                            map.put(SPIKE_PRICE_INTERVAL,o.getString(SPIKE_PRICE_INTERVAL));
                        }
                        if(o.containsKey(DEEP_VALLEY_PRICE_INTERVAL)){
                            map.put(DEEP_VALLEY_PRICE_INTERVAL,o.getString(DEEP_VALLEY_PRICE_INTERVAL));
                        }
                    }
                }else{
                    //表示分月份 获取不同的时间间隔分布
                    JSONArray arr = jsonObject.getJSONArray("interval");
                    for (int i = 0; i <arr.size() ; i++) {
                        JSONObject o = arr.getJSONObject(i);
                        if(o.containsKey("date")){
                            if(o.getString("date").equals(executionTime.split("-")[1])) {
                                map.put(PEAK_PRICE_INTERVAL,o.getString(PEAK_PRICE_INTERVAL));
                                map.put(REGULAR_PRICE_INTERVAL,o.getString(REGULAR_PRICE_INTERVAL));
                                map.put(LOW_VALLEY_PRICE_INTERVAL,o.getString(LOW_VALLEY_PRICE_INTERVAL));
                                map.put(SPIKE_PRICE_INTERVAL,o.getString(SPIKE_PRICE_INTERVAL));
                                map.put(DEEP_VALLEY_PRICE_INTERVAL,o.getString(DEEP_VALLEY_PRICE_INTERVAL));
                                break;
                            }
                        }else{
                            map.put(PEAK_PRICE_INTERVAL,o.getString(PEAK_PRICE_INTERVAL));
                            map.put(REGULAR_PRICE_INTERVAL,o.getString(REGULAR_PRICE_INTERVAL));
                            map.put(LOW_VALLEY_PRICE_INTERVAL,o.getString(LOW_VALLEY_PRICE_INTERVAL));
                            map.put(SPIKE_PRICE_INTERVAL,o.getString(SPIKE_PRICE_INTERVAL));
                            map.put(DEEP_VALLEY_PRICE_INTERVAL,o.getString(DEEP_VALLEY_PRICE_INTERVAL));
                        }
                    }
                }
            }
            return map;
    }

    public static List<IndustrialElecPriceRspVo> getData(IndustrialElecPriceMapper industrialElecPriceMapper, Long id) {
        IndustrialElecPrice industrialElecPrice = industrialElecPriceMapper.findById(id);
        if (industrialElecPrice != null) {
            Calendar calendar = Calendar.getInstance();
            String executionTime=industrialElecPrice.getExecutionTime();
            SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy-MM");
            try {
                calendar.setTime(simpleDateFormat.parse(executionTime));
            } catch (ParseException e) {
                throw new RuntimeException(e);
            }
            // 获取减去一年后的时间
            calendar.add(Calendar.YEAR, -1);
            Date executionStartTime = calendar.getTime();
            List<IndustrialElecPriceRspVo> elecPriceListByDate = industrialElecPriceMapper.findElecPriceListByDate(industrialElecPrice.getRegionId(), industrialElecPrice.getElectricityType(),industrialElecPrice.getCustomerType(), industrialElecPrice.getVoltageLevel(),simpleDateFormat.format(executionStartTime),industrialElecPrice.getExecutionTime());
            return elecPriceListByDate;
        }
        return null;
    }

    public static ArrayList<BigDecimal> list(BigDecimal price, String priceInterval) {
        BigDecimal[] bigDecimal = new BigDecimal[49];
        ArrayList<BigDecimal> list = new ArrayList<BigDecimal>(Arrays.asList(bigDecimal));
        if (priceInterval != null &&!"".equals(priceInterval)&& price != null) {
            String[] split;
            if (priceInterval.contains(",")) {
                //这种格式22:00-24:00,00:00-06:00
                split = priceInterval.split(",");
            } else {
                //这种格式22:00-24:00
                split = new String[1];
                split[0] = priceInterval;
            }
            for (int i = 0; i < split.length; i++) {
                //22:30-24:00
                String s = split[i];
                if(!isInterval(s)){
                   //如果正则校验不通过
                    return null;
                }
                String[] time = s.split("-");
                String startTime = time[0].split(":")[0];
                String endTime = time[1].split(":")[0];
                Integer start=null;
                Integer end=null;
                if (startTime.startsWith("0") && !"00".equals(startTime)) {
                    startTime = startTime.split("0")[1];
                }
                if (endTime.startsWith("0") && !"00".equals(endTime)) {
                    endTime = endTime.split("0")[1];
                }
                if(time[0].contains(":00")){
                    start=Integer.parseInt(startTime)*2;
                }else{
                    start=Integer.parseInt(startTime)*2+1;
                }
                if(time[1].contains(":00")){
                    end=Integer.parseInt(endTime)*2;
                }else{
                    end=Integer.parseInt(endTime)*2+1;
                }
                for (int j = start; j <= end; j++) {
                    list.set(j, price);
                }
            }
        } else {
            return null;
        }
        return list;
    }

    public static boolean isInterval(String interval){
        String pattern = "^((2[0-3]|[01]?[0-9]):[03][0])-((2[0-4]|[01]?[0-9]):[03][0])$";
        Pattern r = Pattern.compile(pattern);
        Matcher m = r.matcher(interval);
        return m.matches();
    }
}
