package com.njcn.csdevice.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.njcn.access.api.CsLineLatestDataFeignClient;
import com.njcn.access.pojo.po.CsLineLatestData;
import com.njcn.common.pojo.enums.common.DataStateEnum;
import com.njcn.common.pojo.exception.BusinessException;
import com.njcn.common.utils.PubUtils;
import com.njcn.csdevice.mapper.*;
import com.njcn.csdevice.pojo.param.CsLineParam;
import com.njcn.csdevice.pojo.po.*;
import com.njcn.csdevice.pojo.vo.LineDetailDataVO;
import com.njcn.csdevice.pojo.vo.PqSensitiveUserLineVO;
import com.njcn.csdevice.service.CsDevModelService;
import com.njcn.csdevice.service.CsLinePOService;
import com.njcn.csdevice.service.ICsDataSetService;
import com.njcn.csharmonic.api.PqSensitiveUserFeignClient;
import com.njcn.csharmonic.pojo.po.PqSensitiveUser;
import com.njcn.oss.constant.OssPath;
import com.njcn.oss.utils.FileStorageUtil;
import com.njcn.system.api.DicDataFeignClient;
import com.njcn.system.enums.DicDataEnum;
import com.njcn.system.pojo.po.DictData;
import com.njcn.user.api.UserFeignClient;
import com.njcn.user.pojo.constant.UserType;
import com.njcn.user.pojo.vo.UserVO;
import com.njcn.web.pojo.param.BaseParam;
import com.njcn.web.utils.RequestUtil;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 *
 * Description:
 * Date: 2023/5/18  14:01【需求编号】
 *
 * @author clam
 * @version V1.0.0
 */
@Service
@RequiredArgsConstructor
public class CsLinePOServiceImpl extends ServiceImpl<CsLinePOMapper, CsLinePO> implements CsLinePOService{

    private final CsLedgerMapper csLedgerMapper;
    private final CsDevModelService csDevModelService;
    private final ICsDataSetService csDataSetService;
    private final DicDataFeignClient dicDataFeignClient;
    private final CsTerminalLogsMapper csTerminalLogsMapper;
    private final CsLineLatestDataFeignClient csLineLatestDataFeignClient;
    private final PqSensitiveUserFeignClient pqSensitiveUserFeignClient;

    private final FileStorageUtil fileStorageUtil;
    private final UserFeignClient userFeignClient;
    private final CsEquipmentDeliveryMapper csEquipmentDeliveryMapper;
    private final CsDeviceUserPOMapper csDeviceUserPOMapper;



    @Override
    public List<CsLinePO> getLineByDev(List<String> list) {
        List<CsLinePO> result = new ArrayList<>();
        list.forEach(temp->{
            List<CsLinePO> csLinePOList = queryByDevId(temp);
            result.addAll(csLinePOList);
        });
    return result;
    }

    @Override
    public List<CsLinePO> queryByDevId(String devId) {
        QueryWrapper<CsLedger> queryWrapper = new QueryWrapper();
        queryWrapper.eq("state",1).eq("pid",devId);
        List<CsLedger> csLedgerList = csLedgerMapper.selectList(queryWrapper);
        List<String> csPairList = csLedgerList.stream().map(CsLedger::getId).collect(Collectors.toList());
        if(CollectionUtil.isEmpty(csPairList)){
            return new ArrayList<>();
        }
        List<CsLinePO> csLinePOS = this.lambdaQuery().in(CsLinePO::getLineId,csPairList).eq(CsLinePO::getStatus,1).list();
        csLinePOS.forEach(temp->temp.setDevId(devId));
        return csLinePOS;
    }

    @Override
    public List<CsLinePO> findByNdid(String id) {
        return this.baseMapper.findByNdid(id);
    }

    public Map<String,String> getCustomDetailByLineId(String lineId){
        return this.baseMapper.getCustomDetailByLineId(lineId);
    }

    @Override
    public void updateLine(CsLineParam csLineParam) {
        LambdaUpdateWrapper<CsLinePO> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        lambdaUpdateWrapper.eq(CsLinePO::getLineId,csLineParam.getLineId())
                            .eq(CsLinePO::getStatus,1)
                            .set(CsLinePO::getVolGrade,csLineParam.getVolGrade())
                            .set(CsLinePO::getPtRatio,csLineParam.getPtRatio())
                            .set(CsLinePO::getCtRatio,csLineParam.getCtRatio())
                            .set(CsLinePO::getConType,csLineParam.getConType())
                            .set(CsLinePO::getLineInterval,csLineParam.getLineInterval());
        this.update(lambdaUpdateWrapper);
    }

    @Override
    public void updateIds(CsLineParam csLineParam) {
        LambdaUpdateWrapper<CsLinePO> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        lambdaUpdateWrapper.eq(CsLinePO::getLineId,csLineParam.getLineId())
                .eq(CsLinePO::getStatus,1)
                .set(CsLinePO::getDataSetId,csLineParam.getDataSetId())
                .set(CsLinePO::getDataModelId,csLineParam.getModelId());
        this.update(lambdaUpdateWrapper);
    }

    @Override
    public List<CsLinePO> getLinesByDevList(List<String> list) {
        return this.lambdaQuery().in(CsLinePO::getDeviceId,list).eq(CsLinePO::getStatus,1).list();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public CsLinePO addCldLine(CsLineParam param) {
        String lineId = param.getDevMac().replace(":","") + param.getLineNo();
        CsLinePO po = new CsLinePO();
        //1.新增监测点信息
        BeanUtils.copyProperties(param,po);
        po.setStatus(1);
        po.setRunStatus(2);
        po.setLineId(param.getDevMac().replace(":","") + param.getLineNo());
        //模板id
        CsDevModelPO po1 = csDevModelService.getCldModel();
        po.setDataModelId(po1.getId());
        //设备id
        po.setDeviceId(param.getDevId());
        //数据集id
        List<CsDataSet> list = csDataSetService.findDataSetByModelId(po1.getId());
        if (CollectionUtil.isNotEmpty(list)) {
            po.setDataSetId(list.get(0).getId());
            po.setClDid(list.get(0).getClDev());
        }
        //监测位置
        DictData data = dicDataFeignClient.getDicDataByCode(DicDataEnum.GRID_SIDE.getCode()).getData();
        po.setPosition(data.getId());
        this.save(po);

        //2.新增台账树信息
        CsLedger csLedger = new CsLedger();
        csLedger.setId(lineId);
        csLedger.setPid(param.getDevId());
        csLedger.setPids("0," + param.getEngineeringId() + "," + param.getProjectId() + "," + param.getDevId());
        csLedger.setName(param.getName());
        csLedger.setLevel(3);
        csLedger.setState(1);
        csLedger.setSort(0);
        csLedgerMapper.insert(csLedger);
        return po;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateCldLine(CsLineParam param) {
        LambdaQueryWrapper<CsLinePO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(CsLinePO::getDeviceId,param.getDevId())
                .ne(CsLinePO::getLineId,param.getLineId())
                .eq(CsLinePO::getLineNo,param.getLineNo())
                .eq(CsLinePO::getStatus,1);
        List<CsLinePO> lineList = this.list(wrapper);
        if (CollectionUtil.isNotEmpty(lineList)) {
            throw new BusinessException("监测点线路号重复,请调整!");
        }
        LambdaUpdateWrapper<CsLinePO> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        lambdaUpdateWrapper.eq(CsLinePO::getLineId,param.getLineId())
                .eq(CsLinePO::getStatus,1)
                .set(CsLinePO::getName,param.getName())
                .set(CsLinePO::getLineNo,param.getLineNo())
                .set(CsLinePO::getConType,param.getConType())
                .set(CsLinePO::getLineInterval,param.getLineInterval())
                .set(CsLinePO::getPtRatio,param.getPtRatio())
                .set(CsLinePO::getPt2Ratio,param.getPt2Ratio())
                .set(CsLinePO::getCtRatio,param.getCtRatio())
                .set(CsLinePO::getCt2Ratio,param.getCt2Ratio())
                .set(CsLinePO::getVolGrade,param.getVolGrade())
                .set(CsLinePO::getRunStatus,param.getRunStatus())
                .set(CsLinePO::getBasicCapacity,param.getBasicCapacity())
                .set(CsLinePO::getDevCapacity,param.getDevCapacity())
                .set(CsLinePO::getProtocolCapacity,param.getProtocolCapacity())
                .set(CsLinePO::getShortCircuitCapacity,param.getShortCircuitCapacity())
                .set(CsLinePO::getMonitorObj,param.getMonitorObj())
                .set(CsLinePO::getMonitorObj,param.getMonitorObj())
                .set(CsLinePO::getGovern,param.getGovern())
                .set(CsLinePO::getMonitorUser,param.getMonitorUser());
        this.update(lambdaUpdateWrapper);

        //修改台账树中监测点的名称
        QueryWrapper<CsLedger> queryWrapper = new QueryWrapper();
        queryWrapper.eq("state",1).eq("id",param.getLineId());
        CsLedger csLedger = csLedgerMapper.selectOne(queryWrapper);
        csLedger.setName(param.getName());
        csLedgerMapper.updateById(csLedger);

        //新增台账日志
        CsTerminalLogs csTerminalLogs = new CsTerminalLogs();
        csTerminalLogs.setDeviceId(param.getDevId());
        csTerminalLogs.setOperateType(1);
        csTerminalLogs.setIsPush(0);
        csTerminalLogsMapper.insert(csTerminalLogs);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteCldLine(String id) {
        CsLinePO po = this.getById(id);

        this.removeById(id);
        csLedgerMapper.deleteById(id);

        //新增台账日志
        CsTerminalLogs csTerminalLogs = new CsTerminalLogs();
        csTerminalLogs.setDeviceId(po.getDeviceId());
        csTerminalLogs.setOperateType(1);
        csTerminalLogs.setIsPush(0);
        csTerminalLogsMapper.insert(csTerminalLogs);
    }

    @Override
    public void updateCldLineStatus(List<CsLinePO> lineList, Integer status) {
        lineList.forEach(item->{item.setRunStatus(status);});
        this.updateBatchById(lineList);
    }

    @Override
    public void updateLineDataByList(List<String> list, String id, String setId) {
        LambdaUpdateWrapper<CsLinePO> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.in(CsLinePO::getDeviceId,list).set(CsLinePO::getDataModelId,id).set(CsLinePO::getDataSetId,setId);
        this.update(updateWrapper);
    }

    @Override
    public  List<CsLinePO> getLineByName(String lineName) {
        return this.lambdaQuery().eq(CsLinePO::getStatus, 1).like(CsLinePO::getName,lineName).list();
    }

    @Override
    public List<String> getAllLine() {
        return this.lambdaQuery()
                .eq(CsLinePO::getStatus, 1)
                .list()
                .stream()
                .map(CsLinePO::getLineId)
                .collect(Collectors.toList());
    }

    @Override
    public List<CsLinePO> getSimpleLine() {
        List<String> devIds = commGetDevIds(RequestUtil.getUserIndex());
        if(CollUtil.isNotEmpty(devIds)){
            List<CsLinePO> poList = this.lambdaQuery().select(CsLinePO::getLineId,CsLinePO::getName).in(CsLinePO::getDeviceId,devIds)
                    .eq(CsLinePO::getStatus, DataStateEnum.ENABLE.getCode()).list();
            return poList;
        }else {
            return Collections.emptyList();
        }
    }

    private List<String> commGetDevIds(String userId){
        UserVO userVO = userFeignClient.getUserById(userId).getData();
        List<String> devIds;
        if(userVO.getType().equals(UserType.SUPER_ADMINISTRATOR ) || userVO.getType().equals(UserType.ADMINISTRATOR )){
            devIds = csEquipmentDeliveryMapper.selectList(new LambdaQueryWrapper<CsEquipmentDeliveryPO>().eq(CsEquipmentDeliveryPO::getStatus,DataStateEnum.ENABLE)).stream().map(CsEquipmentDeliveryPO::getId).collect(Collectors.toList());
        }else {
            LambdaQueryWrapper<CsDeviceUserPO> lambdaQueryWrapper = new LambdaQueryWrapper<>();
            lambdaQueryWrapper.select(CsDeviceUserPO::getDeviceId)
                    .and(w->w.eq(CsDeviceUserPO::getPrimaryUserId,userId).or().eq(CsDeviceUserPO::getSubUserId,userId))
                    .eq(CsDeviceUserPO::getStatus, DataStateEnum.ENABLE.getCode());
            List<CsDeviceUserPO> devList = this.csDeviceUserPOMapper.selectList(lambdaQueryWrapper);
            devIds = devList.stream().map(CsDeviceUserPO::getDeviceId).distinct().collect(Collectors.toList());
        }
        return devIds;
    }

    @Override
    public List<CsLinePO> getLineBySensitiveUser(List<String> list) {
        return this.lambdaQuery()
                .in(CsLinePO::getMonitorUser,list)
                .eq(CsLinePO::getStatus, 1)
                .list();
    }

    @Override
    public Page<PqSensitiveUserLineVO> getSensitiveUserLineList(BaseParam param) {
        Page<PqSensitiveUserLineVO> result = new Page<>();
        result.setCurrent(param.getPageNum());
        result.setSize(param.getPageSize());


        Page<CsLinePO> linePage = this.page(new Page<>(param.getPageNum(), param.getPageSize()),
                new LambdaQueryWrapper<CsLinePO>()
                        .eq(CsLinePO::getStatus, 1)
                        // 关联敏感用户
                        .isNotNull(CsLinePO::getMonitorUser)
                        .orderByAsc(CsLinePO::getMonitorUser)
        );
        BeanUtil.copyProperties(linePage, result);
        List<CsLinePO> records = linePage.getRecords();
        if (CollUtil.isEmpty(records)) {
            return result;
        }
        List<PqSensitiveUserLineVO> list = new ArrayList<>();
        List<String> sensitiveUserIds = list.stream().map(PqSensitiveUserLineVO::getSensitiveUser).distinct().collect(Collectors.toList());

        Map<String, String> sensitiveUserNameMap = pqSensitiveUserFeignClient.getListByIds(sensitiveUserIds).getData()
                .stream().collect(Collectors.toMap(PqSensitiveUser::getId, PqSensitiveUser::getName));
        PqSensitiveUserLineVO sensitiveUserLineVO;
        for (CsLinePO record : records) {
            sensitiveUserLineVO = new PqSensitiveUserLineVO();
            // 治理对象
            sensitiveUserLineVO.setSensitiveUser(sensitiveUserNameMap.getOrDefault(record.getMonitorUser(), null));
            // 测点名称
            sensitiveUserLineVO.setLineId(record.getLineId());
            sensitiveUserLineVO.setLineName(record.getName());
            // 是否治理
            if (ObjectUtil.isNotEmpty(record.getGovern())) {
                if (record.getGovern().equals(0)) {
                    sensitiveUserLineVO.setGovern("未治理");
                }
                if (record.getGovern().equals(1)) {
                    sensitiveUserLineVO.setGovern("已治理");
                }
            }
            // 监测类型
            sensitiveUserLineVO.setPosition(record.getPosition());
            DictData positionDictData = dicDataFeignClient.getDicDataById(record.getPosition()).getData();
            if (positionDictData != null) {
                sensitiveUserLineVO.setPosition(positionDictData.getName());
            }
            // 电压等级
            sensitiveUserLineVO.setVolGrade(record.getVolGrade());
            // 运行状态
            sensitiveUserLineVO.setRunStatus(getRunStatusDescription(record.getRunStatus()));
            // 报告文件
            sensitiveUserLineVO.setReportFilePath(record.getReportFilePath());
            // 最新数据时间
            List<CsLineLatestData> lineLatestDataList = csLineLatestDataFeignClient.listData().getData();
            if (CollUtil.isNotEmpty(lineLatestDataList)) {
                sensitiveUserLineVO.setLatestTime(lineLatestDataList.stream()
                        .filter(item -> item.getLineId().equals(record.getLineId()))
                        .map(CsLineLatestData::getTimeId)
                        .max(LocalDateTime::compareTo)
                        .orElse(null));
            }
            list.add(sensitiveUserLineVO);
        }
        result.setRecords(list);
        return result;
    }

    @Override
    public boolean uploadReport(MultipartFile file, String lineId) {
       String filePath =  fileStorageUtil.uploadMultipart(file, OssPath.GOVERN_HARMONIC_FILE);
       return this.update(new LambdaUpdateWrapper<CsLinePO>().eq(CsLinePO::getLineId, lineId).set(CsLinePO::getReportFilePath, filePath));
    }

    @Override
    public String getReportUrl(String lineId) {
        CsLinePO linePO = this.getById(lineId);
        if (linePO != null) {
            String reportFilePath = linePO.getReportFilePath();
            if (StrUtil.isNotBlank(reportFilePath)) {
               return fileStorageUtil.getFileUrl(reportFilePath);
            }
        }
        return "";
    }


    @Override
    public LineDetailDataVO getLineDetailData(String id) {
        if (StringUtils.isEmpty(id)) {
            return new LineDetailDataVO();
        } else {
            CsLinePO csLinePO = this.baseMapper.selectOne(new LambdaQueryWrapper<CsLinePO>().eq(CsLinePO::getLineId,id));
            LineDetailDataVO lineDetailDataVO = new LineDetailDataVO();

            //lineDetailDataVO.setScale(dicDataFeignClient.getDicDataById(voltageMapper.selectById(voId).getScale()).getData().getName());
            //Device device = deviceMapper.selectById(devId);
            //lineDetailDataVO.setComFlag(PubUtils.comFlag(device.getComFlag()));
            //lineDetailDataVO.setRunFlag(PubUtils.lineRunFlag(lineDetail.getRunFlag()));
            //lineDetailDataVO.setIp(device.getIp());
            //lineDetailDataVO.setLoginTime(device.getLoginTime());
            //lineDetailDataVO.setDevId(device.getId());
            //lineDetailDataVO.setBusinessType(dicDataFeignClient.getDicDataById(lineDetail.getBusinessType()).getData().getName());
            //lineDetailDataVO.setLoadType(dicDataFeignClient.getDicDataById(lineDetail.getLoadType()).getData().getName());
            lineDetailDataVO.setObjName(csLinePO.getMonitorUser());
            lineDetailDataVO.setLineId(csLinePO.getLineId());
            lineDetailDataVO.setPtType(PubUtils.ptType(csLinePO.getConType()));
            //lineDetailDataVO.setPt(lineDetail.getPt1() + "/" + lineDetail.getPt2());
            //lineDetailDataVO.setCt(lineDetail.getCt1() + "/" + lineDetail.getCt2());
            lineDetailDataVO.setDealCapacity(csLinePO.getProtocolCapacity().floatValue());
            lineDetailDataVO.setDevCapacity(csLinePO.getDevCapacity().floatValue());
            lineDetailDataVO.setShortCapacity(csLinePO.getShortCircuitCapacity().floatValue());
            lineDetailDataVO.setStandardCapacity(csLinePO.getBasicCapacity().floatValue());
            lineDetailDataVO.setTimeInterval(csLinePO.getLineInterval());

            return lineDetailDataVO;
        }

    }


    private String getRunStatusDescription(Integer runStatus) {
        // 0：运行；1：检修；2：停运；3：调试；4：退运
        switch (runStatus) {
            case 0:
                return "运行";
            case 1:
                return "检修";
            case 2:
                return "停运";
            case 3:
                return "调试";
            case 4:
                return "退运";
            default:
                return "未知";
        }
    }

//    /**
//     * 1.平台端默认配置拓扑图模板，包含拓扑图信息(cs_topology_diagram_template)和拓扑图上监测点的点位信息(cs_line_topology_template)
//     *
//     * 2.移动端新增项目时可以上传自己的拓扑图也可以选择拓扑图模板
//     * 维护项目和拓扑图关系(cs_topology_diagram,这个表的id可以使用拓扑图模板id)；
//     * 用户使用拓扑图模板，则根据模板id查(cs_line_topology_template)库中有几个监测点，绑定到监测点模板关系表中(cs_line_topology_diagram);
//     * 用户自己添加拓扑图，则新增拓扑图信息(cs_topology_diagram),同时记录用户在此拓扑图上的点位信息(cs_line_topology_diagram)
//     *
//     * 3.用户注册直连设备，根据模板信息返回监测点数量，页面选择拓扑图，根据(cs_topology_diagram)拓扑图id查询(cs_line_topology_diagram)拓扑图监测点关系表，获取监测点信息。根据位置来获取打点信息。
//     * 注:cs_line_topology_diagram这个表还需要加个位置字段，不然无法根据位置来匹配对应的监测点
//     *
//     * 4.保存之后要在这些表中同步数据(cs_line、cs_ledger)
//     *
//     * @param list
//     */
//    @Override
//    @Transactional(rollbackFor = Exception.class)
//    public void addLines(List<CsLineParm> list) {
//        List<CsLedger> csLedgerLis = new ArrayList<>();
//        list.stream().forEach(temp->{
//            CsLinePO csLinePO = new CsLinePO();
//            BeanUtils.copyProperties(temp,csLinePO);
//            this.save(csLinePO);
//            String lineId = csLinePO.getLineId();
//            CsLedger csLedger = new CsLedger();
//
//            csLedger.setId(lineId);
//            csLedger.setPid(temp.getDevId());
//            csLedger.setLevel(3);
//            csLedger.setSort(1);
//            csLedger.setState(1);
//
//
//            AppLineTopologyDiagramPO appLineTopologyDiagramPO = new AppLineTopologyDiagramPO();
//            appLineTopologyDiagramPO.setId(temp.getTopoId());
//            appLineTopologyDiagramPO.setStatus("1");
//            appLineTopologyDiagramPO.setLineId(lineId);
//            appLineTopologyDiagramPO.setLat(temp.getLat());
//            appLineTopologyDiagramPO.setLng(temp.getLng());
//
//        });
//
//    }
}
