package cn.stylefeng.workflow.instance.modular.tag.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.stylefeng.roses.kernel.auth.api.context.LoginContext;
import cn.stylefeng.roses.kernel.db.api.pojo.entity.BaseEntity;
import cn.stylefeng.workflow.instance.api.pojo.tag.SimpleTagVo;
import cn.stylefeng.workflow.instance.modular.tag.entity.RuntimeTag;
import cn.stylefeng.workflow.instance.modular.tag.mapper.RuntimeTagMapper;
import cn.stylefeng.workflow.instance.modular.tag.pojo.request.RuntimeTagRequest;
import cn.stylefeng.workflow.instance.modular.tag.service.RuntimeTagService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

@Service
public class RuntimeTagServiceImpl extends ServiceImpl<RuntimeTagMapper, RuntimeTag> implements RuntimeTagService {

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateUserTag(RuntimeTagRequest runtimeTagRequest) {

        Long userId = LoginContext.me().getLoginUser().getUserId();

        this.removeUserTags(userId, runtimeTagRequest.getInstanceId());

        List<RuntimeTag> runtimeTagList = runtimeTagRequest.getRuntimeTagList();
        List<RuntimeTag> finalInsert = new ArrayList<>();
        for (RuntimeTag runtimeTag : runtimeTagList) {

            if (ObjectUtil.isEmpty(runtimeTag.getTagName()) || ObjectUtil.isEmpty(runtimeTag.getTagColor())) {
                continue;
            }

            runtimeTag.setUserId(userId);
            runtimeTag.setInstanceId(runtimeTagRequest.getInstanceId());
            finalInsert.add(runtimeTag);
        }

        this.saveBatch(finalInsert);
    }

    @Override
    public List<RuntimeTag> findUserTagList(RuntimeTagRequest runtimeTagRequest) {
        LambdaQueryWrapper<RuntimeTag> wrapper = this.createWrapper(runtimeTagRequest);
        return this.list(wrapper);
    }

    @Override
    public List<RuntimeTag> queryParamTagList() {

        Long userId = LoginContext.me().getLoginUser().getUserId();

        LambdaQueryWrapper<RuntimeTag> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(RuntimeTag::getUserId, userId);
        queryWrapper.select(RuntimeTag::getTagName);
        List<RuntimeTag> list = this.list(queryWrapper);
        if (ObjectUtil.isEmpty(list)) {
            return new ArrayList<>();
        }

        return list.stream().distinct().collect(Collectors.toList());
    }

    @Override
    public Map<Long, List<SimpleTagVo>> findUserTagListMap(List<Long> instanceIdList) {

        if (ObjectUtil.isEmpty(instanceIdList)) {
            return new HashMap<>();
        }

        Long userId = LoginContext.me().getLoginUser().getUserId();

        LambdaQueryWrapper<RuntimeTag> runtimeTagLambdaQueryWrapper = new LambdaQueryWrapper<>();
        runtimeTagLambdaQueryWrapper.eq(RuntimeTag::getUserId, userId);
        runtimeTagLambdaQueryWrapper.in(RuntimeTag::getInstanceId, instanceIdList);
        runtimeTagLambdaQueryWrapper.select(RuntimeTag::getTagName, RuntimeTag::getTagColor, RuntimeTag::getUserId, RuntimeTag::getInstanceId);
        List<RuntimeTag> list = this.list(runtimeTagLambdaQueryWrapper);
        if (ObjectUtil.isEmpty(list)) {
            return new HashMap<>();
        }

        Map<Long, List<RuntimeTag>> result = list.stream().collect(Collectors.groupingBy(RuntimeTag::getInstanceId));

        Map<Long, List<SimpleTagVo>> simpleTagMap = new HashMap<>();
        for (Map.Entry<Long, List<RuntimeTag>> entry : result.entrySet()) {
            List<RuntimeTag> value = entry.getValue();
            if (ObjectUtil.isEmpty(value)) {
                continue;
            }
            List<SimpleTagVo> simpleTagVos = BeanUtil.copyToList(value, SimpleTagVo.class);
            simpleTagMap.put(entry.getKey(), simpleTagVos);
        }
        return simpleTagMap;
    }

    private void removeUserTags(Long userId, Long instanceId) {
        LambdaQueryWrapper<RuntimeTag> runtimeTagLambdaQueryWrapper = new LambdaQueryWrapper<>();
        runtimeTagLambdaQueryWrapper.eq(RuntimeTag::getUserId, userId);
        runtimeTagLambdaQueryWrapper.eq(RuntimeTag::getInstanceId, instanceId);
        this.remove(runtimeTagLambdaQueryWrapper);
    }

    private LambdaQueryWrapper<RuntimeTag> createWrapper(RuntimeTagRequest runtimeTagRequest) {
        LambdaQueryWrapper<RuntimeTag> queryWrapper = new LambdaQueryWrapper<>();

        queryWrapper.eq(RuntimeTag::getUserId, LoginContext.me().getLoginUser().getUserId());

        queryWrapper.eq(RuntimeTag::getInstanceId, runtimeTagRequest.getInstanceId());

        queryWrapper.select(RuntimeTag::getTagName, RuntimeTag::getTagColor);

        queryWrapper.orderByAsc(BaseEntity::getCreateTime);

        return queryWrapper;
    }

}
