package com.njcn.gather.source.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 cn.hutool.json.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.njcn.common.pojo.enums.common.DataStateEnum;
import com.njcn.common.pojo.exception.BusinessException;
import com.njcn.gather.device.pojo.enums.CommonEnum;
import com.njcn.gather.pojo.enums.DetectionResponseEnum;
import com.njcn.gather.source.mapper.PqSourceMapper;
import com.njcn.gather.source.pojo.param.PqSourceParam;
import com.njcn.gather.source.pojo.po.PqSource;
import com.njcn.gather.source.pojo.po.SourceInitialize;
import com.njcn.gather.source.pojo.po.SourceParam;
import com.njcn.gather.source.service.IPqSourceService;
import com.njcn.gather.system.dictionary.pojo.po.DictData;
import com.njcn.gather.system.dictionary.service.IDictDataService;
import com.njcn.gather.type.service.IDevTypeService;
import com.njcn.web.factory.PageFactory;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author caozehui
 * @date 2024-11-28
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class PqSourceServiceImpl extends ServiceImpl<PqSourceMapper, PqSource> implements IPqSourceService {

    private final IDictDataService dictDataService;
    private final IDevTypeService devTypeService;

    @Override
    public Page<PqSource> listPqSource(PqSourceParam.QueryParam param) {
        QueryWrapper<PqSource> queryWrapper = new QueryWrapper<>();
        queryWrapper.select(PqSource.class, pqSource -> !pqSource.getColumn().equals("parameter"));
        if (ObjectUtil.isNotNull(param)) {
            queryWrapper.like(StrUtil.isNotBlank(param.getName()), "pq_source.name", param.getName())
                    .eq(StrUtil.isNotBlank(param.getPattern()), "pq_source.pattern", param.getPattern())
                    .eq(StrUtil.isNotBlank(param.getType()), "pq_source.type", param.getType())
                    .eq(StrUtil.isNotBlank(param.getDevType()), "pq_source.Dev_Type", param.getDevType());
        }
        queryWrapper.eq("pq_source.state", DataStateEnum.ENABLE.getCode()).orderByAsc("pq_source.Create_Time");
        return this.page(new Page<>(PageFactory.getPageNum(param), PageFactory.getPageSize(param)), queryWrapper);
    }

    @Override
    public PqSource getPqSourceById(String id) {
        return this.lambdaQuery().eq(PqSource::getId, id).eq(PqSource::getState, DataStateEnum.ENABLE.getCode()).one();
    }

    @Override
    @Transactional
    public boolean addPqSource(PqSourceParam param) {
        PqSource pqSource = new PqSource();
        BeanUtil.copyProperties(param, pqSource);
        pqSource.setName(this.generatePqSourceName(param, true));
        pqSource.setParameter(StrUtil.isBlank(pqSource.getParameter()) ? null : pqSource.getParameter());
        pqSource.setState(DataStateEnum.ENABLE.getCode());
        return this.save(pqSource);
    }

    @Override
    @Transactional
    public boolean updatePqSource(PqSourceParam.UpdateParam param) {
        PqSource pqSource = new PqSource();
        BeanUtil.copyProperties(param, pqSource);
        pqSource.setName(this.generatePqSourceName(param, false));
        return this.updateById(pqSource);
    }

    @Override
    @Transactional
    public boolean deletePqSource(List<String> ids) {
        Integer count = this.baseMapper.getCountBoundByIds(ids);
        if (count > 0) {
            throw new BusinessException(DetectionResponseEnum.SOURCE_BOUND_NOT_DELETE);
        }
        return this.lambdaUpdate().in(PqSource::getId, ids).set(PqSource::getState, DataStateEnum.DELETED.getCode()).update();
    }

    @Override
    public List<Map<String, Object>> listAllPqSource(String patternId) {
        List<PqSource> pqSourceList = this.lambdaQuery().eq(PqSource::getPattern, patternId).orderByAsc(PqSource::getCreateTime).eq(PqSource::getState, DataStateEnum.ENABLE.getCode()).list();
        List<Map<String, Object>> result = pqSourceList.stream().map(pqSource -> {
            Map<String, Object> map = new HashMap<>();
            map.put("id", pqSource.getId());
            map.put("name", pqSource.getName());
            return map;
        }).collect(Collectors.toList());
        return result;
    }

    @Override
    public List<SourceParam> getSourceParam(String sourceId) {
        PqSource pqSource = this.lambdaQuery().eq(PqSource::getId, sourceId).eq(PqSource::getState, DataStateEnum.ENABLE.getCode()).one();
        if (ObjectUtil.isNotNull(pqSource)) {
            String parameter = pqSource.getParameter();
            if (StrUtil.isNotBlank(parameter)) {
                List<SourceParam> list = new JSONArray(parameter).toList(SourceParam.class);
                List<SourceParam> sourceParams = list.stream().filter(p -> p.getPId().equals(CommonEnum.FATHER_ID.getValue()))
                        .peek(p -> p.setChildren(getChildren(p, list)))
                        .sorted(Comparator.comparingInt(SourceParam::getSort))
                        .collect(Collectors.toList());
                return sourceParams;
            }
        }
        return null;
    }

    @Override
    public SourceInitialize getSourceInitializeParam(String sourceId) {
        PqSource pqSource = this.lambdaQuery().eq(PqSource::getId, sourceId).eq(PqSource::getState, DataStateEnum.ENABLE.getCode()).one();
        if (ObjectUtil.isNotNull(pqSource)) {
            String parameter = pqSource.getParameter();
            if (StrUtil.isNotBlank(parameter)) {
                List<SourceInitialize.Initialize> list = new JSONArray(parameter).toList(SourceInitialize.Initialize.class);
                List<SourceInitialize.Initialize> sourceParams = list.stream().filter(p -> p.getPId().equals(CommonEnum.FATHER_ID.getValue()))
                        .peek(p -> p.setChildren(getInitializeChildren(p, list)))
                        .sorted(Comparator.comparingInt(SourceInitialize.Initialize::getSort))
                        .collect(Collectors.toList());
                if (CollUtil.isNotEmpty(sourceParams)) {
                    SourceInitialize initialize = new SourceInitialize();
                    SourceInitialize.Initialize source = sourceParams.get(0);
                    initialize.setSourceId(source.getValue());
                    initialize.setSourceType(source.getType());
                    initialize.setSourceDesc(source.getDesc());
                    initialize.setSourceParamList(source.getChildren());
                    return initialize;
                }
                return null;
            }
        }
        return null;
    }

    @Override
    public List<String> listPqSourceIdByName(String[] sourceNames) {
        return this.lambdaQuery().in(PqSource::getName, sourceNames).eq(PqSource::getState, DataStateEnum.ENABLE.getCode()).list().stream().map(PqSource::getId).collect(Collectors.toList());
    }

    private List<SourceParam> getChildren(SourceParam current, List<SourceParam> list) {
        return list.stream()
                .filter(p -> p.getPId().equals(current.getId()))
                .peek(p -> p.setChildren(getChildren(p, list)))
                .sorted(Comparator.comparingInt(SourceParam::getSort))
                .collect(Collectors.toList());
    }

    private List<SourceInitialize.Initialize> getInitializeChildren(SourceInitialize.Initialize current, List<SourceInitialize.Initialize> list) {
        return list.stream()
                .filter(p -> p.getPId().equals(current.getId()))
                .peek(p -> p.setChildren(getInitializeChildren(p, list)))
                .sorted(Comparator.comparingInt(SourceInitialize.Initialize::getSort))
                .collect(Collectors.toList());
    }


    /**
     * 生成检测源名称（检测源类型+设备类型+数字）
     *
     * @return 检测源名称
     */
    private String generatePqSourceName(PqSourceParam param, boolean isAdd) {
        DictData devType = dictDataService.getDictDataById(param.getDevType());
        DictData typeDictData = dictDataService.getDictDataById(param.getType());

        if (ObjectUtil.isNotNull(devType) && ObjectUtil.isNotNull(typeDictData)) {
            if (isAdd) {
                int count = this.lambdaQuery().eq(PqSource::getPattern, param.getPattern()).eq(PqSource::getState, DataStateEnum.ENABLE.getCode()).count();
                return typeDictData.getName() + "-" + devType.getName() + "-" + (count + 1);
            } else {
                PqSource pqSource = this.lambdaQuery().eq(PqSource::getId, ((PqSourceParam.UpdateParam) param).getId()).one();
                if (ObjectUtil.isNotNull(pqSource)) {
                    String name = pqSource.getName();
                    if (StrUtil.isNotBlank(name)) {
                        int index = name.lastIndexOf("-");
                        return typeDictData.getName() + "-" + devType.getName() + "-" + name.substring(index + 1);
                    }
                }
            }
        }
        throw new BusinessException(DetectionResponseEnum.PQ_SOURCE_GEN_NAME_ERROR);
    }
}
