package com.artfess.sysConfig.persistence.manager.impl;



import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import javax.annotation.Resource;

import com.artfess.base.cache.CacheManager;
import com.artfess.base.cache.ICache;
import com.artfess.base.cache.setting.CacheSetting;
import com.artfess.base.constants.CacheKeyConst;
import com.artfess.base.context.BaseContext;
import com.artfess.base.exception.ApplicationException;
import com.artfess.base.id.IdGenerator;
import com.artfess.base.util.JsonUtil;
import com.artfess.poi.util.ExcelUtil;
import com.artfess.redis.util.RedisUtil;
import com.artfess.sysConfig.persistence.dao.SysTypeDao;
import com.artfess.sysConfig.vo.DataDictExcelVo;
import com.artfess.sysConfig.vo.DictionaryDetailVo;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;



import com.artfess.base.exception.BaseException;
import com.artfess.base.manager.impl.BaseManagerImpl;
import com.artfess.base.model.CommonResult;
import com.artfess.base.util.BeanUtils;
import com.artfess.base.util.StringUtil;
import com.artfess.sysConfig.persistence.dao.DataDictDao;
import com.artfess.sysConfig.persistence.manager.DataDictManager;
import com.artfess.sysConfig.persistence.manager.SysTypeManager;
import com.artfess.sysConfig.persistence.model.DataDict;
import com.artfess.sysConfig.persistence.model.SysType;
import com.artfess.sysConfig.vo.DataDictDatalExcelVo;

@Service("dataDictManager")
public class DataDictManagerImpl extends BaseManagerImpl<DataDictDao, DataDict> implements DataDictManager{
	@Resource
	SysTypeManager sysTypeManager;

	@Resource
	IdGenerator idGenerator;

	@Resource
	private RedisUtil redisUtil;

	@Resource
	BaseContext baseContext;


	@Override
	public List<DataDict> getAllDataVal() throws Exception{

		String tenantId = baseContext.getCurrentTenantId();
		List<Object> list = redisUtil.lGet(CacheKeyConst.SYS_DIMENSION_DICT + ":" + tenantId, 0, -1);
		List<DataDict> relist = new ArrayList<>();
		if(CollectionUtils.isEmpty(list)){
			relist = this.baseMapper.getAllDataVal();
			redisUtil.lSet(CacheKeyConst.SYS_DIMENSION_DICT + ":" + tenantId,relist);
			return relist;
		}
		List<Object> sslist = (ArrayList)list.get(0);
		relist =sslist.stream().map(obj -> (DataDict) obj).collect(Collectors.toList());
		return relist;
	}

	@Override
	public List<DataDict> getByTypeId(String typeId) {
		return baseMapper.getByTypeId(typeId);
	}

	@Override
	public List<DataDict> getDicByTypeId(String type_id_) {
		QueryWrapper<DataDict> queryWrapper = new QueryWrapper();
		queryWrapper.eq("type_id_", type_id_);
		queryWrapper.eq("type_","dic");
		queryWrapper.orderByAsc("sn_");
		return this.baseMapper.selectList(queryWrapper);
	}

	@Override
	public List<DataDict> getDicByDicId(String dicId,boolean isDic) {
		QueryWrapper<DataDict> queryWrapper = new QueryWrapper();
		queryWrapper.eq("dic_id_", dicId);
		if(!isDic){
			queryWrapper.eq("type_","val");
		}
		queryWrapper.orderByAsc("sn_");
		return this.baseMapper.selectList(queryWrapper);
	}

	@Override
	public List<DataDict> getByDicKey(String dicKey) {
		Assert.hasText(dicKey, "字典项编码不能为空");
		return this.baseMapper.getByDicKey(dicKey);
	}

	@Override
	@Transactional(rollbackFor = Exception.class )
	public Boolean moveDic(List<String> ids, String gId, String type) {
		Assert.hasText(gId, "目标ID不能为空");
		Assert.hasText(type, "移动类型不能为空");
		if(CollectionUtils.isEmpty(ids)){
			throw new ApplicationException("请选择要移动的字典项！");
		}
		String tenantId = baseContext.getCurrentTenantId();
		redisUtil.del(CacheKeyConst.SYS_DIMENSION_DICT + ":" + tenantId);
		UpdateWrapper<DataDict> updateWrapper =new UpdateWrapper<>();
		if(type.equals("dic")){
			updateWrapper.set("type_id_", gId).in("dic_id_",ids);
			UpdateWrapper<DataDict> dictUpdateWrapper =new UpdateWrapper<>();
			dictUpdateWrapper.set("parent_id_", gId).in("id_",ids);
			this.update(dictUpdateWrapper);

			return 	this.update(updateWrapper);
		}else if(type.equals("val")){
			DataDict parentDic = this.getById(gId);
			if(parentDic==null){
				throw new ApplicationException("没有找到要移动到的字典项，请核实！");
			}
			updateWrapper.set("parent_id_", gId).set("type_id_", parentDic.getTypeId()).set("dic_id_", parentDic.getDicId()).in("id_",ids);
			return 	this.update(updateWrapper);
		}
		return 	false;
	}


	@Override
	public DataDict getByKey(String type, String key, String dicId) {
		QueryWrapper<DataDict> queryWrapper = new QueryWrapper();
		queryWrapper.eq(StringUtil.isNotEmpty(dicId),"dic_id_", dicId);
		queryWrapper.eq("type_",type);
		queryWrapper.eq("key_",key);
		List<DataDict> list = this.baseMapper.selectList(queryWrapper);
		if(CollectionUtils.isEmpty(list)){
			return null;
		}
		return list.get(0);
	}

	@Override
	public DataDict getByDictKey(String typeId, String key) {
		Map<String, Object> params = new HashMap<>();
		params.put("typeId", typeId);
		params.put("key", key);
		return baseMapper.getByDictKey(params);
	}
	
	@Override
	public void removeByIds(String ...ids) {
		String tenantId = baseContext.getCurrentTenantId();
		redisUtil.del(CacheKeyConst.SYS_DIMENSION_DICT + ":" + tenantId);

		if(BeanUtils.isNotEmpty(ids)){
			for(String id : ids){
				this.remove(id);
				List<DataDict> childs = getChildrenByParentId(id);
				for(DataDict dict : childs){
					this.remove(dict.getId());
				}
				
			}
		}
		super.removeByIds(ids);
	}
	/**
	 * 获取一级子节点
	 * @param id
	 * @return
	 */
	@Override
	public List<DataDict> getFirstChilsByParentId(String id){
		return baseMapper.getByParentId(id);
	}
	/**
	 * 获取所有的子节点
	 * @param id
	 * @return
	 */
	@Override
	public List<DataDict> getChildrenByParentId(String id){
		List<DataDict> childs = baseMapper.getByParentId(id);
		return getChilds(childs);
	}
	/**
	 * 通过子节点查询子节点
	 * @param childs
	 * @return
	 */
	private List<DataDict> getChilds(List<DataDict> childs){
		List<DataDict> dataDict = new ArrayList<DataDict>();
		// 如果孩子不为空 查询孩子的孩子
		if(BeanUtils.isNotEmpty(childs)){
			for(DataDict dict : childs){
				List<DataDict> children =  baseMapper.getByParentId(dict.getId());  
				//如果孩子的孩子们不为空  则通过孩子们 查询他们的孩子们
				if(BeanUtils.isNotEmpty(children)){
					children = getChilds(children);
					dataDict.addAll(children);
				}
				
			}
			dataDict.addAll(childs);
		}
		return dataDict;
	}
	@Override
	public void delByDictTypeId(String dictTypeId) {
		String tenantId = baseContext.getCurrentTenantId();
		redisUtil.del(CacheKeyConst.SYS_DIMENSION_DICT + ":" + tenantId);
		baseMapper.delByDictTypeId(dictTypeId);
	}
	
	/**
	 * 更新排序  sn
	 * @param dicId
	 * @param sn
	 */
	@Override
	public void updSn(String dicId, int sn) {
		Map<String, Object> params = new HashMap<>();
		params.put("id", dicId);
		params.put("sn", sn);
		baseMapper.updSn(params);
	}
	@Override
	public CommonResult<String> removeByTypeIds(String typeIds) {
		if (StringUtil.isNotEmpty(typeIds)) {
			List<SysType> typeList = sysTypeManager.getChildByTypeId(typeIds);
			String[] typeIdList = new String[typeList.size()+1];
			typeIdList[0] = typeIds;
			for (int i = 0; i < typeList.size(); i++) {
				typeIdList[i+1] = typeList.get(i).getId();
			}
			sysTypeManager.removeByIds(typeIdList);
			for (String typeId : typeIdList) {
				baseMapper.delByDictTypeId(typeId);
			}
			String tenantId = baseContext.getCurrentTenantId();
			redisUtil.del(CacheKeyConst.SYS_DIMENSION_DICT + ":" + tenantId);
		}
		return new CommonResult<>("操作成功");
	}
	@Override
	@Transactional
	public void importData(List<MultipartFile> files, String typeId) throws Exception {
		Iterator<MultipartFile> it = files.iterator();
		Map<String, DataDict> data = new HashMap<String, DataDict>();
		//数据字典分类
		SysType sysType = sysTypeManager.get(typeId);
		if(BeanUtils.isEmpty(sysType)) {
			throw new BaseException("请选择数据字典分类进行导入");
		}
		while (it.hasNext()) {
			MultipartFile file = it.next();
			List<DataDictDatalExcelVo> list= ExcelUtil.readExcel(DataDictDatalExcelVo.class,file);
			LinkedList<DataDict> dataDictBuffer = new LinkedList<>();
			for (DataDictDatalExcelVo vo:list) {
				String pKey = vo.getPidKey();
				String key = vo.getKey();
				String name = vo.getName();
				Map<String, Object> params = new HashMap<>();
				params.put("typeId", typeId);
				params.put("key", key);
				// 验证字典key 是否已经存在
				DataDict dict= baseMapper.getByDictKey(params);
				if(dict != null){
					throw new BaseException("该字典项值已经存在");
				}
				
				DataDict dataDict = new DataDict();
				dataDict.setTypeId(typeId);
				if(StringUtil.isEmpty(pKey)) {
					dataDict.setParentId(typeId);
				}else {
					//
					Map<String, Object> pMap = new HashMap<>();
					pMap.put("typeId", typeId);
					pMap.put("key", pKey);
					
					DataDict dtDict= baseMapper.getByDictKey(pMap);
					if(BeanUtils.isEmpty(dtDict)) {
						//从添加的列表中获取
						DataDict dmDict = data.get(pKey);
						if(BeanUtils.isEmpty(dmDict)) {
							if(isParentKeyInList(pKey,list)){
								//将父亲节点尚未生成的元素放入一个缓冲队列中
								dataDict.setParentId(pKey);
								dataDict.setKey(key);
								dataDict.setName(name);
								dataDictBuffer.add(dataDict);
								continue;
							}else{
								throw new BaseException("请输入正确的父节点key");
							}
						}else {
							dataDict.setParentId(dmDict.getId());
						}
					}
					dataDict.setParentId(dtDict.getId());
				}
				dataDict.setKey(key);
				dataDict.setName(name);
				this.create(dataDict);
				//添加列表
				data.put(key, dataDict);
			}
			//循环处理dataDictBuffer
			handleSaveBuffer(dataDictBuffer,data);
			/*for (DataDict dataDict : dataDictBuffer) {
				String parentKey = dataDict.getParentId();
				DataDict parent = data.get(parentKey);
				if(BeanUtils.isEmpty(parent)){
					throw new BaseException("请输入正确的父节点");
				}
				dataDict.setParentId(parent.getId());
				this.create(dataDict);
			}*/
		}
		String tenantId = baseContext.getCurrentTenantId();
		redisUtil.del(CacheKeyConst.SYS_DIMENSION_DICT + ":" + tenantId);
	}

	@Override
	@Transactional
	public void importDic(MultipartFile file) throws Exception {
		List<DataDictExcelVo> list= ExcelUtil.readExcel(DataDictExcelVo.class,file);
		List<DataDict> saveList = new ArrayList<>();
		for (DataDictExcelVo vo:list) {
			String typeCode = vo.getTypeCode();
			//SysType sysType=sysTypeManager.getByKey(typeCode);
			SysType sysType = sysTypeManager.getByTypeKeyAndGroupKey("dic", typeCode);
			if(sysType!=null){
				DataDict dict = this.getByKey("dic", vo.getKey(),"");
				if (dict != null) {
					continue;
				}
				DataDict dataDict = new DataDict();
				dataDict.setId(idGenerator.getSuid());
				dataDict.setKey(vo.getKey());
				dataDict.setName(vo.getName());
				dataDict.setType("dic");
				dataDict.setTypeId(sysType.getId());
				dataDict.setParentId(sysType.getId());
				dataDict.setDicId(dataDict.getId());
				dataDict.setSn(Integer.valueOf(vo.getSn()));
				saveList.add(dataDict);
			}
		}
		if(!CollectionUtils.isEmpty(saveList)){
			this.saveBatch(saveList);
			String tenantId = baseContext.getCurrentTenantId();
			redisUtil.del(CacheKeyConst.SYS_DIMENSION_DICT + ":" + tenantId);
		}
	}

	/*
	* 判断父节点在DataDictExcelVo中是否存在
	* */
	private boolean isParentKeyInList(String parentKey,List<DataDictDatalExcelVo> list){
		if(StringUtil.isEmpty(parentKey) || BeanUtils.isEmpty(list)){
			return false;
		}
		for (DataDictDatalExcelVo dataDictDatalExcelVo : list) {
			if (parentKey.equals(dataDictDatalExcelVo.getPidKey())) {
				return true;
			}
		}
		return false;
	}

	private void handleSaveBuffer(LinkedList<DataDict> list,Map<String,DataDict> data){
		if(BeanUtils.isEmpty(list)){
			return ;
		}
		int size = list.size();
		int count = 0;
		//出队又入队的次数，连续出队入队次数超过队列长度，则可以认为进入了死循环。
		//如果循环一遍，一个元素都没有被处理，则直接跳出循环
		while(list.size() > 0){
			//队首取，队尾插入
			DataDict dataDict = list.removeFirst();
			String parentKey = dataDict.getParentId();
			DataDict parent = data.get(parentKey);
			//父节点尚未生成，将此元素放到队尾
			if(BeanUtils.isEmpty(parent)){
				list.addLast(dataDict);
				count++;
				if(count > size){
					throw new BaseException("导入失败，请检查excel数据是否正确");
				}
			}else{
				dataDict.setParentId(parent.getId());
				this.create(dataDict);
				data.put(dataDict.getKey(),dataDict);
				//重置count和size
				size = list.size();
				count = 0;
			}
		}
	}

}
