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

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import com.huatek.busi.common.SiteConstants;
import com.huatek.busi.service.cable.BusiCableCirculationCacheService;
import com.huatek.busi.service.cable.CableCirculationtemperIncreaseRateCacheService;
import com.huatek.busi.service.cable.CableCirculationtemperIncreaseRateService;
import com.huatek.busi.service.temperature.TemperIncreaseRateService;
import com.huatek.frame.base.util.BusinessConstants;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import com.alibaba.dubbo.config.annotation.Service;
import com.alibaba.fastjson.JSON;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
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.DateUtil;
import com.huatek.busi.common.util.Tools;
import com.huatek.busi.dao.BusiOnlineMonitorDataDao;
import com.huatek.busi.dao.BusiOnlineMonitorDataInfoDao;
import com.huatek.busi.dto.monitor.BusiOnlineMonitorDataDto;
import com.huatek.busi.dto.monitor.BusiOnlineMonitorTrendDataDto;
import com.huatek.busi.entity.BusiOnlineMonitorData;
import com.huatek.busi.entity.BusiOnlineMonitorDataInfo;
import com.huatek.busi.entity.TransformerEpaDeviationStatistics;
import com.huatek.busi.mapper.BusiOnlineMonitorDataMapper;
import com.huatek.busi.mapper.BusiSubTreeMapper;
import com.huatek.busi.service.BusiCommonService;
import com.huatek.busi.service.BusiEqmWarningService;
import com.huatek.busi.service.BusiSensorService;
import com.huatek.busi.service.BusiStabilityService;
import com.huatek.busi.service.FailureRateService;
import com.huatek.busi.service.curve.CurveSensorEntityService;
import com.huatek.busi.service.impl.monitor.helper.MonitorDataTableMapping;
import com.huatek.busi.service.monitor.BaseMonitorDataTaskService;
import com.huatek.busi.service.monitor.BusiOnlineMonitorDataService;
import com.huatek.busi.service.transformer.TransformerEpaDeviationStatisticsService;
import com.huatek.busi.vo.BusiSensorVo;
import com.huatek.busi.vo.BusiStabilityIndexVo;
import com.huatek.busi.vo.BusiTreeNodeVo;
import com.huatek.busi.vo.echarts.EchartLineDataVo;
import com.huatek.busi.vo.monitor.BusiMonitorIcgeDataVo;
import com.huatek.busi.vo.monitor.BusiOnlineMonitorDataVo;
import com.huatek.torch.frame.exception.OwlException;
import com.huatek.torch.util.uuid.Uuid;

import lombok.extern.slf4j.Slf4j;

/**
 * 在线监测——监测数据Service实现
 *
 * @author buck_guo
 * @date 2019/08/27
 */
@Slf4j
@Component
@Service(interfaceClass = BusiOnlineMonitorDataService.class)
public class BusiOnlineMonitorDataServiceImpl implements BusiOnlineMonitorDataService, ApplicationContextAware {
    /**
     * 实现类Map缓存
     */
    private final Map<String, BaseMonitorDataTaskService> serviceImplMap = Maps.newConcurrentMap();

    @Autowired
    private BusiOnlineMonitorDataMapper busiOnlineMonitorDataMapper;
    @Autowired
    private BusiOnlineMonitorDataDao busiOnlineMonitorDataDao;
    @Autowired
    private BusiOnlineMonitorDataInfoDao busiOnlineMonitorDataInfoDao;
    @Autowired
    private BusiSubTreeMapper busiSubTreeMapper;
    @Autowired
    private BusiCommonService busiCommonService;
    @Autowired
    private BusiSensorService busiSensorService;
    @Autowired
    private BusiEqmWarningService busiEqmWarningService;
    @Autowired
    private FailureRateService failureRateService;
    @Autowired
    private CurveSensorEntityService curveSensorEntityService;
    @Autowired
    private BusiStabilityService busiStabilityService;
    @Autowired
    private TransformerEpaDeviationStatisticsService transformerEpaDeviationStatisticsService;
    @Autowired
    private CableCirculationtemperIncreaseRateService cableCirculationtemperIncreaseRateService;
    @Autowired
    private TemperIncreaseRateService temperIncreaseRateService;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        Map<String, BaseMonitorDataTaskService> beansOfTypeMap =
                applicationContext.getBeansOfType(BaseMonitorDataTaskService.class);
        if (CollectionUtils.isEmpty(beansOfTypeMap)) {
            log.debug("implement class is empty!");
            return;
        }
        for (BaseMonitorDataTaskService service : beansOfTypeMap.values()) {
            if (service.persistentClass() == null) {
                log.debug("{}.persistentClass is empty!", service.getClass().getName());
                continue;
            }
            serviceImplMap.put(service.persistentClass().getName(), service);
        }
    }

    private BaseMonitorDataTaskService serviceImpl(String equipmentType, String subEquipmentType) {
        String tableMapping = MonitorDataTableMapping.getTableMapping(equipmentType, subEquipmentType);
        BaseMonitorDataTaskService service = serviceImplMap.get(tableMapping);
        if (service == null) {
            throw new OwlException("无法获取实现类：" + tableMapping);
        }
        return service;
    }

    @Override
    public List<BusiTreeNodeVo> subEquipmentList(String mainEquipmentType, String subEquipmentType,
                                                 String mainEquipmentId) {
        if (SiteTreeEnum.BYQ_EQM.getValue().equals(mainEquipmentType)) {
            if (TransfromerTreeEnum.TX_EQM.getValue().equals(subEquipmentType)) {
                List<BusiTreeNodeVo> list = new ArrayList<BusiTreeNodeVo>();
                list.addAll(busiSubTreeMapper.getTransformerSubTree(mainEquipmentId, subEquipmentType));
                list.addAll(busiSubTreeMapper.getTransformerSubTree(mainEquipmentId, TransfromerTreeEnum.JJ_EQM.getValue()));
                return list;
            } else {
                return busiSubTreeMapper.getTransformerSubTree(mainEquipmentId, subEquipmentType);
            }
        }
        if (SiteTreeEnum.GIS_HL_EQM.getValue().equals(mainEquipmentType)) {
            return busiSubTreeMapper.getGisSubTree(mainEquipmentId, subEquipmentType);
        }
        if (SiteTreeEnum.CW_HL_EQM.getValue().equals(mainEquipmentType)) {
            //return busiTemperPointService.q
        }
        if (SiteTreeEnum.BLQ_HL_EQM.getValue().equals(mainEquipmentType)) {
            return busiSubTreeMapper.getArresterSubTree(mainEquipmentId, subEquipmentType);
        }
        if (SiteTreeEnum.OTHER_EQM.getValue().equals(mainEquipmentType)) {
            return busiSubTreeMapper.getOtherSubTree(mainEquipmentId, subEquipmentType);
        }
        // mark 20230330添加
        if (SiteTreeEnum.DL_EQM.getValue().equals(mainEquipmentType)) {
            return busiSubTreeMapper.getCableSubTree(mainEquipmentId, subEquipmentType);
        }
        if (SiteTreeEnum.GEN_EQM.getValue().equals(mainEquipmentType)) {
            return busiSubTreeMapper.getGenSubTree(mainEquipmentId, subEquipmentType);
        }
        return null;
    }

    /**
     * 在线监测数据查询
     */
    @Override
    public PageInfo<BusiOnlineMonitorDataVo>
    selectBusiOnlineMonitorDataPage(BusiOnlineMonitorDataDto busiOnlineMonitorDataDto) {
        if (SiteTreeEnum.CW_HL_EQM.getValue().equals(busiOnlineMonitorDataDto.getEquipmentType())) {
            return PageHelper.startPage(busiOnlineMonitorDataDto.getPage(), busiOnlineMonitorDataDto.getLimit())
                    .doSelectPageInfo(
                            () -> busiOnlineMonitorDataMapper.selectCWBusiOnlineMonitorDataPage(busiOnlineMonitorDataDto));
        } else {
            return PageHelper.startPage(busiOnlineMonitorDataDto.getPage(), busiOnlineMonitorDataDto.getLimit())
                    .doSelectPageInfo(
                            () -> busiOnlineMonitorDataMapper.selectBusiOnlineMonitorDataPage(busiOnlineMonitorDataDto));
        }
    }

    @Override
    public PageInfo<BusiOnlineMonitorDataVo>
    findBusiOnlineMonitorDataPage(BusiOnlineMonitorDataDto busiOnlineMonitorDataDto) {
        BaseMonitorDataTaskService serviceImpl = serviceImpl(busiOnlineMonitorDataDto.getEquipmentType(),
                busiOnlineMonitorDataDto.getSubEquipmentType());
        return serviceImpl.findBusiOnlineMonitorDataPage(busiOnlineMonitorDataDto);
    }

    @Override
    public synchronized BusiOnlineMonitorData generateBusiOnlineMonitorData(LocalDate day, String sensorCode, String runState) {
        BusiOnlineMonitorData busiOnlineMonitorData =
                busiOnlineMonitorDataMapper.getBusiOnlineMonitorData(day, sensorCode, runState);
        if (busiOnlineMonitorData == null) {
            busiOnlineMonitorData = new BusiOnlineMonitorData();
            busiOnlineMonitorData.setId(Uuid.getUUID());
            busiOnlineMonitorData.setCreatedTime(LocalDateTime.now());
            busiOnlineMonitorData.setSensorCode(sensorCode);
            busiOnlineMonitorData.setDay(day);
            busiOnlineMonitorDataDao.add(busiOnlineMonitorData);
        }
        return busiOnlineMonitorData;
    }

    @Override
    public synchronized BusiOnlineMonitorData generateBusiOnlineMonitorData(LocalDate day, Map<String, Object> map) {
        String sensorCode = Tools.popString(map, "sensorCode");
        String mainTreeId = Tools.popString(map, "mainTreeId");
        String subTreeId = Tools.popString(map, "subTreeId");
        String mainEquipmentId = Tools.popString(map, "mainEquipmentId");
        String subEquipmentId = Tools.popString(map, "subEquipmentId");
        String siteId = Tools.popString(map, "siteId");
        String runState = Tools.popString(map, "runState");
        String phase = Tools.popString(map, "phase");
        BusiOnlineMonitorData busiOnlineMonitorData = this.generateBusiOnlineMonitorData(day, sensorCode, runState);
        busiOnlineMonitorData.setRunState(runState);
        busiOnlineMonitorData.setMainTreeId(mainTreeId);
        busiOnlineMonitorData.setMainEquipmentId(mainEquipmentId);
        busiOnlineMonitorData.setSubTreeId(subTreeId);
        busiOnlineMonitorData.setSubEquipmentId(subEquipmentId);
        busiOnlineMonitorData.setSiteId(siteId);
        busiOnlineMonitorData.setPhase(phase);
        return busiOnlineMonitorData;
    }

    @Override
    public void saveBusiOnlineMonitorData(BusiOnlineMonitorData busiOnlineMonitorData, String data) {
        ExternalTypeEnum externalTypeEnum = ExternalTypeEnum.fromValue(busiOnlineMonitorData.getExtType());
        LocalDate day = busiOnlineMonitorData.getDay();
        Date startTime = DateUtil.toDate(day.atStartOfDay());
        Date endTime = DateUtil.toDate(day.plusDays(1).atStartOfDay());
        // 维修次数
        busiOnlineMonitorData.setRepairCount(
                busiCommonService.getEquipHalfYearRepairCount(externalTypeEnum, busiOnlineMonitorData.getSubEquipmentId()));
        // TODO 相对增长率（%/月）
        // TODO 绝对增长率（%/月）
        // 其他-电缆环流月增长率
        if (SiteTreeEnum.OTHER_EQM.getValue().equals(busiOnlineMonitorData.getEquipmentType()) && SiteConstants.OtherTreeEnum.DLHL_EQM.getValue().equals(busiOnlineMonitorData.getSubEquipmentType())) {
            busiOnlineMonitorData.setMonthlyAbsolutelyGrowthRate(cableCirculationtemperIncreaseRateService.getMonthlyGrowThRate(busiOnlineMonitorData.getSensorCode(), day));
        }
        // 增加开关柜测温点将日增长率存为相对增长率
        if (SiteTreeEnum.CW_HL_EQM.getValue().equals(busiOnlineMonitorData.getEquipmentType())) {
            busiOnlineMonitorData.setMonthlyRelativeGrowthRate(temperIncreaseRateService.getDailyGrowthRate(busiOnlineMonitorData.getSensorCode(), day));
        }
        // 电缆-电缆环流月增长率
        if (SiteTreeEnum.DL_EQM.getValue().equals(busiOnlineMonitorData.getEquipmentType()) && SiteConstants.CableTreeEnum.DLHL_EQM.getValue().equals(busiOnlineMonitorData.getSubEquipmentType())) {
            busiOnlineMonitorData.setMonthlyAbsolutelyGrowthRate(cableCirculationtemperIncreaseRateService.getMonthlyGrowThRate(busiOnlineMonitorData.getSensorCode(), day));
        }
        // 数据缺失率
        busiOnlineMonitorData.setLossRate(failureRateService.getSensorLossRate(busiOnlineMonitorData.getSensorCode(), startTime, endTime));
        // 误报率
        busiOnlineMonitorData.setFalseAlarmRate(busiEqmWarningService.getFalseAlarmRateBySensor(
                busiOnlineMonitorData.getSensorCode(), null, DateUtil.atEndOfDay(busiOnlineMonitorData.getDay())));
        // 稳定性指标
        String stabilityIndex = "";
        BusiStabilityIndexVo busiStabilityIndexVo = busiStabilityService.findStabilityMapByCondition(busiOnlineMonitorData.getSensorCode(), busiOnlineMonitorData.getRunState());
        if (busiStabilityIndexVo != null) {
            stabilityIndex = busiStabilityIndexVo.getStabilityIndex();
        }
        busiOnlineMonitorData.setStabilityIndex(stabilityIndex);
        //偏差率
        String accuracyIndex = StringUtils.EMPTY;
        TransformerEpaDeviationStatistics epaDeviationStatistics = transformerEpaDeviationStatisticsService.getTransformerEpaDeviationStatisticsInfo(busiOnlineMonitorData.getSensorCode(), day);
        if (!ObjectUtils.isEmpty(epaDeviationStatistics)) {
            accuracyIndex = JSON.toJSONString(epaDeviationStatistics);
            busiOnlineMonitorData.setAccuracyIndex(accuracyIndex);
        }
        busiOnlineMonitorDataDao.updateLocal(busiOnlineMonitorData);
        // 删除并保存Info表数据
        saveBusiOnlineMonitorDataInfo(busiOnlineMonitorData, data);
    }

    private void saveBusiOnlineMonitorDataInfo(BusiOnlineMonitorData busiOnlineMonitorData, String data) {
        // 删除并保存Info表数据
        busiOnlineMonitorDataMapper.deleteBusiOnlineMonitorDataInfo(busiOnlineMonitorData.getId());
        BusiOnlineMonitorDataInfo busiOnlineMonitorDataInfo = new BusiOnlineMonitorDataInfo();
        busiOnlineMonitorDataInfo.setId(Uuid.getUUID());
        busiOnlineMonitorDataInfo.setRefId(busiOnlineMonitorData.getId());
        busiOnlineMonitorDataInfo.setData(data);
        busiOnlineMonitorDataInfoDao.add(busiOnlineMonitorDataInfo);
    }

    @Override
    public EchartLineDataVo trend(BusiOnlineMonitorTrendDataDto param) {
        return curveSensorEntityService.getTrendData(param);
    }

    @Override
    public BusiSensorVo findBusiSensorVo(String equipmentType, String sensorCode) {
        ExternalTypeEnum externalTypeEnum = null;
        if (SiteTreeEnum.BYQ_EQM.getValue().equals(equipmentType)) {
            externalTypeEnum = ExternalTypeEnum.BYQ;
        } else if (SiteTreeEnum.GIS_HL_EQM.getValue().equals(equipmentType)) {
            externalTypeEnum = ExternalTypeEnum.GIS;
        } else if (SiteTreeEnum.CW_HL_EQM.getValue().equals(equipmentType)) {
            externalTypeEnum = ExternalTypeEnum.CW;
        } else if (SiteTreeEnum.BLQ_HL_EQM.getValue().equals(equipmentType)) {
            externalTypeEnum = ExternalTypeEnum.BLQ;
        } else if (SiteTreeEnum.OTHER_EQM.getValue().equals(equipmentType)) {
            externalTypeEnum = ExternalTypeEnum.OTHER;
        } else {
            throw new OwlException("未知类型：equipmentType=" + equipmentType + ", sensorCode=" + sensorCode);
        }
        BusiSensorVo busiSensorVo = busiSensorService.getBusiSensorVo(externalTypeEnum, sensorCode);
        if (busiSensorVo != null) {
            // 稳定性
            busiSensorVo.setStabilityMap(busiStabilityService.findStabilityMapBySensorCode(sensorCode));
        }
        return busiSensorVo;
    }


    /**
     * 导出在线监测数据
     */
    @Override
    public List<BusiOnlineMonitorDataVo> selectBusiOnlineMonitorData(BusiOnlineMonitorDataDto busiOnlineMonitorDataDto) {
        // TODO Auto-generated method stub
        List<BusiOnlineMonitorDataVo> resultList = Lists.newArrayList();
        if (SiteTreeEnum.CW_HL_EQM.getValue().equals(busiOnlineMonitorDataDto.getEquipmentType())) {
            resultList = busiOnlineMonitorDataMapper.exportCWBusiOnlineMonitorDataPage(busiOnlineMonitorDataDto);
        } else {
            resultList = busiOnlineMonitorDataMapper.exportBusiOnlineMonitorDataPage(busiOnlineMonitorDataDto);
        }
        return resultList;
    }

    /**
     * 导出在线监测数据
     */
    @Override
    public List<BusiOnlineMonitorDataVo> exportBusiOnlineMonitorDataPage(BusiOnlineMonitorDataDto busiOnlineMonitorDataDto) {
        // TODO Auto-generated method stub
        BaseMonitorDataTaskService serviceImpl = serviceImpl(busiOnlineMonitorDataDto.getEquipmentType(),
                busiOnlineMonitorDataDto.getSubEquipmentType());
        return serviceImpl.exportBusiOnlineMonitorDataPage(busiOnlineMonitorDataDto);
    }

    @Override
    public Class<?> getExportVoClass() {
        // TODO Auto-generated method stub
        return BusiMonitorIcgeDataVo.class;
    }
}