package com.keyware.shandan.bianmu.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.keyware.shandan.bianmu.entity.DataLabelsVo;
import com.keyware.shandan.bianmu.entity.DirectoryResource;
import com.keyware.shandan.bianmu.entity.FormLabelVo;
import com.keyware.shandan.bianmu.entity.LabelEntity;
import com.keyware.shandan.bianmu.mapper.DataLabelsMapper;
import com.keyware.shandan.bianmu.mapper.DirectoryResourceMapper;
import com.keyware.shandan.bianmu.mapper.FormLabelMapper;
import com.keyware.shandan.bianmu.service.DataLabelsService;
import com.keyware.shandan.bianmu.service.LabelEntityService;
import com.keyware.shandan.common.entity.Result;
import com.keyware.shandan.common.service.BaseServiceImpl;
import com.keyware.shandan.common.util.StringUtils;
import com.keyware.shandan.system.entity.SysUser;
import com.keyware.shandan.system.service.SysUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author GuoXin
 * @date 2022-12-30
 */
@Service
public class DataLabelsServiceImpl extends BaseServiceImpl<DataLabelsMapper, DataLabelsVo, Integer> implements DataLabelsService {

    @Autowired
    private SysUserService userService;

    @Autowired
    private FormLabelMapper formLabelMapper;

    @Autowired
    private LabelEntityService labelEntityService;

    @Autowired
    private DirectoryResourceMapper directoryResourceMapper;

    @Override
    public Result<DataLabelsVo> updateOrSave(DataLabelsVo entity) throws Exception {
        if (entity.getParentId() != 0) {
            DataLabelsVo parent = getById(entity.getParentId());
            entity.setLevel(parent.getLevel() + 1);
            entity.setIdPath(parent.getIdPath() + parent.getId() + "/");
            entity.setTitlePath(parent.getTitlePath() + parent.getTitle() + "/");
        } else {
            entity.setLevel(1);
            entity.setIdPath("/");
            entity.setTitlePath("/");
        }
        DataLabelsVo old = getById(entity.getId());
        if(old == null || !old.getTitle().equals(entity.getTitle())){
            Assert.isNull(getByTitlePathAndTitle(entity), "分类下存在相同名称，请检查");
        }
        return super.updateOrSave(entity);
    }

    @Override
    public Page<DataLabelsVo> page(Page<DataLabelsVo> page, QueryWrapper<DataLabelsVo> wrapper) {
        DataLabelsVo dataLabel = wrapper.getEntity();
        if (dataLabel != null && StringUtils.hasText(dataLabel.getTitle()) && StringUtils.hasText(dataLabel.getDescription())) {
            wrapper.like("TITLE", dataLabel.getTitle()).or().like("DESCRIPTION", dataLabel.getDescription());
            wrapper.setEntity(null);
        }
        Page<DataLabelsVo> result = super.page(page, wrapper);
        result.getRecords().forEach(item -> {
            SysUser user = userService.getById(item.getCreateUser());
            item.setCreateUserName(user.getUserName());
        });
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean removeByIds(Collection<? extends Serializable> idList) {
        idList.forEach(id -> deleteById(Integer.valueOf((String) id)));
        return super.removeByIds(idList);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Boolean> deleteById(Integer id) {
        DataLabelsVo dataLabel = getById(id);
        Assert.notNull(dataLabel, "数据不存在");
        QueryWrapper<DataLabelsVo> wrapper = new QueryWrapper<>();
        wrapper.likeRight("ID_PATH", dataLabel.getIdPathWithSelf());
        super.remove(wrapper);
        return super.deleteById(id);
    }

    private DataLabelsVo getByTitlePathAndTitle(DataLabelsVo label) {
        QueryWrapper<DataLabelsVo> wrapper = new QueryWrapper<>();
        wrapper.eq("TITLE_PATH", label.getTitlePath()).eq("TITLE", label.getTitle());
        return getOne(wrapper);
    }

    @Override
    public Boolean checkConfig(DataLabelsVo label, String fieldTitle) {
        QueryWrapper<FormLabelVo> formWrapper = new QueryWrapper<>();
        formWrapper.clear();
        formWrapper.eq("FIELD_TITLE", fieldTitle);
        List<FormLabelVo> configList = formLabelMapper.selectList(formWrapper);
        Assert.isTrue(configList.size() == 0, "字段标题已经存在");

        return true;
    }

    @Override
    public void addConfig(DataLabelsVo label, String fieldTitle) {
        formLabelMapper.insert(FormLabelVo.builder()
                .labelId(label.getId())
                .labelIdPath(label.getIdPathWithSelf())
                .fieldTitle(fieldTitle)
                .build());
    }

    @Override
    public List<FormLabelVo> formConfigList() {
        List<FormLabelVo> list = formLabelMapper.selectList(new QueryWrapper<>());
        list.forEach(item -> {
            item.setUser(userService.getById(item.getCreateUser()));
            item.setLabel(getById(item.getLabelId()));
        });
        return list;
    }

    @Override
    public FormLabelVo getFormLabelById(Integer id) {
        return formLabelMapper.selectById(id);
    }

    @Override
    public Boolean updateFormLabel(FormLabelVo formLabel) {
        return formLabelMapper.updateById(formLabel) > 0;
    }

    @Override
    public Boolean deleteFormLabelById(Integer id) {
        return formLabelMapper.deleteById(id) > 0;
    }

    /**
     * 该方法查询的数据可能包含重复数据
     *
     * @param label
     * @return
     */
    @Override
    public int countByLabelEntity(DataLabelsVo label) {
        List<Integer> labelIdList = listByLikeIdPath(label, true)
                .stream()
                .map(DataLabelsVo::getId)
                .collect(Collectors.toList());
        if (labelIdList.size() == 0) {
            return 0;
        }
        QueryWrapper<LabelEntity> wrapper = new QueryWrapper<>();
        wrapper.in("LABEL_ID", labelIdList);
        return labelEntityService.count(wrapper);
    }

    @Override
    public Page<DirectoryResource> directoryResourcePageByDataLabel(Page<DirectoryResource> page, String resourceName, Integer... labelId) {
        QueryWrapper<DirectoryResource> wrapper = new QueryWrapper<>();
        // 模糊查询条件
        wrapper.and(StringUtils.hasText(resourceName), subWrapper -> {
            subWrapper.like("RESOURCE_NAME", resourceName).or().like("RESOURCE_COMMENT", resourceName);
        });

        // 多标签查询条件拼接逻辑
        List<DataLabelsVo> labelList = listByIds(Arrays.asList(labelId));
        if (labelList.size() > 0) {
            // 对标签进行过滤，只保留叶子节点的数据
            List<String> labelPathList = labelList.stream().map(DataLabelsVo::getIdPathWithSelf).collect(Collectors.toList());
            labelList = labelList.stream().filter(label -> {
                for (String path : labelPathList) {
                    if (path.startsWith(label.getIdPathWithSelf()) && !path.equals(label.getIdPathWithSelf())) {
                        return false;
                    }
                }
                return true;
            }).collect(Collectors.toList());

            // 将标签数据转换为条件项sql
            List<String> tempSqlList = labelList
                    .stream()
                    .map(label -> "" +
                            "L.ID_PATH || L.ID || '/' LIKE '" + label.getIdPathWithSelf() + "' || '%' ")
                    .collect(Collectors.toList());

            // 拼接where sql，判断关系表命中数据的条数是否与标签数一致，一致说明所有标签条件都满足，不一致说明不满足
            String whereSql = "(SELECT COUNT(T.ID) " +
                    "       FROM (SELECT E.ID, E.ENTITY_ID " +
                    "             FROM B_DATA_LABEL_ENTITY E " +
                    "                      LEFT JOIN B_DATA_LABELS L ON L.ID = E.LABEL_ID " +
                    "             WHERE " + String.join(" OR ", tempSqlList) + ") T " +
                    "       WHERE T.ENTITY_ID = V_DIRECTORY_RESOURCE.ID) = " + tempSqlList.size();
            // 判断拼接sql的关键字
            if(!StringUtils.hasText(resourceName)){
                whereSql = " WHERE " + whereSql;
            }else{
                whereSql = " AND " + whereSql;
            }
            wrapper.last(whereSql);
        } else {
            wrapper.exists("SELECT T.ID FROM B_DATA_LABEL_ENTITY T WHERE T.ENTITY_ID = V_DIRECTORY_RESOURCE.ID");
        }
        return directoryResourceMapper.selectPage(page, wrapper);
    }

    private List<DataLabelsVo> listByLikeIdPath(DataLabelsVo label, boolean includeSelf) {
        List<DataLabelsVo> list = new ArrayList<>();
        if (includeSelf) {
            list.add(label);
        }
        QueryWrapper<DataLabelsVo> wrapper = new QueryWrapper<>();
        wrapper.likeRight("ID_PATH", label.getIdPath() + label.getId() + "/");
        list.addAll(list(wrapper));
        return list;
    }
}
