package cn.axzo.workflow.core.service.impl;

import cn.axzo.basics.common.constant.enums.TableIsDeleteEnum;
import cn.axzo.framework.data.mybatisplus.model.BaseEntity;
import cn.axzo.framework.domain.ServiceException;
import cn.axzo.workflow.common.model.request.category.CategoryGroupVarSearchDto;
import cn.axzo.workflow.common.model.request.category.CategoryGroupVarUpsertDto;
import cn.axzo.workflow.common.model.response.category.CategoryGroupVarItemVo;
import cn.axzo.workflow.core.repository.entity.ExtAxDictGroup;
import cn.axzo.workflow.core.repository.entity.ExtAxDictGroupVariable;
import cn.axzo.workflow.core.repository.mapper.ExtAxDictGroupMapper;
import cn.axzo.workflow.core.service.CategoryGroupService;
import cn.axzo.workflow.core.service.CategoryGroupVariableService;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.ListUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
@Slf4j
public class CategoryGroupServiceImpl extends ServiceImpl<ExtAxDictGroupMapper, ExtAxDictGroup> implements CategoryGroupService {

    private final CategoryGroupVariableService categoryGroupVariableService;

    @Override
    public List<CategoryGroupVarItemVo> searchGroupAndVarList(CategoryGroupVarSearchDto dto) {
        if ((dto.getDictId() == null || dto.getDictId() <= 0) && StringUtils.isBlank(dto.getCategory())) {
            throw new ServiceException("dictId和category不能同时为空");
        }
        List<ExtAxDictGroup> extAxDictGroups = this.lambdaQuery()
                .eq(Objects.nonNull(dto.getDictId()) && dto.getDictId() > 0, ExtAxDictGroup::getDictId, dto.getDictId())
                .inSql((Objects.isNull(dto.getDictId()) || dto.getDictId() <= 0) && StringUtils.isNotBlank(dto.getCategory()), ExtAxDictGroup::getDictId,
                        String.format("SELECT id FROM ext_ax_dict WHERE value = '%s'", dto.getCategory()))
                .orderByAsc(ExtAxDictGroup::getOrdinal)
                .list();
        if (CollectionUtils.isEmpty(extAxDictGroups)) {
            return Collections.emptyList();
        }
        List<ExtAxDictGroupVariable> groupVars = categoryGroupVariableService.lambdaQuery()
                .eq(Objects.nonNull(dto.getDictId()), ExtAxDictGroupVariable::getDictId, dto.getDictId())
                .eq(ExtAxDictGroupVariable::getIsDelete, TableIsDeleteEnum.NORMAL.value)
                .list();
        Map<Long, List<ExtAxDictGroupVariable>> varMap = ListUtils.emptyIfNull(groupVars).stream().collect(Collectors.groupingBy(ExtAxDictGroupVariable::getGroupId));
        return extAxDictGroups.stream()
                .map(group -> {
                    CategoryGroupVarItemVo categoryGroupVarItemVo = BeanUtil.copyProperties(group, CategoryGroupVarItemVo.class);
                    List<CategoryGroupVarItemVo.CategoryVarItemVo> categoryVarItemVos = BeanUtil.copyToList(ListUtils.emptyIfNull(varMap.get(group.getId())), CategoryGroupVarItemVo.CategoryVarItemVo.class);
                    categoryGroupVarItemVo.setVars(categoryVarItemVos);
                    return categoryGroupVarItemVo;
                }).collect(Collectors.toList());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean upsertGroupAndVars(CategoryGroupVarUpsertDto dto) {
        if (dto.getDictId() == null || dto.getDictId() <= 0) {
            throw new ServiceException("dictId 不能为空且必须大于0");
        }
        if (ListUtils.emptyIfNull(dto.getGroupVos()).stream()
                .collect(Collectors.groupingBy(CategoryGroupVarUpsertDto.CategoryGroupUpsertVo::getOrdinal))
                .values()
                .stream()
                .anyMatch(gl -> gl.size() > 1)) {
            throw new ServiceException("分组 ordinal 不允许重复");
        }
        List<ExtAxDictGroup> existGroups = this.lambdaQuery()
                .eq(ExtAxDictGroup::getDictId, dto.getDictId())
                .eq(ExtAxDictGroup::getIsDelete, TableIsDeleteEnum.NORMAL.value)
                .list();
        Map<Long, List<ExtAxDictGroup>> existGroupMap = ListUtils.emptyIfNull(existGroups).stream().collect(Collectors.groupingBy(BaseEntity::getId));
        List<ExtAxDictGroupVariable> existVars = categoryGroupVariableService.lambdaQuery()
                .eq(ExtAxDictGroupVariable::getDictId, dto.getDictId())
                .eq(ExtAxDictGroupVariable::getIsDelete, TableIsDeleteEnum.NORMAL.value)
                .list();
        if (CollectionUtils.isEmpty(dto.getGroupVos())) {
            if (!CollectionUtils.isEmpty(existGroups)) {
                this.removeByIds(existGroups.stream().map(BaseEntity::getId).collect(Collectors.toList()));
            }
            if (!CollectionUtils.isEmpty(existVars)) {
                categoryGroupVariableService.removeByIds(existVars.stream().map(BaseEntity::getId).collect(Collectors.toList()));
            }
            return Boolean.TRUE;
        }
        Map<Long, List<ExtAxDictGroupVariable>> existVarMap = ListUtils.emptyIfNull(existVars).stream().collect(Collectors.groupingBy(BaseEntity::getId));
        List<ExtAxDictGroup> saveOrUpdateGroups = new ArrayList<>();
        List<ExtAxDictGroupVariable> saveOrUpdateVars = new ArrayList<>();
        Map<Integer, List<ExtAxDictGroupVariable>> createVarMap = new HashMap<>();
        for (CategoryGroupVarUpsertDto.CategoryGroupUpsertVo groupVo : dto.getGroupVos()) {
            ExtAxDictGroup extAxDictGroup = new ExtAxDictGroup();
            extAxDictGroup.setGroupName(groupVo.getGroupName());
            extAxDictGroup.setDictId(dto.getDictId());
            extAxDictGroup.setParentGroupId(groupVo.getParentGroupId());
            extAxDictGroup.setOrdinal(groupVo.getOrdinal());
            if (groupVo.getId() != null && groupVo.getId() > 0) {
                extAxDictGroup.setId(groupVo.getId());
                saveOrUpdateGroups.add(extAxDictGroup);
                List<CategoryGroupVarUpsertDto.CategoryVarUpsertVo> vars = groupVo.getVars();
                if (!CollectionUtils.isEmpty(vars)) {
                    for (CategoryGroupVarUpsertDto.CategoryVarUpsertVo v : vars) {
                        ExtAxDictGroupVariable extAxDictGroupVariable = BeanUtil.copyProperties(v, ExtAxDictGroupVariable.class);
                        if (v.getId() != null && v.getId() > 0) {
                            saveOrUpdateVars.add(extAxDictGroupVariable);
                        } else {
                            extAxDictGroupVariable.setDictId(dto.getDictId());
                            extAxDictGroupVariable.setGroupId(groupVo.getId());
                            extAxDictGroupVariable.setOrdinal(groupVo.getOrdinal());
                            extAxDictGroupVariable.setDictId(dto.getDictId());
                            createVarMap.computeIfAbsent(groupVo.getOrdinal(), c -> new ArrayList<>()).add(extAxDictGroupVariable);
                        }
                    }
                }
            } else {
                saveOrUpdateGroups.add(extAxDictGroup);
                List<CategoryGroupVarUpsertDto.CategoryVarUpsertVo> vars = groupVo.getVars();
                if (!CollectionUtils.isEmpty(vars)) {
                    vars.forEach(v -> {
                        ExtAxDictGroupVariable extAxDictGroupVariable = BeanUtil.copyProperties(v, ExtAxDictGroupVariable.class);
                        extAxDictGroupVariable.setOrdinal(v.getOrdinal());
                        extAxDictGroupVariable.setDictId(dto.getDictId());
                        createVarMap.computeIfAbsent(groupVo.getOrdinal(), c -> new ArrayList<>()).add(extAxDictGroupVariable);
                    });
                }
            }
        }
        if (!existGroupMap.isEmpty()) {
            saveOrUpdateGroups.stream()
                    .filter(g -> g.getId() != null && g.getId() > 0)
                    .forEach(g -> existGroupMap.remove(g.getId()));
        }
        if (!existVarMap.isEmpty()) {
            saveOrUpdateVars.stream()
                    .filter(v -> v.getId() != null && v.getId() > 0)
                    .forEach(v -> existVarMap.remove(v.getId()));
        }
        boolean groupSaveResult = this.saveOrUpdateBatch(saveOrUpdateGroups);
        if (!groupSaveResult) {
            throw new ServiceException("保存失败");
        }
        Map<Integer, List<ExtAxDictGroup>> ordinalGroupMap = saveOrUpdateGroups.stream().collect(Collectors.groupingBy(ExtAxDictGroup::getOrdinal));
        createVarMap.forEach((key, value) -> value.forEach(v -> v.setGroupId(ordinalGroupMap.get(key).get(0).getId())));
        saveOrUpdateVars.addAll(createVarMap.values().stream().flatMap(Collection::stream).collect(Collectors.toList()));
        //保存变量
        categoryGroupVariableService.saveOrUpdateBatch(saveOrUpdateVars);
        //删除多余的group和变量
        if (!existGroupMap.isEmpty()) {
            //删除分组
            this.removeByIds(existGroupMap.keySet());
            //删除分组下的变量
            QueryWrapper<ExtAxDictGroupVariable> queryWrapper = new QueryWrapper<>();
            queryWrapper.in("group_id", existGroupMap.keySet());
            categoryGroupVariableService.remove(queryWrapper);
        }
        //删除多余变量
        if (!existVarMap.isEmpty()) {
            categoryGroupVariableService.removeByIds(existVarMap.keySet());
        }
        return true;
    }
}
