package com.huatek.busi.service.impl.transformer;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.dubbo.config.annotation.Service;
import com.alibaba.fastjson.JSON;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.huatek.busi.common.BusiConstant.EqType;
import com.huatek.busi.common.BusiConstant.GzType;
import com.huatek.busi.common.CacMonitorTypeCode;
import com.huatek.busi.common.DateUtils;
import com.huatek.busi.common.SiteConstants;
import com.huatek.busi.common.SiteConstants.ExternalTypeEnum;
import com.huatek.busi.common.SiteConstants.SiteTreeEnum;
import com.huatek.busi.common.SiteConstants.TransfromerTreeEnum;
import com.huatek.busi.common.util.DecimalUtil;
import com.huatek.busi.common.util.TimeUtil;
import com.huatek.busi.common.util.Tools;
import com.huatek.busi.dao.*;
import com.huatek.busi.dto.BusiSensorQueryParamDto;
import com.huatek.busi.dto.EquipmentInfoDto;
import com.huatek.busi.dto.HomeSearchDto;
import com.huatek.busi.dto.WindingTemperatureStatisticsDto;
import com.huatek.busi.dto.curve.BaseCurveQueryDto;
import com.huatek.busi.dto.curve.PointItemDto;
import com.huatek.busi.entity.*;
import com.huatek.busi.mapper.BusiVideoMapper;
import com.huatek.busi.mapper.TransformerWindingTemperatureMapper;
import com.huatek.busi.service.BusiEqmWarningPictureService;
import com.huatek.busi.service.BusiSiteTreeService;
import com.huatek.busi.service.BusiTransfromTemperatureExcessService;
import com.huatek.busi.service.IecBydworkParamService;
import com.huatek.busi.service.impl.cac.AbstractCacEtlService;
import com.huatek.busi.service.threshold.WindingThresholdService;
import com.huatek.busi.service.transformer.BusiTransformerSensorService;
import com.huatek.busi.service.transformer.BusiTransformerSubTreeService;
import com.huatek.busi.service.transformer.TransformerWindingTemperatureCacheService;
import com.huatek.busi.service.transformer.TransformerWindingTemperatureService;
import com.huatek.busi.util.FFmpegUtil;
import com.huatek.busi.vo.*;
import com.huatek.busi.vo.curve.PointItemVo;
import com.huatek.busi.vo.monitor.BusiOnlineMonitorDataVo;
import com.huatek.torch.frame.exception.OwlException;
import com.huatek.torch.frame.tools.ConstantUtil;
import com.huatek.torch.frame.tools.ResultUtil;
import com.huatek.torch.sql.beans.WherePrams;
import com.huatek.torch.util.uuid.Uuid;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.io.File;
import java.math.BigDecimal;
import java.sql.Time;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;

/**
 * 变压器——绕组测温：021010、022002、023002、024007 ServiceImpl
 *
 * @author anker_cheng
 * @date Jun 26, 2019 1:11:48 PM
 */
@Component
@Service(interfaceClass = TransformerWindingTemperatureService.class)
@Transactional(rollbackFor = Exception.class)
public class TransformerWindingTemperatureServiceImpl extends AbstractCacEtlService<TransformerWindingTemperature>
        implements TransformerWindingTemperatureService {

    @Autowired
    private WindingThresholdService windingThresholdService;

    @Reference(check = false)
    private BusiTransfromTemperatureExcessService busiTransfromTemperatureExcess;

    @Reference(check = false)
    private IecBydworkParamService iecBydworkParamService;

    @Reference(check = false)
    private BusiSiteTreeService busiSiteTreeService;

    @Reference(check = false)
    private TransformerWindingTemperatureCacheService transformerWindingTemperatureCacheService;

    @Reference(check = false)
    private BusiEqmWarningPictureService busiEqmWarningPictureService;

    @Autowired
    private BusiTransformerSensorDao busiTransformerSensorDao;

    @Autowired
    private TransformerWindingTemperatureDao transformerWindingTemperatureDao;

    @Autowired
    private WindingThresholdDao windingThresholdDao;
    @Autowired
    private BusiOnlineMonitorDataDao busiOnlineMonitorDataDao;

    @Autowired
    private BusiTransformerSensorService busiTransformerSensorService;

    @Autowired
    private BusiTransfromerSubTreeDao busiTransfromerSubTreeDao;
    @Value("${warningpicture.base.path}")
    private String pictureBasePath;

    @Value("${warningpicture.base.num}")
    private Integer pictureBaseNum;

    @Value("${warningpicture.base.suffix}")
    private String suffix;

    @Value("${warningpicture.base.startTime}")
    private String startTime;

    @Value("${warningpicture.base.endTime}")
    private String endTime;

    @Value("${nginx.video.capture}")
    private String videoCapture;

    @Autowired
    private TransformerWindingTemperatureMapper transformerWindingTemperatureMapper;

    @Autowired
    private BusiVideoMapper busiVideoMapper;

    @Override
    public void saveHistoryData(TransformerWindingTemperature cacEntity, EquipmentInfoDto equipmentInfo) {
        // 设备状态
        String state = iecBydworkParamService.getIecType(cacEntity.getMainTreeId(), cacEntity.getTimeStamp());
        if (StringUtils.isEmpty(state)) {
            logger.warn("IecType is empty! eqmCode: {}, timeStamp: {}", cacEntity.getEquipmentCode(),
                    cacEntity.getTimeStamp());
        }
        cacEntity.setRunState(state);
        // 设置rowkey，导入hbase使用
        cacEntity.setHbaseRowkey(Tools.strReverse(TimeUtil.getTimeStr(cacEntity.getTimeStamp())) + "_"
                + cacEntity.getSensorId() + "_" + TimeUtil.getTimeStr(cacEntity.getTimeStamp()) + "_"
                + cacEntity.getCacMonitorTypeCode() + "_" + cacEntity.getMainTreeId());

        // 保存
        super.saveHistoryData(cacEntity, equipmentInfo);
    }

    @Override
    protected void saveBusiWarning(TransformerWindingTemperature cacEntity, String cacMonitorTypeCode, String sensorId,
                                   EquipmentInfoDto equipmentInfo) {
        equipmentInfo.setSensorCode(sensorId);
        CacMonitorTypeCode type = CacMonitorTypeCode.from(cacMonitorTypeCode);
        // 变压器绕组测温
        if (CacMonitorTypeCode.TRANSFORMER_WindingTemperature == type) {
            saveTransformerWarning(cacEntity, equipmentInfo);
            return;
        }
    }

    private void saveTransformerWarning(TransformerWindingTemperature cacEntity, EquipmentInfoDto equipmentInfo) {
        if (StringUtils.isEmpty(cacEntity.getMaxTmp())) {
            logger.debug("变压器绕组测温最高温度为空不生成告警");
            return;
        }
        // 阈值
        WindingThresholdVo threshold =
                windingThresholdService.queryWindingThreshold(cacEntity.getSensorId(), cacEntity.getRunState());
        if (threshold == null || StringUtils.isEmpty(threshold.getRegionThreshold())) {
            logger.warn("变压器绕组测温阈值未匹配，sensorCode: {}, runState: {}", cacEntity.getSensorId(), cacEntity.getRunState());
            return;
        }
        // 阈值
        BigDecimal thresholdValue = DecimalUtil.getVal(threshold.getRegionThreshold());
        // 绕组测温时间
        BusiTransfromTemperatureExcess excess = busiTransfromTemperatureExcess
                .findBusiTransfromTemperatureExcess(cacEntity.getSiteId(), cacEntity.getMainTreeId());
        // 告警
        if (DecimalUtil.getVal(cacEntity.getMaxTmp()).compareTo(thresholdValue) > 0) {
            BusiEqmWarning busiEqmWarning =
                    newEw(EqType.EQ_TYPE1, GzType.GZ_TYPE20, msg(cacEntity), cacEntity.getCacMonitorTypeCode(), "1");
            busiEqmWarning.setWarningFlag("1");
            saveWarnAndDealInfo(busiEqmWarning, equipmentInfo, cacEntity, threshold);
            if (excess == null) {
                excess = new BusiTransfromTemperatureExcess();
                excess.setBeginTime(cacEntity.getTimeStamp());
                excess.setSiteId(cacEntity.getSiteId());
                excess.setSiteEqmCode(cacEntity.getMainTreeId());
                busiTransfromTemperatureExcess.saveOrUpdate(excess);
            } else {
                if (excess.getEndTime() == null) {
                    excess.setEndTime(cacEntity.getTimeStamp());
                    busiTransfromTemperatureExcess.saveOrUpdate(excess);
                }
                BusiTransfromTemperatureExcess excess2 = new BusiTransfromTemperatureExcess();
                excess2.setBeginTime(cacEntity.getTimeStamp());
                excess2.setSiteEqmCode(cacEntity.getMainTreeId());
                excess2.setSiteId(cacEntity.getSiteId());
                busiTransfromTemperatureExcess.saveOrUpdate(excess2);
            }
        } else {
            if (null != excess && excess.getEndTime() == null) {
                excess.setEndTime(cacEntity.getTimeStamp());
                busiTransfromTemperatureExcess.saveOrUpdate(excess);
            }
        }
    }

    @Override
    public void updateCurrentData(TransformerWindingTemperature cacEntity, EquipmentInfoDto equipmentInfo) {
        // 都保存到这一张表里面去
        transformerWindingTemperatureCacheService.saveTransformerWindingTemperatureCache(cacEntity);
    }

    private String msg(TransformerWindingTemperature cacEntity) {
        return format("绕组温度:{}℃超标", cacEntity.getMaxTmp());
    }

    /**
     * 增加报警及报警详情信息
     *
     * @param busiEqmWarning    设备报警
     * @param equipmentInfo     设备信息DAO
     * @param cacEntity         变压器/电抗器——绕组测温：021010、022002、023002、024007 entity
     * @param windingThreshold 绕组测温阈值
     */
    private void saveWarnAndDealInfo(BusiEqmWarning busiEqmWarning, EquipmentInfoDto equipmentInfo,
                                     TransformerWindingTemperature cacEntity, WindingThresholdVo windingThreshold) {
        // 保存告警
        busiEqmWarning.setWarningTime(cacEntity.getTimeStamp());
        busiEqmWarning.setRunState(cacEntity.getRunState());
        busiEqmWarning = this.buildWarning(busiEqmWarning, equipmentInfo);
        // 请求视频流截取图片或视频
        BusiVideoVo videoVo = busiVideoMapper.getRtspUrl(equipmentInfo.getSensorCode());
        // 图片名称
        String pictureBaseName = Uuid.getUUID() + "-";
        // 如果视频地址为空则不行
        if (StringUtils.isNotEmpty(videoVo.getRtspUrl())) {
            boolean cropImage = FFmpegUtil.cropImage(videoVo.getRtspUrl(), new File(pictureBasePath), Time.valueOf(startTime), Time.valueOf(endTime),
                    pictureBaseNum, pictureBaseName + "%01d" + suffix);
            // 截取图片成功再绑定关联关系
            if (cropImage) {
                // 计算时间差
                long k = (Time.valueOf(endTime).getTime() - Time.valueOf(startTime).getTime()) / 1000;
                // 计算图片数量有几张
                long i = k * pictureBaseNum;
                // 循环将每张图片都存储起来
                for (int j = 1; j <= i; j++) {
                    // 保存告警图片信息
                    BusiEqmWarningPicture picture = new BusiEqmWarningPicture();
                    picture.setWarningId(busiEqmWarning.getId());
                    picture.setWarningPicturePath("\\" + File.separator + videoCapture + "\\" + File.separator + pictureBaseName + j + suffix);
                    busiEqmWarningPictureService.save(picture);
                }
            }
        }
        // 保存告警详情
        BusiWindingVo busiWindingVo = new BusiWindingVo();
        busiWindingVo.setCollectValue(cacEntity.getMaxTmp());
        busiWindingVo.setRealValue(cacEntity.getMaxTmp());
        busiWindingVo.setThresholdValue(windingThreshold.getRegionThreshold());
        busiWindingVo.setEquipmentStatus(cacEntity.getRunState());
        busiWindingVo.setCollectDate(cacEntity.getTimeStamp());
        busiWindingVo.setPhase(cacEntity.getPhase());
        busiWindingVo.setEquipmentName(equipmentInfo.getSubEquipmentName());
        this.buildWarningInfo(busiEqmWarning, JSON.toJSONString(busiWindingVo));
    }

    /**
     * 数据输入-绕组测温原始数据查询（未完成）
     */
    @Override
    public Map<String, Object> findCACPageData(Map<String, Object> params) {
        if (params.get("page") != null && params.get("limit") != null) {
            PageHelper.startPage(page(params), limit(params));
        }
       Page<Map<String, Object>> page = transformerWindingTemperatureMapper.findCACPageData(params);
        return ResultUtil.put(ConstantUtil.REQUEST_SUCCESS, page.getTotal(), "", page.getResult());
    }

    @Override
    public Map<String, Object> exportCacMonitorData(Map<String, Object> mapParams) {
        Map<String, Object> returnMap = new HashMap<>();
        if (mapParams.containsKey("mainTreeId") && StringUtils.isNotEmpty(mapParams.get("mainTreeId") + "")) {
            BusiSiteTree busiSiteTree = busiSiteTreeService.findByPK(mapParams.get("mainTreeId") + "");
            List<TransformerWindingTemperatureVo> transformerWindingTemperatureList =
                    transformerWindingTemperatureMapper.exportCacMonitorData(mapParams);
            String replaceRegex = "[\\\\n`~!@#$%^&*()+=|{}':;',\\\\\\\\[\\\\\\\\].<>/?~！@#￥%……&*（）——+|{}【】‘；：”“’。， 、？]";
            String treeName = busiSiteTree.getName().replaceAll(replaceRegex, "-");
            returnMap.put("fileName", String.format("%s%s", treeName, "绕组监测数据"));
            returnMap.put("title", String.format("%s%s", treeName, "绕组监测数据"));
            if (transformerWindingTemperatureList.isEmpty()) {
                transformerWindingTemperatureList = new ArrayList<>();
                transformerWindingTemperatureList.add(new TransformerWindingTemperatureVo());
            }
            returnMap.put("data", transformerWindingTemperatureList);
        } else {
            throw new RuntimeException("主设备编码不正确");
        }
        return returnMap;
    }

    @Override
    public List<BaseCurveQueryDto> findSensorCodeList(LocalDate day) {
        return transformerWindingTemperatureMapper.findSensorCodeList(day.atStartOfDay(),
                day.plusDays(1).atStartOfDay());
    }

    @Override
    public List<PointItemVo> findDaylyPointList(BaseCurveQueryDto sensorCode, LocalDate day, String subType) {
        return transformerWindingTemperatureMapper.findDaylyPointList(sensorCode, subType, day.atStartOfDay(),
                day.plusDays(1).atStartOfDay());
    }

    @Override
    public PointItemDto getDaylyPointStatistics(BaseCurveQueryDto param) {
        return transformerWindingTemperatureMapper.getDaylyPointStatistics(param);
    }

    @Override
    protected List<Map<String, Object>> queryMonitorDataList(LocalDateTime startTime, LocalDateTime endTime) {
        return transformerWindingTemperatureMapper.queryMonitorDataList(startTime, endTime);
    }

    @Override
    protected void saveBusiOnlineMonitorData(BusiOnlineMonitorData busiOnlineMonitorData, Map<String, Object> item) {
        String cacMonitorTypeCode = popString(item, "cacMonitorTypeCode");
        // 变压器绕组测温
        if (CacMonitorTypeCode.TRANSFORMER_WindingTemperature.isThis(cacMonitorTypeCode)) {
            busiOnlineMonitorData.setSubEquipmentType(TransfromerTreeEnum.RZCW_EQM.getValue());
            busiOnlineMonitorData.setExtType(ExternalTypeEnum.BYQ.getValue());
            busiOnlineMonitorData.setEquipmentType(SiteTreeEnum.BYQ_EQM.getValue());
        } else {
            throw new OwlException(format("数据错误，sensorCode: {}", busiOnlineMonitorData.getSensorCode()));
        }
        // 这里将保存的任务交给父类方法完成，子类只需要修改指定几个字段就可以了
        super.saveBusiOnlineMonitorData(busiOnlineMonitorData, item);
    }

    @Override
    protected Map<String, Object> thresholdDataMap(BusiOnlineMonitorDataVo vo) {
        WindingThresholdVo thresholdVo =
                windingThresholdService.queryWindingThreshold(vo.getSensorCode(), vo.getRunState());
        return Tools.beanToMap(thresholdVo, "id");
    }

    @Override
    public WindingTemperatureStatisticsVo getListEquInfo(String cacMonitorTypeCode, LocalDate day, String sensorCode) {
        WindingTemperatureStatisticsDto param = new WindingTemperatureStatisticsDto();
        param.setStartTime(day.atStartOfDay());
        param.setEndTime(day.plusDays(1).atStartOfDay());
        param.setCacMonitorTypeCode(cacMonitorTypeCode);
        param.setSensorCode(sensorCode);
        List<WindingTemperatureStatisticsVo> list = transformerWindingTemperatureMapper.getListEquInfo(param);
        if (CollectionUtils.isEmpty(list)) {
            return null;
        }
        return list.get(0);
    }

    @Override
    public List<Map<String, Object>> queryHistory(String sensorCode, LocalDateTime startTime, LocalDateTime endTime) {
        // TODO Auto-generated method stub
        return transformerWindingTemperatureMapper.queryHistory(sensorCode, startTime, endTime);
    }

    public  HomeActualInfoVo build(HomeActualInfoVo homeActualInfoVo,BusiTransformerSensor busiTransformerSensor,String mainTreeId){
        homeActualInfoVo.setEquipmentBrand(busiTransformerSensor.getSensorBrand());
        homeActualInfoVo.setEquipmentName(busiTransformerSensor.getSensorName());
        homeActualInfoVo.setInstallLocation(busiTransformerSensor.getPositionDes());
        homeActualInfoVo.setEqmId(busiTransformerSensor.getEquipmentId());
        homeActualInfoVo.setPhase(busiTransformerSensor.getPosition());
        homeActualInfoVo.setManufactor(busiTransformerSensor.getManufactor());
        homeActualInfoVo.setSensorBrand(busiTransformerSensor.getSensorBrand());
        homeActualInfoVo.setUseDate(busiTransformerSensor.getUseDate());
        homeActualInfoVo.setSensorId(busiTransformerSensor.getSensorCode());
        homeActualInfoVo.setSensorName(busiTransformerSensor.getSensorName());
        homeActualInfoVo.setMainTreeId(mainTreeId);
        return homeActualInfoVo;
    }

    @Override
    public HomeActualVo queryActual(HomeSearchDto param) {
        HomeActualVo homeActualVo=new HomeActualVo();
        BusiTransformerSensor busiTransformerSensor = busiTransformerSensorDao.get(new WherePrams()
                .where("sensor_code", param.getSensorCode()));
        if(ObjectUtils.isEmpty(busiTransformerSensor)){
            return homeActualVo;
        }
        HomeActualInfoVo homeActualInfoVo =new HomeActualInfoVo();
        String mainTreeId=busiTransfromerSubTreeDao.get(busiTransformerSensor.getEquipmentId()).getEquipmentId();

        homeActualInfoVo = build(homeActualInfoVo, busiTransformerSensor, mainTreeId);
        String date = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, DateUtils.addDays(new Date(), -1));
        BusiOnlineMonitorData busiOnlineMonitorData = busiOnlineMonitorDataDao.get(new WherePrams()
                .where("sensor_code", param.getSensorCode())
                .and("day","like",date));
        //组装各种率
        if(!ObjectUtils.isEmpty(busiOnlineMonitorData)){
            homeActualInfoVo.setRunState(busiOnlineMonitorData.getRunState());
            homeActualInfoVo.setFalseAlarmRate(busiOnlineMonitorData.getFalseAlarmRate());
            homeActualInfoVo.setLossRate(busiOnlineMonitorData.getLossRate());
            homeActualInfoVo.setRepairCount(busiOnlineMonitorData.getRepairCount());
            homeActualInfoVo.setDTime(busiOnlineMonitorData.getCreatedTime());
        }
        homeActualVo.setHomeActualInfoVo(homeActualInfoVo);
        List<TransformerWindingTemperature> list = transformerWindingTemperatureDao.list(new WherePrams()
                .where("sensor_id", param.getSensorCode())
                .orderBy("time_stamp desc limit 1"));
        HomeActualDataVo homeActualDataVo=new HomeActualDataVo();
        List<HomeActualDataVo> homeActualDataVos=new ArrayList<>();
        if(CollectionUtils.isEmpty(list)){

            return homeActualVo;
        }

        TransformerWindingTemperature transformerWindingTemperature = list.get(0);
        homeActualDataVo.setDTime(transformerWindingTemperature.getTimeStamp());
        homeActualDataVo.setName("温度(℃)");
        homeActualDataVo.setValue(transformerWindingTemperature.getMaxTmp());
        String thresholdValue="";
        WindingThreshold windingThreshold = windingThresholdDao.get(new WherePrams()
                .where("sensor_code", param.getSensorCode())
                .and("work_status",list.get(0).getRunState()));
        if(!ObjectUtils.isEmpty(windingThreshold)){
            thresholdValue=windingThreshold.getRegionThreshold();
        }
        homeActualDataVo.setThresholdValue(thresholdValue);
        homeActualDataVos.add(homeActualDataVo);
        homeActualVo.setHomeActualDataVos(homeActualDataVos);
        return homeActualVo;
    }

    @Override
    public List<HomeActualVo> queryActuals() {
        List<HomeActualVo> homeActualVos=new ArrayList<>();
        List<String> equipmentTypeList=new ArrayList<>();
        equipmentTypeList.add(SiteConstants.TransfromerTreeEnum.RZCW_EQM.getValue());
        BusiSensorQueryParamDto param =new BusiSensorQueryParamDto();
        param.setEquipmentTypeList(equipmentTypeList);
        List<BusiSensorVo> sensorList =  busiTransformerSensorService.findSensorList(param);
        if(CollectionUtils.isEmpty(sensorList)){
            return homeActualVos;
        }
        for (BusiSensorVo busiSensorVo:sensorList) {
            HomeSearchDto homeSearchDto= new HomeSearchDto();
            homeSearchDto.setSensorCode(busiSensorVo.getSensorCode());
            HomeActualVo homeActualVo = this.queryActual(homeSearchDto);
            homeActualVo.setName(busiSensorVo.getMainEquipmentName());
            homeActualVos.add(homeActualVo);
        }
        return homeActualVos;
    }
}
