package com.yifu.cloud.plus.v1.yifu.archives.service.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.read.metadata.holder.ReadRowHolder;
import com.alibaba.excel.util.ListUtils;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yifu.cloud.plus.v1.yifu.admin.api.entity.SysUser;
import com.yifu.cloud.plus.v1.yifu.archives.entity.TCutsomerDataPermisson;
import com.yifu.cloud.plus.v1.yifu.archives.entity.TSettleDomain;
import com.yifu.cloud.plus.v1.yifu.archives.mapper.TCutsomerDataPermissonMapper;
import com.yifu.cloud.plus.v1.yifu.archives.mapper.TSettleDomainMapper;
import com.yifu.cloud.plus.v1.yifu.archives.service.TCutsomerDataPermissonService;
import com.yifu.cloud.plus.v1.yifu.archives.vo.DataPermissionImportVo;
import com.yifu.cloud.plus.v1.yifu.common.core.constant.CacheConstants;
import com.yifu.cloud.plus.v1.yifu.common.core.constant.CommonConstants;
import com.yifu.cloud.plus.v1.yifu.common.core.util.*;
import com.yifu.cloud.plus.v1.yifu.common.core.vo.YifuUser;
import com.yifu.cloud.plus.v1.yifu.common.dapr.config.DaprUpmsProperties;
import com.yifu.cloud.plus.v1.yifu.common.dapr.util.UpmsDaprUtils;
import lombok.AllArgsConstructor;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.shardingsphere.transaction.annotation.ShardingTransactionType;
import org.apache.shardingsphere.transaction.core.TransactionType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.InputStream;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;


/**
 * 客户数据权限表
 *
 * @author pwang
 * @date 2019-07-19 11:42:58
 */

@Service
@RequiredArgsConstructor
@EnableConfigurationProperties(DaprUpmsProperties.class)
@AllArgsConstructor
@Slf4j
public class TCutsomerDataPermissonServiceImpl extends ServiceImpl<TCutsomerDataPermissonMapper, TCutsomerDataPermisson> implements TCutsomerDataPermissonService {
	@Autowired
	private UpmsDaprUtils upmsDaprUtils;
	@Autowired
	private TSettleDomainMapper domainMapper;
	@Autowired
	private RedisUtil redisUtil;
	/**
	 * 客户数据权限表简单分页查询
	 *
	 * @param tCutsomerDataPermisson 客户数据权限表
	 * @return
	 */
	@Override
	public IPage<TCutsomerDataPermisson> getTCutsomerDataPermissonPage(Page<TCutsomerDataPermisson> page, TCutsomerDataPermisson tCutsomerDataPermisson) {
		return baseMapper.getTCutsomerDataPermissonPage(page, tCutsomerDataPermisson);
	}

	@Override
	public List<TCutsomerDataPermisson> getTCutsomerDataPermissonList(TCutsomerDataPermisson tCutsomerDataPermisson) {
		return baseMapper.getTCutsomerDataPermissonPage(tCutsomerDataPermisson);
	}

	@Override
	@Transactional
	public R<String> insertForCopyCutsomerDataPermisson(String[] srcUser, String[] beUser, YifuUser user) {
		if(Common.isEmpty(srcUser)){
			return R.failed("请选择要被复制人！") ;
		}
		if(Common.isEmpty(beUser)){
			return R.failed("请选择被授权的人！") ;
		}
		if(beUser.length > 1){
			return R.failed("为了避免权限混乱，暂时只支持权限复制给某一个人！") ;
		}
		List<TCutsomerDataPermisson> list = baseMapper.selectList(Wrappers.<TCutsomerDataPermisson>lambdaQuery().eq(TCutsomerDataPermisson::getUserId, srcUser[0]));
		Collection<TCutsomerDataPermisson> saveColl;
		if(Common.isNotNull(list)){
			LocalDateTime now = LocalDateTime.now();
			for(String userId : beUser){
				saveColl = getSaveDataPermissonList(user, list, now, userId);
				if(Common.isNotNull(saveColl)){
					this.saveBatch(saveColl);
				}
			}
		}else{
			return R.failed("未查到要被复制人的权限表数据，请换个人复制权限") ;
		}
		return  R.ok("操作成功");
	}
	/**
	 * 获取要新增的权限集合
	 * @Author pwang
	 * @Date 2020-09-27 17:24
	 * @param user
	 * @param list
	 * @param now
	 * @param userId
	 * @return
	 **/
	private Collection<TCutsomerDataPermisson> getSaveDataPermissonList(YifuUser user, List<TCutsomerDataPermisson> list, LocalDateTime now, String userId) {
		Collection<TCutsomerDataPermisson> result = new HashSet<>();
		Map<String, TCutsomerDataPermisson> settleDomianDataPermissonMap = new HashMap<>();
		List<TCutsomerDataPermisson> oldPermisson = baseMapper.selectList(Wrappers.<TCutsomerDataPermisson>lambdaQuery().eq(TCutsomerDataPermisson::getUserId, userId));
		//被复制的权限去重
		for(TCutsomerDataPermisson cdp : list){
			cdp.setId(null);
			cdp.setUserId(userId);
			// 注意 :人员部门、登录名等没加
			cdp.setType(CommonConstants.TWO_STRING);
			cdp.setCreateBy(user.getId());
			cdp.setCreateName(user.getNickname());
			cdp.setCreateTime(now);
			settleDomianDataPermissonMap.put(cdp.getSettleDomainId(),cdp);
		}
		//去除本身有的权限
		for(TCutsomerDataPermisson cdp : oldPermisson){
			settleDomianDataPermissonMap.remove(cdp.getSettleDomainId());
		}
		if(Common.isNotNull(settleDomianDataPermissonMap.values())){
			result.addAll(settleDomianDataPermissonMap.values());
		}
		return result;
	}


	@Override
	public boolean save(TCutsomerDataPermisson cutsomerDataPermisson){
		return super.save(cutsomerDataPermisson);
	}
	/**
	 * @Author fxj
	 * @Description 批量导入项目权限
	 * @Date 16:59 2023/10/17
	 * @Param
	 * @return
	 **/
	@Transactional(rollbackFor = Exception.class)
	@ShardingTransactionType(TransactionType.BASE)
	@Override
	public R<List<ErrorMessage>> importDiy(InputStream inputStream) {
		List<ErrorMessage> errorMessageList = new ArrayList<>();
		ExcelUtil<DataPermissionImportVo> util1 = new ExcelUtil<>(DataPermissionImportVo.class);
		List<TSettleDomain> settleDomains  = domainMapper.getAllInfoMap();
		Map<String, TSettleDomain> domainMap = null;
		if (Common.isNotNull(settleDomains)){
			domainMap = settleDomains.stream().collect(Collectors.toMap(k->k.getDepartNo(),k->k));
		}
		if (Common.isEmpty(domainMap)){
			domainMap = new HashMap<>();
		}
		Map<String,SysUser> userMap = new HashMap<>();
		Map<String,String> existMap = new HashMap<>();
		// 写法2：
		// 匿名内部类 不用额外写一个DemoDataListener
		// 这里 需要指定读用哪个class去读，然后读取第一个sheet 文件流会自动关闭
		try {
			Map<String, TSettleDomain> finalDomainMap = domainMap;
			EasyExcel.read(inputStream, DataPermissionImportVo.class, new ReadListener<DataPermissionImportVo>() {
				/**
				 * 单次缓存的数据量
				 */
				public static final int BATCH_COUNT = CommonConstants.BATCH_COUNT;
				/**
				 *临时存储
				 */
				private List<DataPermissionImportVo> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);

				@Override
				public void invoke(DataPermissionImportVo data, AnalysisContext context) {
					ReadRowHolder readRowHolder = context.readRowHolder();
					Integer rowIndex = readRowHolder.getRowIndex();
					data.setRowIndex(rowIndex+1);
					ErrorMessage errorMessage = util1.checkEntity(data, data.getRowIndex());
					if (Common.isNotNull(errorMessage)){
						errorMessage.setData(data);
						errorMessageList.add(errorMessage);
					}else {
						cachedDataList.add(data);
					}
					if (cachedDataList.size() >= BATCH_COUNT) {
						saveData();
						// 存储完成清理 list
						cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
					}
				}
				@Override
				public void doAfterAllAnalysed(AnalysisContext context) {
					saveData();
				}

				/**
				 * 加上存储数据库
				 */
				private void saveData() {
					log.info("{}条数据，开始存储数据库！", cachedDataList.size());
					importEntity(cachedDataList,errorMessageList, finalDomainMap,userMap,existMap);
					log.info("存储数据库成功！");
				}
			}).sheet().doRead();
		}catch (Exception e){
			log.error(CommonConstants.IMPORT_DATA_ANALYSIS_ERROR,e);
			return R.failed(CommonConstants.IMPORT_DATA_ANALYSIS_ERROR);
		}finally {
			// 清理
			domainMap.clear();
		}
		return   judgeAllMessage(errorMessageList);
	}
	/**
	 * @Author fxj
	 * @Description 判断所有返回数据，是否全部为正确的
	 * @Date 18:01 2023/10/18
	 * @Param
	 * @return
	 **/
	private R<List<ErrorMessage>> judgeAllMessage(List<ErrorMessage> errorMessageList) {
		if (!errorMessageList.isEmpty() && errorMessageList.stream().noneMatch(e-> e.getColor().equals(CommonConstants.RED))) {
			return R.ok();
		}
		return R.ok(errorMessageList);
	}
	private void importEntity(List<DataPermissionImportVo> excelVOList,
							  List<ErrorMessage> errorMessageList,
							  Map<String,TSettleDomain> domainMap,
							  Map<String,SysUser> userMap,
							  Map<String,String> existMap) {
		// 执行数据插入操作 组装
		TCutsomerDataPermisson permission = null;
		SysUser user;
		R<SysUser> res;
		TSettleDomain  domain;
		TCutsomerDataPermisson exist;
		String temp;
		DataPermissionImportVo excel;
		for (int i = 0; i < excelVOList.size(); i++) {
			excel = excelVOList.get(i);
			// 数据合法情况
			user = userMap.get(excel.getUserLoginName());
			// 用户信息验证
			if (Common.isEmpty(user)){
				res = upmsDaprUtils.getSimpleUserByLoginName(excel.getUserLoginName());
				if (Common.isNotNull(res) && Common.isNotNull(res.getData())){
					user = res.getData();
					userMap.put(user.getUsername(),user);
				}else {
					errorMessageList.add(new ErrorMessage(excel.getRowIndex(),CommonConstants.USER_FAIL,excel));
					continue;
				}
			}
			if (Common.isEmpty(user.getDeptName())){
				errorMessageList.add(new ErrorMessage(excel.getRowIndex(),"对应登录账号无部门信息，请完善后导入",excel));
				continue;
			}
			// 项目信息验证
			domain = domainMap.get(excel.getSettleDomainNo());
			if (Common.isEmpty(domain)){
				errorMessageList.add(new ErrorMessage(excel.getRowIndex(),CommonConstants.SETTLE_DOMAIN_NOT_EXIST,excel));
				continue;
			}
			// 重复校验
			temp = existMap.get(excel.getUserLoginName()+CommonConstants.DOWN_LINE_STRING+excel.getSettleDomainNo());
			if (Common.isNotNull(temp)){
				errorMessageList.add(new ErrorMessage(excel.getRowIndex(),"对应账号的权限已存在，请勿重复导入",excel));
				continue;
			}else {
				exist = baseMapper.selectOne(Wrappers.<TCutsomerDataPermisson>query().lambda()
						.eq(TCutsomerDataPermisson::getSettleDomainNo,excel.getSettleDomainNo())
						.eq(TCutsomerDataPermisson::getUserLoginName,excel.getUserLoginName())
						.last(CommonConstants.LAST_ONE_SQL));
				if (Common.isNotNull(exist)){
					errorMessageList.add(new ErrorMessage(excel.getRowIndex(),"对应账号的权限已存在，请勿重复导入",excel));
					continue;
				}
			}
			// 初始化及新增数据
			permission = new TCutsomerDataPermisson();
			permission.setType(CommonConstants.ONE_STRING);
			permission.setSettleDomainId(domain.getId());
			permission.setRemark("批量授权");
			permission.setSettleDomainName(domain.getDepartName());
			permission.setSettleDomainNo(domain.getDepartNo());
			permission.setStatus(CommonConstants.ZERO_STRING);
			permission.setUserId(user.getUserId());
			permission.setUserDeptName(user.getDeptName());
			permission.setUserLoginName(user.getUsername());
			permission.setUserNickName(user.getNickname());
			insertExcel(permission);
			// 加入map 验证当前表单数据是否重复
			existMap.put(excel.getUserLoginName()+CommonConstants.DOWN_LINE_STRING+excel.getSettleDomainNo(),excel.getSettleDomainNo());
			errorMessageList.add(new ErrorMessage(excel.getRowIndex(),CommonConstants.SAVE_SUCCESS,CommonConstants.GREEN,excel));
			// 清理缓存
			redisUtil.remove(CacheConstants.WXHR_SETTLE_DOMAIN_VOS_BY_USERID +"_"+user.getUserId());
			redisUtil.remove(CacheConstants.WXHR_SETTLE_DOMAIN_NOS_BY_USERID +"_"+user.getUserId());
		}
	}
	/**
	 * 插入excel bad record
	 */
	private void insertExcel(TCutsomerDataPermisson entity) {
		this.save(entity);
	}
}
