package com.njcn.gather.monitor.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.njcn.common.pojo.exception.BusinessException;
import com.njcn.gather.detection.util.socket.CnSocketUtil;
import com.njcn.gather.device.pojo.enums.CheckResultEnum;
import com.njcn.gather.device.pojo.enums.CheckStateEnum;
import com.njcn.gather.monitor.mapper.PqMonitorMapper;
import com.njcn.gather.monitor.pojo.param.PqMonitorParam;
import com.njcn.gather.monitor.pojo.po.PqMonitor;
import com.njcn.gather.monitor.service.IPqMonitorService;
import com.njcn.gather.plan.pojo.enums.DataSourceEnum;
import com.njcn.gather.pojo.enums.DetectionResponseEnum;
import com.njcn.gather.storage.service.DetectionDataDealService;
import com.njcn.gather.storage.service.impl.DetectionDataServiceImpl;
import com.njcn.gather.system.dictionary.pojo.po.DictData;
import com.njcn.gather.system.dictionary.service.IDictDataService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * @author caozehui
 * @date 2024-12-12
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class PqMonitorServiceImpl extends ServiceImpl<PqMonitorMapper, PqMonitor> implements IPqMonitorService {

    private final IDictDataService dictDataService;
    private final DetectionDataDealService detectionDataDealService;

    @Override
    public List<PqMonitor> listPqMonitorByDevIds(List<String> devIds) {
        if (CollUtil.isNotEmpty(devIds)) {
            return this.baseMapper.listByDevIds(devIds);
        }
        return CollUtil.empty(PqMonitor.class);
    }

    @Override
    public boolean addPqMonitorByDevId(String devId, List<PqMonitorParam> monitorList) {
        List<PqMonitor> pqMonitorList = BeanUtil.copyToList(monitorList, PqMonitor.class);
        pqMonitorList.forEach(pqMonitor -> pqMonitor.setDevId(devId));
        return this.saveBatch(pqMonitorList);
    }

    @Override
    @Transactional
    public boolean updatePqMonitorByDevId(String devId, List<PqMonitorParam> paramList) {
        // 先删除原有数据
        this.deletePqMonitorByDevId(devId);
        // 再添加新数据
        List<PqMonitor> pqMonitorList = BeanUtil.copyToList(paramList, PqMonitor.class);
        pqMonitorList.forEach(pqMonitor -> pqMonitor.setDevId(devId));
        return this.saveBatch(pqMonitorList);
    }

    @Override
    @Transactional
    public boolean deletePqMonitorByDevId(String devId) {
        QueryWrapper<PqMonitor> wrapper = new QueryWrapper<>();
        wrapper.eq("pq_monitor.Dev_Id", devId);
        return this.remove(wrapper);
    }

    @Override
    public void visualizeMonitor(List<PqMonitor> monitorList) {
        monitorList.forEach(monitor -> {
            DictData dictData = dictDataService.getDictDataById(monitor.getConnection());
            if (ObjectUtil.isNotNull(dictData)) {
                monitor.setConnection(dictData.getName());
            } else {
                throw new BusinessException(DetectionResponseEnum.CONNECTION_NOT_EXIST);
            }
        });
    }

    @Override
    public void reverseVisualizeMonitor(List<PqMonitor> monitorList) {
        monitorList.forEach(monitor -> {
            DictData dictData = dictDataService.getDictDataByName(monitor.getConnection());
            if (ObjectUtil.isNotNull(dictData)) {
                monitor.setConnection(dictData.getId());
            } else {
                throw new BusinessException(DetectionResponseEnum.CONNECTION_NOT_EXIST);
            }
        });
    }

    @Override
    public PqMonitor getByDevMonitorId(String devMonitorId) {
        String[] split = devMonitorId.split("_");
        return this.baseMapper.getByDevIdAndNum(split[0], Integer.valueOf(split[1]));
    }

    @Override
    public Double getRatedCurrent(String devMonitorId) {
        PqMonitor pqMonitor = this.getByDevMonitorId(devMonitorId);
        if (ObjectUtil.isNotNull(pqMonitor)) {
            String ct = pqMonitor.getCt();
            if (StrUtil.isNotBlank(ct) && ct.contains(StrUtil.COLON)) {
                String[] ctArray = ct.split(StrUtil.COLON);
                return Double.parseDouble(ctArray[1]);
            }
        }
        throw new BusinessException(DetectionResponseEnum.RATED_CT_ERROR);
    }

    @Override
    public Double getRatedVoltage(String devMonitorId) {
        PqMonitor pqMonitor = this.getByDevMonitorId(devMonitorId);
        if (ObjectUtil.isNotNull(pqMonitor)) {
            String pt = pqMonitor.getPt();
            if (StrUtil.isNotBlank(pt) && pt.contains(StrUtil.COLON)) {
                String[] ptArray = pt.split(StrUtil.COLON);
                return Double.parseDouble(ptArray[1]);
            }
        }
        throw new BusinessException(DetectionResponseEnum.RATED_PT_ERROR);
    }

    @Override
    @Transactional
    public boolean updateMonitorResult(String monitorId, List<String> adTypes, DataSourceEnum dataSourceEnum, Integer num, Integer waveNum, String code) {
        String[] split = monitorId.split(CnSocketUtil.SPLIT_TAG);
        QueryWrapper<PqMonitor> wrapper = new QueryWrapper<>();
        wrapper.eq("pq_monitor.Dev_Id", split[0])
                .eq("pq_monitor.Num", split[1])
                .last("LIMIT 1");
        PqMonitor monitor = this.getOne(wrapper);
        String resultType = monitor.getResultType();
        Integer qualifiedNum = monitor.getQualifiedNum();

        Integer newMonitorResult = CheckResultEnum.UNCHECKED.getValue();
        AtomicReference<Integer> newWaveNum = new AtomicReference<>(-1);
        switch (dataSourceEnum) {
            case WAVE_DATA:
                Map<Integer, Integer> waveNumResultMap = detectionDataDealService.getWaveNumResultMap(monitorId, adTypes, num, code);
                if (CollUtil.isEmpty(waveNumResultMap)) {
                    return true;
                }
                waveNumResultMap.forEach((key, value) -> {
                    if (CheckResultEnum.ACCORD.getValue().equals(value)) {
                        newWaveNum.set(key);
                    }
                });
                if (!newWaveNum.get().equals(-1)) {
                    newMonitorResult = CheckResultEnum.ACCORD.getValue();
                } else {
                    newWaveNum.set(waveNum);
                    newMonitorResult = waveNumResultMap.get(waveNum);
                    if (newMonitorResult == 2) {
                        newMonitorResult = CheckResultEnum.NOT_ACCORD.getValue();
                    }
                }
                break;
            default:
                newMonitorResult = detectionDataDealService.getMonitorResult(monitorId, adTypes, dataSourceEnum.getValue(), num, null, code);
                if (newMonitorResult == 2) {
                    newMonitorResult = CheckResultEnum.NOT_ACCORD.getValue();
                }
                if (newMonitorResult == 1) {
                    newMonitorResult = CheckResultEnum.ACCORD.getValue();
                }
                break;
        }

        boolean updateFlag = false;
        if (StrUtil.isBlank(resultType)) {
            updateFlag = true;
            if (newMonitorResult.equals(CheckResultEnum.ACCORD.getValue())) {
                qualifiedNum += 1;
            }
        } else {
            Integer oldMonitorResult = null;
            if (DataSourceEnum.REAL_DATA.getValue().equals(resultType)) {
                oldMonitorResult = monitor.getRealtimeResult();
            } else if (DataSourceEnum.WAVE_DATA.getValue().equals(resultType)) {
                oldMonitorResult = monitor.getRecordedResult();
            } else {
                oldMonitorResult = monitor.getStatisticsResult();
            }

            if (CheckResultEnum.ACCORD.getValue().equals(oldMonitorResult)) {
                if (CheckResultEnum.ACCORD.getValue().equals(newMonitorResult)) {
                    qualifiedNum += 1;
                    updateFlag = true;
                }
            } else {
                updateFlag = true;
                if (CheckResultEnum.ACCORD.getValue().equals(newMonitorResult)) {
                    qualifiedNum += 1;
                }
            }
        }

        if (updateFlag) {
            monitor.setResultType(dataSourceEnum.getValue());

            switch (dataSourceEnum) {
                case REAL_DATA:
                    monitor.setRealtimeNum(String.valueOf(num));
                    monitor.setRealtimeResult(newMonitorResult);
                    monitor.setRecordedNum(null);
                    monitor.setRecordedResult(null);
                    monitor.setStatisticsNum(null);
                    monitor.setStatisticsResult(null);
                    break;
                case WAVE_DATA:
                    monitor.setRealtimeNum(null);
                    monitor.setRealtimeResult(null);
                    monitor.setRecordedNum(num + CnSocketUtil.SPLIT_TAG + newWaveNum.get());
                    monitor.setRecordedResult(newMonitorResult);
                    monitor.setStatisticsNum(null);
                    monitor.setStatisticsResult(null);
                    break;
                default:
                    monitor.setRealtimeResult(null);
                    monitor.setRealtimeNum(null);
                    monitor.setRecordedResult(null);
                    monitor.setRecordedNum(null);
                    monitor.setStatisticsNum(String.valueOf(num));
                    monitor.setStatisticsResult(newMonitorResult);
                    break;
            }
            monitor.setQualifiedNum(qualifiedNum);
            return this.updateById(monitor);
        } else {
            return true;
        }
    }


    @Override
    public Integer getDevCheckState(String devId) {
        QueryWrapper<PqMonitor> wrapper = new QueryWrapper<>();
        wrapper.eq("pq_monitor.Dev_Id", devId)
                .eq("pq_monitor.Check_Flag", 1);
        List<PqMonitor> monitorList = this.list(wrapper);
        if (CollUtil.isNotEmpty(monitorList)) {
            List<Integer> allNumList = monitorList.stream().map(PqMonitor::getNum).collect(Collectors.toList());
            List<Integer> checkedNumList = monitorList.stream().filter(obj -> ObjectUtil.isNotNull(obj.getResultType())).map(PqMonitor::getNum).collect(Collectors.toList());

            if (checkedNumList.containsAll(allNumList)) {
                return CheckStateEnum.CHECKED.getValue();
            } else {
                if (checkedNumList.size() > 0) {
                    return CheckStateEnum.CHECKING.getValue();
                }
            }
        }
        return CheckStateEnum.UNCHECKED.getValue();
    }

    @Override
    public Integer getDevCheckResult(String devId) {
        QueryWrapper<PqMonitor> wrapper = new QueryWrapper<>();
        wrapper.eq("pq_monitor.Dev_Id", devId)
                .eq("pq_monitor.Check_Flag", 1);
        List<PqMonitor> monitorList = this.list(wrapper);

        List<Integer> allResultFlags = new ArrayList<>();
        for (PqMonitor monitor : monitorList) {
            String resultType = monitor.getResultType();
            if (StrUtil.isNotBlank(resultType)) {
                if (DataSourceEnum.REAL_DATA.getValue().equals(resultType)) {
                    //allResultFlags.add(monitor.getRealtimeResult());
                    if (monitor.getRealtimeResult() == 0) {
                        allResultFlags.add(2);
                    }
                    if (monitor.getRealtimeResult() == 1) {
                        allResultFlags.add(1);
                    }
                    if(monitor.getRealtimeResult() == 4){
                        allResultFlags.add(4);
                    }
                } else if (DataSourceEnum.WAVE_DATA.getValue().equals(resultType)) {
                    //allResultFlags.add(monitor.getRecordedResult());
                    if (monitor.getRecordedResult() == 0) {
                        allResultFlags.add(2);
                    }
                    if (monitor.getRecordedResult() == 1) {
                        allResultFlags.add(1);
                    }
                    if(monitor.getRecordedResult() == 4){
                        allResultFlags.add(4);
                    }
                } else {
                    //allResultFlags.add(monitor.getStatisticsResult());
                    if (monitor.getStatisticsResult() == 0) {
                        allResultFlags.add(2);
                    }
                    if (monitor.getStatisticsResult() == 1) {
                        allResultFlags.add(1);
                    }
                    if(monitor.getStatisticsResult() == 4){
                        allResultFlags.add(4);
                    }
                }
            }
        }

        return DetectionDataServiceImpl.isResultFlag(allResultFlags);
    }

    @Override
    public boolean removeByDevId(String devId) {
        QueryWrapper<PqMonitor> wrapper = new QueryWrapper<>();
        wrapper.eq("pq_monitor.Dev_Id", devId);
        return this.remove(wrapper);
    }
}
