package com.artfess.base.manager.impl;

import com.artfess.base.entity.BaseTreeModel;
import com.artfess.base.entity.CqltTreeModel;
import com.artfess.base.id.IdGenerator;
import com.artfess.base.manager.BaseManager;
import com.artfess.base.manager.QueryFilterHelper;
import com.artfess.base.query.PageBean;
import com.artfess.base.query.PageList;
import com.artfess.base.query.QueryFilter;
import com.artfess.base.util.UniqueIdUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.lang3.StringUtils;
import org.jsoup.helper.StringUtil;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.io.Serializable;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class BaseManagerImpl<M extends BaseMapper<T>, T extends Model<T>> extends ServiceImpl<M, T> implements BaseManager<T>, QueryFilterHelper<T> {
	@Override
	public T get(Serializable id) {
		return this.getById(id);
	}

	@Override
	public void create(T t) {
		this.save(t);
	}

	@Override
	public void update(T t) {
		this.updateById(t);
	}

	@Override
	public void remove(Serializable id) {
		this.removeById(id);
	}

	@Override
	public void removeByIds(String ...ids) {
		this.removeByIds(Arrays.asList(ids));
	}

	@Override
	@Transactional(readOnly=true)
	public PageList<T> query(QueryFilter<T> queryFilter) {
		M m = super.getBaseMapper();
		PageBean pageBean = queryFilter.getPageBean();
		Class<T> currentModelClass = currentModelClass();
		IPage<T> result = m.selectPage(convert2IPage(pageBean), convert2Wrapper(queryFilter, currentModelClass));
		return new PageList<T>(result);
	}


	@Override
	public PageList<T> page(PageBean pageBean) {
		IPage<T> result = this.page(convert2IPage(pageBean));
		return new PageList<T>(result);
	}

	@Override
	public List<T> getAll() {
		return this.list();
	}

	@Override
	@Transactional(readOnly=true)
	public List<T> queryNoPage(QueryFilter<T> queryFilter) {
		M m = super.getBaseMapper();
		Class<T> currentModelClass = currentModelClass();
		return m.selectList(convert2Wrapper(queryFilter, currentModelClass));
	}

	@Transactional
	@Override
	public void updateSequence(Map<String, Integer> params) {
		Assert.notEmpty(params, "参数params不能为空。");
		M m = super.getBaseMapper();
		for (String key : params.keySet()) {
			UpdateWrapper<T> updateWrapper = new UpdateWrapper<T>();
			updateWrapper.set("SN_",params.get(key)).eq("ID_",key);
			m.update(null,updateWrapper);
		}
	}

	@Override
	public Integer getNextSequence(Map<String, Object> criteriaMap) {
		M m = super.getBaseMapper();
		QueryWrapper<T> queryWrapper = new QueryWrapper<T>();
		queryWrapper.select("COALESCE(max(SN_),0) \"sn\"");
		if(criteriaMap!=null && !criteriaMap.isEmpty()){
			queryWrapper.allEq(criteriaMap);
		}
		List<Map<String,Object>> resultList =m.selectMaps(queryWrapper);
		if(resultList!=null && resultList.size()>0){
			Map<String,Object> resultMap = resultList.get(0);
			Integer result =Integer.parseInt(resultMap.get("sn").toString());
			return Integer.valueOf(result == null ? 1 : (result = Integer.valueOf(result.intValue() + 1)).intValue());
		}else{
			return 1;
		}
	}

	@Override
	public Integer getNextSequenceByParentId(String parentId) {
		Map<String,Object> criteriaMap=new HashMap<>();
		criteriaMap.put("parent_id_",parentId);
		return getNextSequence(criteriaMap);
	}

	/**
	 * Description: 查询树是否有重复数据
	 * param id, parentId, code, name]
	 * Return:
	 * Author: chens
	 * Date: 2020/4/16 15:11
	 */
	public List<T> findDuplicateEntities(String id, String parentId, String code, String name) {
//		Assert.hasText(parentId, "父ID不能为空。");
		Assert.hasText(code, "编码不能为空。");
		Assert.hasText(name, "名称不能为空。");
		M m = super.getBaseMapper();
		QueryWrapper<T> queryWrapper = new QueryWrapper<T>();
		queryWrapper.ne("id_", StringUtil.isBlank(id) ? "@" : id).eq("parent_Id_",parentId).and(i -> i.eq("upper(code_) ", code.toUpperCase()).or().eq("upper(name_)", name.toUpperCase()));
//		queryWrapper.eq("is_dele_", DelStatusEnum.N.getType());
		return m.selectList(queryWrapper);
	}

	@Override
	@Transactional
	public String insertTree(BaseTreeModel entity) {
		return saveTree(entity, true);
	}

	@Transactional
	public String saveTree(BaseTreeModel entity, boolean useDefaultCheck) {
		M m = super.getBaseMapper();
		if (useDefaultCheck) {
			List<?> duplicateEntities = findDuplicateEntities(entity.getId(), entity.getParentId(), entity.getCode(),entity.getName());
			BaseTreeModel other = null;
			if (duplicateEntities.size() > 0) {
				other = (BaseTreeModel) duplicateEntities.get(0);
			}
			entity.checkConstraints(other);
		}

		BaseTreeModel parent = (BaseTreeModel) baseMapper.selectById(entity.getParentId());
		if (entity.getSn() == null) {
			entity.setSn(Integer.valueOf(parent == null ? 1 : parent.getHasChildren().intValue() + 1));
		}
		if(entity.isNew()){
			entity.setHasChildren(Integer.valueOf(0));
			//m.insert((T)entity);
			entity.setId(UniqueIdUtil.getSuid());
		}

		entity.buildFullIdAndName(parent);
		//m.updateById((T)entity);
		super.saveOrUpdate((T)entity);

		if (parent != null) {
			QueryWrapper<T> queryWrapper = new QueryWrapper<T>();
			queryWrapper.eq("parent_Id_",entity.getParentId());
			Integer childrenCount = this.baseMapper.selectCount(queryWrapper);
			parent.setHasChildren(childrenCount);
			m.updateById((T) parent);
		}

		return entity.getId();
	}

	@Override
	@Transactional
	public String saveTreeAndId(BaseTreeModel entity) {
		M m = super.getBaseMapper();
		entity.setId(entity.getCode());
		entity.setHasChildren(Integer.valueOf(0));
		m.insert((T)entity);
		BaseTreeModel parent = (BaseTreeModel) baseMapper.selectById(entity.getParentId());
		entity.buildFullIdAndName(parent);
		if (entity.getSn() == null) {
			entity.setSn(Integer.valueOf(parent == null ? 1 : parent.getHasChildren().intValue() + 1));
		}
		m.updateById((T)entity);

		if (parent != null) {
			QueryWrapper<T> queryWrapper = new QueryWrapper<T>();
			queryWrapper.eq("parent_Id_",entity.getParentId());
			Integer childrenCount = this.baseMapper.selectCount(queryWrapper);
			parent.setHasChildren(childrenCount);
			m.updateById((T) parent);
		}
		return entity.getId();
	}

	/**
	 * @Description: 修改树
	 * @param entity 修改的实体
	 *@param oldName 以前的name
	 * @Return: java.lang.String
	 * @Author: chens
	 * @Date: 2020/4/28 14:52
	 */
	@Override
	@Transactional
	public String updateTree(BaseTreeModel entity, String oldName) {
		M m = super.getBaseMapper();
		m.updateById((T)entity);
		BaseTreeModel treeEntity = (BaseTreeModel)m.selectById(entity.getId());
		return updateTree(treeEntity, oldName, true);
	}

	@Transactional
	public String updateTree(BaseTreeModel entity, String oldName, boolean useDefaultCheck) {
		Assert.notNull(entity, "对象不能为空。");

		boolean updatedName = entity.isUpdateName(oldName);//判断是否修改过name
		String oldFullName = entity.getFullName();
		String id = saveTree(entity, useDefaultCheck);
		if (updatedName) { //如果修改了name，则修改子节点的fullName
			updateChildrenFullName(entity.getFullId(), oldFullName, entity.getFullName());
		}
		return id;
	}

	/**
	 * @Description: 修改子节点的名称全路径
	 * @param fullId id全路径
	 * @param oldFullName 旧的name全路径
	 * @param newFullName 新的name全路径
	 * @Author: chens
	 * @Date: 2020/4/15 17:33
	 */
	@Transactional
	public void updateChildrenFullName(String fullId, String oldFullName, String newFullName) {
		UpdateWrapper<T> updateWrapper = new UpdateWrapper<T>();
		updateWrapper.setSql("full_Name_ = concat('"+newFullName+"', substring(full_Name_,char_length('"+oldFullName+"') + 1,char_length(full_Name_)))").likeRight("full_Id_",fullId);
		this.baseMapper.update(null,updateWrapper);

	}

	public boolean checkSameField(String id,String fieldName,String fieldValue){
		Assert.hasText(fieldName, "要比较的字段名不能为空。");
		Assert.hasText(fieldValue, "字段值不能为空。");
		QueryWrapper<T> queryWrapper = new QueryWrapper<T>();
		queryWrapper.eq( fieldName, fieldValue);
		queryWrapper.ne(StringUtils.isNotBlank(id), "ID_", id);
		int num = this.baseMapper.selectCount(queryWrapper);
		if(num != 0){
			return false;
		}else {
			return true;
		}
	}

	@Override
	@Transactional
	public String newInsertTree(CqltTreeModel entity) {
		return newSaveTree(entity, true);
	}

	@Transactional
	public String newSaveTree(CqltTreeModel entity, boolean useDefaultCheck) {
		M m = super.getBaseMapper();
		if (useDefaultCheck) {
			List<?> duplicateEntities = findDuplicateEntities(entity.getId(), entity.getParentId(), entity.getCode(),entity.getName());
			CqltTreeModel other = null;
			if (duplicateEntities.size() > 0) {
				other = (CqltTreeModel) duplicateEntities.get(0);
			}
			entity.checkConstraints(other);
		}

		if (entity.isNew()) {
			entity.setHasChildren(Integer.valueOf(0));
			m.insert((T)entity);
		}

		CqltTreeModel parent = (CqltTreeModel) baseMapper.selectById(entity.getParentId());
		entity.buildFullIdAndName(parent);
		if (entity.getSn() == null) {
			entity.setSn(Integer.valueOf(parent == null ? 1 : parent.getHasChildren().intValue() + 1));
		}
		m.updateById((T)entity);

		if (parent != null) {
			QueryWrapper<T> queryWrapper = new QueryWrapper<T>();
			queryWrapper.eq("parent_Id_",entity.getParentId());
			Integer childrenCount = this.baseMapper.selectCount(queryWrapper);
			parent.setHasChildren(childrenCount);
			m.updateById((T) parent);
		}

		return entity.getId();
	}

	/**
	 * @Description: 修改树
	 * @param entity 修改的实体
	 *@param oldName 以前的name
	 * @Return: java.lang.String
	 * @Author: chens
	 * @Date: 2020/4/28 14:52
	 */
	@Override
	@Transactional
	public String newUpdateTree(CqltTreeModel entity, String oldName) {
		M m = super.getBaseMapper();
		m.updateById((T)entity);
		CqltTreeModel treeEntity = (CqltTreeModel)m.selectById(entity.getId());
		return newUpdateTree(treeEntity, oldName, true);
	}

	@Transactional
	public String newUpdateTree(CqltTreeModel entity, String oldName, boolean useDefaultCheck) {
		Assert.notNull(entity, "对象不能为空。");

		boolean updatedName = entity.isUpdateName(oldName);//判断是否修改过name
		String oldFullName = entity.getFullName();
		String id = newSaveTree(entity, useDefaultCheck);
		if (updatedName) { //如果修改了name，则修改子节点的fullName
			updateChildrenFullName(entity.getFullId(), oldFullName, entity.getFullName());
		}
		return id;
	}

}
