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

import java.io.File;
import java.math.BigDecimal;
import java.sql.Time;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.huatek.busi.entity.*;
import com.huatek.busi.mapper.BusiVideoMapper;
import com.huatek.busi.service.BusiEqmWarningPictureService;
import com.huatek.busi.util.FFmpegUtil;
import com.huatek.busi.vo.*;
import com.huatek.torch.util.uuid.Uuid;
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 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.SiteConstants.ArresterTreeEnum;
import com.huatek.busi.common.SiteConstants.ExternalTypeEnum;
import com.huatek.busi.common.SiteConstants.GisTreeEnum;
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.dto.EquipmentInfoDto;
import com.huatek.busi.dto.InfraredTemperatureStatisticsDto;
import com.huatek.busi.dto.curve.BaseCurveQueryDto;
import com.huatek.busi.dto.curve.PointItemDto;
import com.huatek.busi.mapper.TransformerInfraredTemperatureMapper;
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.InfraredThresholdService;
import com.huatek.busi.service.transformer.TransformerInfraredMonitoringCacheService;
import com.huatek.busi.service.transformer.TransformerInfraredTemperatureService;
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;

/**
 * 变压器/电抗器——红外测温：021010、022002、023002、024007 ServiceImpl
 *
 * @author anker_cheng
 * @date Jun 26, 2019 1:11:48 PM
 */
@Component
@Service(interfaceClass = TransformerInfraredTemperatureService.class)
@Transactional(rollbackFor = Exception.class)
public class TransformerInfraredTemperatureServiceImpl extends AbstractCacEtlService<TransformerInfraredTemperature>
        implements TransformerInfraredTemperatureService {

    @Autowired
    private InfraredThresholdService infraredThresholdService;

    @Reference(check = false)
    private BusiTransfromTemperatureExcessService busiTransfromTemperatureExcess;

    @Reference(check = false)
    private IecBydworkParamService iecBydworkParamService;

    @Reference(check = false)
    private BusiSiteTreeService busiSiteTreeService;

    @Reference(check = false)
    private TransformerInfraredMonitoringCacheService transformerInfraredMonitoringCacheService;

    @Reference(check = false)
    private BusiEqmWarningPictureService busiEqmWarningPictureService;

    @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 TransformerInfraredTemperatureMapper transformerInfraredTemperatureMapper;

    @Autowired
    private BusiVideoMapper busiVideoMapper;

    @Override
    public void saveHistoryData(TransformerInfraredTemperature 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(TransformerInfraredTemperature cacEntity, String cacMonitorTypeCode, String sensorId,
                                   EquipmentInfoDto equipmentInfo) {
        equipmentInfo.setSensorCode(sensorId);
        CacMonitorTypeCode type = CacMonitorTypeCode.from(cacMonitorTypeCode);
        // 变压器红外测温
        if (CacMonitorTypeCode.TRANSFORMER_InfraredTemperature == type) {
            saveTransformerWarning(cacEntity, equipmentInfo);
            return;
        }
        // 电容型设备红外测温
        if (CacMonitorTypeCode.CAPACITIVE_EQUIPMENT_InfraredTemperature == type) {
            saveInfraredTemperature(cacEntity, equipmentInfo);
            return;
        }
        // 避雷器红外测温
        if (CacMonitorTypeCode.LIGHTNINGROD_InfraredTemperature == type) {
            saveArresterWarning(cacEntity, equipmentInfo);
            return;
        }
        // GIS红外测温
        if (CacMonitorTypeCode.GIS_InfraredTemperature == type) {
            saveGisWarning(cacEntity, equipmentInfo);
            return;
        }
    }

    private void saveTransformerWarning(TransformerInfraredTemperature cacEntity, EquipmentInfoDto equipmentInfo) {
        if (StringUtils.isEmpty(cacEntity.getMaxTmp())) {
            logger.debug("变压器红外测温最高温度为空不生成告警");
            return;
        }
        // 阈值
        InfraredThresholdVo threshold =
                infraredThresholdService.queryInfraredThreshold(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_TYPE4, 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);
            }
        }
    }

    private void saveArresterWarning(TransformerInfraredTemperature cacEntity, EquipmentInfoDto equipmentInfo) {
        if (StringUtils.isEmpty(cacEntity.getMaxTmp())) {
            logger.debug("避雷器外测温最高温度为空不生成告警");
            return;
        }
        // 阈值
        InfraredThresholdVo threshold =
                infraredThresholdService.queryInfraredThreshold(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());
        // 告警
        if (DecimalUtil.getVal(cacEntity.getMaxTmp()).compareTo(thresholdValue) > 0) {
            BusiEqmWarning busiEqmWarning =
                    newEw(EqType.EQ_TYPE3, GzType.GZ_TYPE4, msg(cacEntity), cacEntity.getCacMonitorTypeCode(), "1");
            saveWarnAndDealInfo(busiEqmWarning, equipmentInfo, cacEntity, threshold);
        }
    }

    private void saveInfraredTemperature(TransformerInfraredTemperature cacEntity, EquipmentInfoDto equipmentInfo) {
        if (StringUtils.isEmpty(cacEntity.getMaxTmp())) {
            logger.debug("电容性外测温最高温度为空不生成告警");
            return;
        }
        // 阈值
        InfraredThresholdVo threshold =
                infraredThresholdService.queryInfraredThreshold(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());
        // 告警
        if (DecimalUtil.getVal(cacEntity.getMaxTmp()).compareTo(thresholdValue) > 0) {
            BusiEqmWarning busiEqmWarning =
                    newEw(EqType.EQ_TYPE3, GzType.GZ_TYPE12, msg(cacEntity), cacEntity.getCacMonitorTypeCode(), "1");
            saveWarnAndDealInfo(busiEqmWarning, equipmentInfo, cacEntity, threshold);
        }
    }

    private void saveGisWarning(TransformerInfraredTemperature cacEntity, EquipmentInfoDto equipmentInfo) {
        if (StringUtils.isEmpty(cacEntity.getMaxTmp())) {
            logger.debug("GIS外测温最高温度为空不生成告警");
            return;
        }
        // 阈值
        InfraredThresholdVo threshold =
                infraredThresholdService.queryInfraredThreshold(cacEntity.getSensorId(), cacEntity.getRunState());
        if (threshold == null || StringUtils.isEmpty(threshold.getRegionThreshold())) {
            logger.warn("GIS红外测温阈值未匹配，sensorCode: {}, runState: {}", cacEntity.getSensorId(), cacEntity.getRunState());
            return;
        }
        // 阈值
        BigDecimal thresholdValue = DecimalUtil.getVal(threshold.getRegionThreshold());
        // 告警
        if (DecimalUtil.getVal(cacEntity.getMaxTmp()).compareTo(thresholdValue) > 0) {
            BusiEqmWarning busiEqmWarning =
                    newEw(EqType.EQ_TYPE2, GzType.GZ_TYPE4, msg(cacEntity), cacEntity.getCacMonitorTypeCode(), "1");
            busiEqmWarning.setWarningFlag("1");
            saveWarnAndDealInfo(busiEqmWarning, equipmentInfo, cacEntity, threshold);
        }
    }

    @Override
    public void updateCurrentData(TransformerInfraredTemperature cacEntity) {
        // 都保存到这一张表里面去
        transformerInfraredMonitoringCacheService.saveTransformerInfraredMonitoringCache(cacEntity);
    }

    private String msg(TransformerInfraredTemperature cacEntity) {
        return format("红外温度:{}℃超标", cacEntity.getMaxTmp());
    }

    /**
     * 增加报警及报警详情信息
     *
     * @param busiEqmWarning    设备报警
     * @param equipmentInfo     设备信息DAO
     * @param cacEntity         变压器/电抗器——红外测温：021010、022002、023002、024007 entity
     * @param infraredThreshold 红外测温阈值
     */
    private void saveWarnAndDealInfo(BusiEqmWarning busiEqmWarning, EquipmentInfoDto equipmentInfo,
                                     TransformerInfraredTemperature cacEntity, InfraredThresholdVo infraredThreshold) {
        // 保存告警
        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);
                }
            }
        }
        // 保存告警详情
        BusiInfraredVo busiInfraredVo = new BusiInfraredVo();
        busiInfraredVo.setCollectValue(cacEntity.getMaxTmp());
        busiInfraredVo.setRealValue(cacEntity.getMaxTmp());
        busiInfraredVo.setThresholdValue(infraredThreshold.getRegionThreshold());
        busiInfraredVo.setEquipmentStatus(cacEntity.getRunState());
        busiInfraredVo.setCollectDate(cacEntity.getTimeStamp());
        busiInfraredVo.setPhase(cacEntity.getPhase());
        busiInfraredVo.setEquipmentName(equipmentInfo.getSubEquipmentName());
        this.buildWarningInfo(busiEqmWarning, JSON.toJSONString(busiInfraredVo));
    }

    /**
     * 数据输入-红外原始数据查询
     */
    @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 = transformerInfraredTemperatureMapper.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<TransformerInfraredTemperatureVo> transformerInfraredTemperatureList =
                    transformerInfraredTemperatureMapper.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 (transformerInfraredTemperatureList.isEmpty()) {
                transformerInfraredTemperatureList = new ArrayList<>();
                transformerInfraredTemperatureList.add(new TransformerInfraredTemperatureVo());
            }
            returnMap.put("data", transformerInfraredTemperatureList);
        } else {
            throw new RuntimeException("主设备编码不正确");
        }
        return returnMap;
    }

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

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

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

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

    @Override
    protected void saveBusiOnlineMonitorData(BusiOnlineMonitorData busiOnlineMonitorData, Map<String, Object> item) {
        String cacMonitorTypeCode = popString(item, "cacMonitorTypeCode");
        // 变压器红外测温
        if (CacMonitorTypeCode.TRANSFORMER_InfraredTemperature.isThis(cacMonitorTypeCode)) {
            busiOnlineMonitorData.setSubEquipmentType(TransfromerTreeEnum.HW_EQM.getValue());
            busiOnlineMonitorData.setExtType(ExternalTypeEnum.BYQ.getValue());
            busiOnlineMonitorData.setEquipmentType(SiteTreeEnum.BYQ_EQM.getValue());
        }
        // 电容型设备红外测温
        else if (CacMonitorTypeCode.CAPACITIVE_EQUIPMENT_InfraredTemperature.isThis(cacMonitorTypeCode)) {
            throw new OwlException("容性设备-红外测温未处理");
        }
        // 避雷器红外测温
        else if (CacMonitorTypeCode.LIGHTNINGROD_InfraredTemperature.isThis(cacMonitorTypeCode)) {
            busiOnlineMonitorData.setSubEquipmentType(ArresterTreeEnum.HW_EQM.getValue());
            busiOnlineMonitorData.setExtType(ExternalTypeEnum.BLQ.getValue());
            busiOnlineMonitorData.setEquipmentType(SiteTreeEnum.BLQ_HL_EQM.getValue());
        }
        // GIS红外测温
        else if (CacMonitorTypeCode.GIS_InfraredTemperature.isThis(cacMonitorTypeCode)) {
            busiOnlineMonitorData.setSubEquipmentType(GisTreeEnum.HW_EQM.getValue());
            busiOnlineMonitorData.setExtType(ExternalTypeEnum.GIS.getValue());
            busiOnlineMonitorData.setEquipmentType(SiteTreeEnum.GIS_HL_EQM.getValue());
        } else {
            throw new OwlException(format("数据错误，sensorCode: {}", busiOnlineMonitorData.getSensorCode()));
        }
        // 这里将保存的任务交给父类方法完成，子类只需要修改指定几个字段就可以了
        super.saveBusiOnlineMonitorData(busiOnlineMonitorData, item);
    }

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

    @Override
    public InfraredTemperatureStatisticsVo getListEquInfo(String cacMonitorTypeCode, LocalDate day, String sensorCode) {
        InfraredTemperatureStatisticsDto param = new InfraredTemperatureStatisticsDto();
        param.setStartTime(day.atStartOfDay());
        param.setEndTime(day.plusDays(1).atStartOfDay());
        param.setCacMonitorTypeCode(cacMonitorTypeCode);
        param.setSensorCode(sensorCode);
        List<InfraredTemperatureStatisticsVo> list = transformerInfraredTemperatureMapper.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 transformerInfraredTemperatureMapper.queryHistory(sensorCode, startTime, endTime);
    }
}
