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

import java.lang.reflect.ParameterizedType;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import cn.hutool.core.bean.BeanUtil;
import com.huatek.busi.common.SiteConstants;
import com.huatek.busi.dao.EquipmentTemperatureCacheDao;
import com.huatek.busi.entity.EquipmentTemperatureCache;
import com.huatek.busi.service.threshold.GeneratorAmplThresholdService;
import com.huatek.busi.service.transformer.EquipmentTemperatureCacheService;
import com.huatek.torch.util.uuid.Uuid;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.helpers.FormattingTuple;
import org.slf4j.helpers.MessageFormatter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;

import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Maps;
import com.huatek.busi.common.BusiConstant;
import com.huatek.busi.common.CacDataType;
import com.huatek.busi.common.CacMonitorTypeCode;
import com.huatek.busi.common.SiteConstants.ArresterTreeEnum;
import com.huatek.busi.common.SiteConstants.GisTreeEnum;
import com.huatek.busi.common.SiteConstants.IecTypeEnum;
import com.huatek.busi.common.SiteConstants.OtherTreeEnum;
import com.huatek.busi.common.SiteConstants.SiteTreeEnum;
import com.huatek.busi.common.SiteConstants.TransfromerTreeEnum;
import com.huatek.busi.common.util.FieldUtil;
import com.huatek.busi.common.util.Tools;
import com.huatek.busi.dto.EquipmentInfoDto;
import com.huatek.busi.dto.curve.BaseCurveQueryDto;
import com.huatek.busi.dto.curve.PointItemDto;
import com.huatek.busi.dto.monitor.BusiOnlineMonitorDataDto;
import com.huatek.busi.entity.BusiEqmWarning;
import com.huatek.busi.entity.BusiOnlineMonitorData;
import com.huatek.busi.service.BusiEqmWarningService;
import com.huatek.busi.service.BusiStabilityService;
import com.huatek.busi.service.BusiSubTreeService;
import com.huatek.busi.service.PageUtility;
import com.huatek.busi.service.cac.CacEtlService;
import com.huatek.busi.service.curve.BaseCurveSensorService;
import com.huatek.busi.service.monitor.BaseMonitorDataTaskService;
import com.huatek.busi.service.monitor.BusiOnlineMonitorDataService;
import com.huatek.busi.vo.curve.PointItemVo;
import com.huatek.busi.vo.monitor.BusiOnlineMonitorDataVo;
import com.huatek.torch.sql.beans.Pojo;
import com.huatek.torch.sql.dao.impl.BaseDao;

/**
 * CAC数据保存接口抽象实现
 *
 * @author anker cheng
 * @Date 2019年7月2日
 */
public abstract class AbstractCacEtlService<T extends Pojo>
        implements CacEtlService<T>, BaseMonitorDataTaskService, BaseCurveSensorService, PageUtility {
    protected final Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    private BaseDao<T, String> baseDao;

    @Autowired
    private BusiSubTreeService busiSubTreeService;
    @Autowired
    private BusiEqmWarningService busiEqmWarningService;
    @Autowired
    protected BusiOnlineMonitorDataService busiOnlineMonitorDataService;
    @Autowired
    protected BusiStabilityService busiStabilityService;

    @Autowired
    private EquipmentTemperatureCacheDao equipmentTemperatureCacheDao;

    @Autowired
    EquipmentTemperatureCacheService equipmentTemperatureCacheService;

    @Autowired
    private GeneratorAmplThresholdService generatorAmplThresholdService;

    private Class<?> persistentClass;

    public AbstractCacEtlService() {
        this.persistentClass =
                (Class<?>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
    }

    @Override
    public Class<?> persistentClass() {
        return persistentClass;
    }

    // *****************************报文处理部分*******************************\\
    @Override
    public void saveCACData(T cacEntity) {
        String cacMonitorTypeCode = (String) FieldUtil.getFieldValue(cacEntity, "cacMonitorTypeCode");
        String sensorId = (String) FieldUtil.getFieldValue(cacEntity, "sensorId");
        CacDataType dataType = CacDataType.from(CacMonitorTypeCode.from(cacMonitorTypeCode).getDataType());
        EquipmentInfoDto equipmentInfo = getEquipmentInfo(sensorId, dataType);
        if (equipmentInfo == null) {
            logger.warn("未查到传感器配置信息，不保存数据，也不生成告警: {}", cacEntity);
            return;
        }
        // 设置站点ID、设备编码
        FieldUtil.setFieldValue(cacEntity, "siteId", equipmentInfo.getSiteId());
        FieldUtil.setFieldValue(cacEntity, "equipmentCode", equipmentInfo.getMainSysCode());
        FieldUtil.setFieldValue(cacEntity, "extEquipmentCode", equipmentInfo.getSubSysCode());
        FieldUtil.setFieldValue(cacEntity, "mainTreeId", equipmentInfo.getMainTreeId());
        FieldUtil.setFieldValue(cacEntity, "subTreeId", equipmentInfo.getSubTreeId());
        FieldUtil.setFieldValue(cacEntity, "mainEquipmentId", equipmentInfo.getMainEquipmentId());
        FieldUtil.setFieldValue(cacEntity, "subEquipmentId", equipmentInfo.getSubEquipmentId());
        // 20230424 工作状态默认赋值为  3：空闲
        FieldUtil.setFieldValue(cacEntity, "runState", "3");
        //equipmentInfo.setSensorName(equipmentInfo.getSensorPositionDes());
        // 保存历史数据
        saveHistoryData(cacEntity, equipmentInfo);
        // 判断是否告警，保存报警数据
        saveBusiWarning(cacEntity, cacMonitorTypeCode, sensorId, equipmentInfo);

        //保存所有
        EquipmentTemperatureCache equipmentTemperatureCache = new EquipmentTemperatureCache();
        BeanUtil.copyProperties(cacEntity,equipmentTemperatureCache);
        equipmentTemperatureCache.setType(equipmentInfo.getType());
        equipmentTemperatureCache.setSensorName(equipmentInfo.getSensorPositionDes());
        saveOrUpdate(equipmentTemperatureCache);

        // 保存或者更新实时数据
        updateCurrentData(cacEntity, equipmentInfo);
    }

    protected void saveOrUpdate(EquipmentTemperatureCache equipmentTemperatureCache){

        equipmentTemperatureCacheDao.saveOrUpdate(equipmentTemperatureCache);
    }


    /**
     * 保存历史数据
     *
     * @param cacEntity
     * @param equipmentInfo
     */
    protected void saveHistoryData(T cacEntity, EquipmentInfoDto equipmentInfo) {
        baseDao.add(cacEntity);
    }

    /**
     * 保存告警
     *
     * @param cacEntity
     * @param cacMonitorTypeCode
     * @param sensorId
     * @param equipmentInfo
     */
    protected void saveBusiWarning(T cacEntity, String cacMonitorTypeCode, String sensorId,
                                   EquipmentInfoDto equipmentInfo) {
    }


    /**
     * 保存告警
     *
     * @param cacEntity
     * @param cacMonitorTypeCode
     * @param sensorId
     * @param equipmentInfo
     */
    protected void savePdBusiWarning(T cacEntity, String cacMonitorTypeCode, String sensorId,
                                   EquipmentInfoDto equipmentInfo,String sensorCode) {
    }

    /**
     * 保存实时数据
     *
     * @param cacEntity
     */
    protected void updateCurrentData(T cacEntity, EquipmentInfoDto equipmentInfo) {
    }

    protected BusiEqmWarning buildWarning(BusiEqmWarning busiEqmWarning, EquipmentInfoDto equipmentInfo) {
        return busiEqmWarningService.saveBusiEqmWarning(equipmentInfo, busiEqmWarning.getEqType(), busiEqmWarning.getGzType(),
                busiEqmWarning.getWarningTypeCode(), busiEqmWarning.getWarningTime(), busiEqmWarning.getWarningMsg(), busiEqmWarning.getWarningFlag());
    }

    protected BusiEqmWarning buildCableWarning(BusiEqmWarning busiEqmWarning, EquipmentInfoDto equipmentInfo) {
        return busiEqmWarningService.saveBusiEqmCableWarning(equipmentInfo, busiEqmWarning.getEqType(), busiEqmWarning.getGzType(),
                busiEqmWarning.getWarningTypeCode(), busiEqmWarning.getWarningTime(), busiEqmWarning.getWarningMsg(), busiEqmWarning.getWarningFlag(),busiEqmWarning.getRunState());
    }

    protected int buildWarningInfo(BusiEqmWarning busiEqmWarning, String warningInfo) {
        return busiEqmWarningService.saveBusiEqmWarningInfo(busiEqmWarning, warningInfo);
    }

    protected BusiEqmWarning newEw(String eqType, String gzType, String warningMsg, String cacMonitorTypeCode, String warningFlag) {
        BusiEqmWarning busiEqmWarning = new BusiEqmWarning();
        busiEqmWarning.setEqType(eqType);
        busiEqmWarning.setGzType(gzType);
        busiEqmWarning.setWarningMsg(warningMsg);
        busiEqmWarning.setWarningTypeCode(cacMonitorTypeCode);
        busiEqmWarning.setWarningFlag(warningFlag);
        return busiEqmWarning;
    }

    @Override
    public Map<String, Object> findCACPageData(Map<String, Object> params) {
        throw new UnsupportedOperationException();
    }

    @Override
    public Map<String, Object> exportCacMonitorData(Map<String, Object> params) {
        throw new UnsupportedOperationException();
    }

    // *****************************在线监测监测数据部分***********************\\

    @Override
    public void doDailyMonitorDataStatistics(LocalDate day) {
        List<Map<String, Object>> monitorDataList =
                this.queryMonitorDataList(day.atStartOfDay(), day.plusDays(1).atStartOfDay());
        if (CollectionUtils.isEmpty(monitorDataList)) {
            return;
        }
        // 保存
        for (Map<String, Object> item : monitorDataList) {
            BusiOnlineMonitorData busiOnlineMonitorData =
                    busiOnlineMonitorDataService.generateBusiOnlineMonitorData(day, item);
            this.saveBusiOnlineMonitorData(busiOnlineMonitorData, item);
        }
    }

    protected List<Map<String, Object>> queryMonitorDataList(LocalDateTime startTime, LocalDateTime endTime) {
        return null;
    }

    protected void saveBusiOnlineMonitorData(BusiOnlineMonitorData busiOnlineMonitorData, Map<String, Object> item) {
        busiOnlineMonitorDataService.saveBusiOnlineMonitorData(busiOnlineMonitorData, JSONObject.toJSONString(item));
    }

    @Override
    @SuppressWarnings("unchecked")
    public PageInfo<BusiOnlineMonitorDataVo> findBusiOnlineMonitorDataPage(BusiOnlineMonitorDataDto param) {
        PageInfo<BusiOnlineMonitorDataVo> pageInfo =
                busiOnlineMonitorDataService.selectBusiOnlineMonitorDataPage(param);
        if (pageInfo == null || pageInfo.getList() == null) {
            return pageInfo;
        }
        pageInfo.getList().stream().forEach(e -> {

            e.setThresholdDataMap(thresholdDataMap(e));
            if (e.getStabilityIndex() != null && !"".equals(e.getStabilityIndex())) {
                Map<String, Object> oldMap = JSONObject.parseObject(e.getStabilityIndex(), Map.class);
                Map<String, Object> newMap = Maps.newLinkedHashMap();
                for (String key : oldMap.keySet()) {
                    newMap.put(key + "Stability", oldMap.get(key));
                }
                e.setStabilityIndexMap(newMap);
            } else {
                e.setStabilityIndexMap(Collections.emptyMap());
            }
            //设置精度指标
            if (StringUtils.isNotEmpty(e.getAccuracyIndex())) {
                Map<String, Object> mapAccuracy = JSONObject.parseObject(e.getAccuracyIndex(), Map.class);
                e.setAccuracyIndexMap(mapAccuracy);
            } else {
                e.setAccuracyIndexMap(Collections.emptyMap());
            }
            // 设置阈值显示
            if (e.getThresholdDataMap() == null) {
                e.setThresholdDataMap(Maps.newHashMapWithExpectedSize(0));
            }
            // 设置监测数据
            if (!StringUtils.isEmpty(e.getData())) {
                e.setMonitorDataMap(JSONObject.parseObject(e.getData(), Map.class));
            } else {
                e.setMonitorDataMap(Maps.newHashMapWithExpectedSize(0));
            }
            //其他值
            e.setOtherDataMap(otherDataMap(e));
        });
        return pageInfo;
    }

    /**
     * 导出在线监测数据
     */
    @Override
    @SuppressWarnings("unchecked")
    public List<BusiOnlineMonitorDataVo> exportBusiOnlineMonitorDataPage(BusiOnlineMonitorDataDto param) {
        List<BusiOnlineMonitorDataVo> resultList = busiOnlineMonitorDataService.selectBusiOnlineMonitorData(param);
        resultList.stream().forEach(e -> {
            e.setStabilityIndexMap(Maps.newHashMapWithExpectedSize(0));
            e.setThresholdDataMap(thresholdDataMap(e));
            // 设置阈值显示
            if (e.getThresholdDataMap() == null) {
                e.setThresholdDataMap(Maps.newHashMapWithExpectedSize(0));
            }
            // 设置监测数据
            if (!StringUtils.isEmpty(e.getData())) {
                e.setMonitorDataMap(JSONObject.parseObject(e.getData(), Map.class));
            } else {
                e.setMonitorDataMap(Maps.newHashMapWithExpectedSize(0));
            }
            //其他值
            e.setOtherDataMap(otherDataMap(e));
            //转换相位
            if (e.getEquipmentType().equals(SiteTreeEnum.OTHER_EQM.getValue()) && e.getSubEquipmentType().equals(OtherTreeEnum.DLHL_EQM.getValue())){
                e.setSensorposition(BusiConstant.CablePhase.getName(e.getSensorposition()));
            }else{
                e.setSensorposition(BusiConstant.Phase.getName(e.getSensorposition()));
            }
            //转换运行状态
            if (StringUtils.isNotEmpty(e.getRunState())) {
                e.setRunState(IecTypeEnum.getName(e.getRunState()));
            }
            //转换主设备类型
            if (e.getEquipmentType().equals(SiteTreeEnum.BYQ_EQM.getValue())) {
                e.setEquipmentType(SiteTreeEnum.BYQ_EQM.getName());
                e.setSubEquipmentType(TransfromerTreeEnum.getName(e.getSubEquipmentType()));
            }
            if (e.getEquipmentType().equals(SiteTreeEnum.GIS_HL_EQM.getValue())) {
                e.setEquipmentType(SiteTreeEnum.GIS_HL_EQM.getName());
                e.setSubEquipmentType(GisTreeEnum.getName(e.getSubEquipmentType()));
            }
            if (e.getEquipmentType().equals(SiteTreeEnum.CW_HL_EQM.getValue())) {
                e.setEquipmentType(SiteTreeEnum.CW_HL_EQM.getName());
            }
            if (e.getEquipmentType().equals(SiteTreeEnum.BLQ_HL_EQM.getValue())) {
                e.setEquipmentType(SiteTreeEnum.BLQ_HL_EQM.getName());
                e.setSubEquipmentType(ArresterTreeEnum.getName(e.getSubEquipmentType()));
            }
            if (e.getEquipmentType().equals(SiteTreeEnum.DL_EQM.getValue())) {
                e.setEquipmentType(SiteTreeEnum.DL_EQM.getName());
                e.setSubEquipmentType(SiteConstants.CableTreeEnum.getName(e.getSubEquipmentType()));
            }
            if (e.getEquipmentType().equals(SiteTreeEnum.OTHER_EQM.getValue())) {
                e.setEquipmentType(SiteTreeEnum.OTHER_EQM.getName());
                e.setSubEquipmentType(OtherTreeEnum.getName(e.getSubEquipmentType()));
            }
        });
//          Map<String, Object> resultMap = Maps.newLinkedHashMap();
//          resultMap.put("data", resultList);
        return resultList;
    }

    /**
     * 阈值查询方法
     *
     * @param vo
     * @return
     */
    protected Map<String, Object> thresholdDataMap(BusiOnlineMonitorDataVo vo) {
        return Collections.emptyMap();
    }

    protected Map<String, Object> otherDataMap(BusiOnlineMonitorDataVo vo) {
        return Collections.emptyMap();
    }

    // *****************************趋势图部分********************************\\
    @Override
    public List<BaseCurveQueryDto> findSensorCodeList(LocalDate day) {
        return null;
    }

    @Override
    public List<PointItemVo> findDaylyPointList(BaseCurveQueryDto baseCurve, LocalDate day, String subType) {
        return null;
    }

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

    // *****************************工具类辅助方法*****************************\\
    protected void append(final StringBuilder warningMsg, String msg) {
        Tools.append(warningMsg, msg);
    }

    private EquipmentInfoDto getEquipmentInfo(String sensorId, CacDataType dataType) {
        EquipmentInfoDto equipmentInfoDto = null;
        switch (dataType) {
            case BLQ:
                equipmentInfoDto = busiSubTreeService.findEquipmentInfo(sensorId, SiteTreeEnum.BLQ.getValue());
                break;
            case BYQ:
                equipmentInfoDto = busiSubTreeService.findEquipmentInfo(sensorId, SiteTreeEnum.BYQ.getValue());
                break;
            case CAP:
                // 变压器容性、避雷器容性
                equipmentInfoDto = busiSubTreeService.findEquipmentInfo(sensorId, SiteTreeEnum.BYQ.getValue());
                if (equipmentInfoDto != null) {
                    break;
                }
                equipmentInfoDto = busiSubTreeService.findEquipmentInfo(sensorId, SiteTreeEnum.BLQ.getValue());
                break;
            case CW:
                equipmentInfoDto = busiSubTreeService.findEquipmentInfo(sensorId, SiteTreeEnum.CW.getValue());
                break;
            case GIS:
                equipmentInfoDto = busiSubTreeService.findEquipmentInfo(sensorId, SiteTreeEnum.GIS.getValue());
                break;
            case QT:
                equipmentInfoDto = busiSubTreeService.findEquipmentInfo(sensorId, SiteTreeEnum.OTHER.getValue());
                break;
            case DL:
                equipmentInfoDto = busiSubTreeService.findEquipmentInfo(sensorId, SiteTreeEnum.DL.getValue());
                break;
            default:
                break;
        }
        return equipmentInfoDto;
    }

    /**
     * 字符串格式化</br>
     * 区别于String.format
     *
     * @param format   格式化PATTERN使用{}作为占位符
     * @param argArray 参数数组
     * @return 格式化后的字符串
     */
    protected String format(String format, Object... argArray) {
        FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray);
        return ft.getMessage();
    }

    protected String popString(Map<String, Object> map, String key) {
        if (map == null) {
            return null;
        }
        return (String) map.remove(key);
    }

    protected String getString(Map<String, Object> map, String key) {
        return (String) map.remove(key);
    }

    protected String getString(Map<String, Object> map, String key, String defaultVal) {
        if (map == null) {
            return null;
        }
        String val = (String) map.get(key);
        if (StringUtils.isEmpty(val)) {
            return defaultVal;
        }
        return val;
    }
}
