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

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.check.entity.TCanCheck;
import com.yifu.cloud.plus.v1.check.entity.TCheckApiNum;
import com.yifu.cloud.plus.v1.check.entity.TCheckIdCard;
import com.yifu.cloud.plus.v1.check.entity.TCheckLock;
import com.yifu.cloud.plus.v1.check.mapper.TCheckIdCardMapper;
import com.yifu.cloud.plus.v1.check.service.TCanCheckService;
import com.yifu.cloud.plus.v1.check.service.TCheckApiNumService;
import com.yifu.cloud.plus.v1.check.service.TCheckIdCardService;
import com.yifu.cloud.plus.v1.check.service.TCheckLockService;
import com.yifu.cloud.plus.v1.check.utils.ChecksUtil;
import com.yifu.cloud.plus.v1.yifu.common.core.constant.CommonConstants;
import com.yifu.cloud.plus.v1.yifu.common.core.util.Common;
import com.yifu.cloud.plus.v1.yifu.common.core.util.DateUtil;
import com.yifu.cloud.plus.v1.yifu.common.core.util.R;
import com.yifu.cloud.plus.v1.yifu.common.core.vo.YifuUser;
import com.yifu.cloud.plus.v1.yifu.common.security.util.SecurityUtils;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 身份证实名校验自留库
 *
 * @author hgw
 * @date 2022-05-11 16:12:18
 */
@AllArgsConstructor
@Service
public class TCheckIdCardServiceImpl extends ServiceImpl<TCheckIdCardMapper, TCheckIdCard> implements TCheckIdCardService {

     private final TCheckLockService tCheckLockService;
     private final TCheckApiNumService tCheckApiNumService;

	 private final TCanCheckService canCheckService;

     /**
      * 身份证实名校验自留库简单分页查询
      *
      * @param tCheckIdCard 身份证实名校验自留库
      * @return
      */
     @Override
     public IPage<TCheckIdCard> getTCheckIdCardPage(Page<TCheckIdCard> page, TCheckIdCard tCheckIdCard) {
          return baseMapper.getTCheckIdCardPage(page, tCheckIdCard);
     }

     @Override
     public List<TCheckIdCard> getAllList(TCheckIdCard tCheckIdCard) {
          return baseMapper.getAllList(tCheckIdCard);
     }

     @Override
     public Map<String, TCheckIdCard> getAllMap(TCheckIdCard tCheckIdCard) {
          List<TCheckIdCard> list = baseMapper.getAllList(tCheckIdCard);
          Map<String, TCheckIdCard> returnMap = new HashMap<>();
          if (list != null && !list.isEmpty()) {
               for (TCheckIdCard c : list) {
                    returnMap.put(c.getIdCard() + CommonConstants.DOWN_LINE_STRING + c.getName(), c);
               }
          }
          return returnMap;
     }

     /**
      * @param checkList
      * @Description: 校验
      * @Author: hgw
      * @Date: 2022/5/12 15:47
      * @return: com.yifu.cloud.v1.common.core.util.R<java.util.List < com.yifu.cloud.v1.checks.api.entity.TCheckIdCard>>
      **/
     @Override
     public synchronized R<List<TCheckIdCard>> checkIdCard(List<TCheckIdCard> checkList) {
          YifuUser user = SecurityUtils.getUser();
          if (user == null || Common.isEmpty(user.getId())) {
               return R.failed("请登录！");
          }
          List<TCheckLock> lockList = tCheckLockService.getAllList();
          if (lockList != null && !lockList.isEmpty()) {
               return R.failed("当前有用户在导入中，请稍后！或联系管理员处理表TCheckLock数据和重启校验服务");
          }
          String nowMonth = DateUtil.addMonth(0);
          TCheckApiNum nowMonthNum = tCheckApiNumService.getById(nowMonth);
          if (nowMonthNum == null) {
               TCheckApiNum lastMonth = tCheckApiNumService.getById(DateUtil.addMonth(-1));
               int canApiNum = 10000;
               if (lastMonth != null && lastMonth.getCanApiNum() != null) {
                    canApiNum = lastMonth.getCanApiNum();
               }
               nowMonthNum = new TCheckApiNum();
               nowMonthNum.setId(nowMonth);
               nowMonthNum.setCanApiNum(canApiNum);
               nowMonthNum.setApiNum(0);
               tCheckApiNumService.save(nowMonthNum);
          } else if (nowMonthNum.getApiNum() >= nowMonthNum.getCanApiNum()) {
               return R.failed("当月总条数：" + nowMonthNum.getCanApiNum() + "已到达上限!");
          }
          if (checkList != null && !checkList.isEmpty()) {
               TCheckLock lock = new TCheckLock();
               lock.setImportNum(checkList.size());
               lock.setApiNum(0);
               lock.setCreateMonth(nowMonth);
               lock.setCreateTime(LocalDateTime.now());
               lock.setCreateUser(String.valueOf(user.getId()));
               lock.setDeleteFlag(0);
               lock.setCreateUserName(user.getNickname());
               tCheckLockService.save(lock);
               int nowApiNum = 0;
               int canApiNum = nowMonthNum.getCanApiNum();

               Map<String, TCheckIdCard> returnMap = this.getAllMap(null);
               TCheckIdCard nowIdCard;
               TCheckIdCard lastCard;
               Map<String, TCheckIdCard> idCardMap = new HashMap<>();
               String userId = String.valueOf(user.getId());
               TCheckLock lockUpdate;
               try {
                    for (TCheckIdCard c : checkList) {
                         if (Common.isNotNull(c.getIdCard()) && Common.isNotNull(c.getName())) {
                              lastCard = idCardMap.get(c.getIdCard());
                              if (lastCard != null) {
                                   c.setIsTrue(lastCard.getIsTrue());
                                   c.setReason(lastCard.getReason());
                              } else {
                                   // 校验姓名身份证规则
                                   if (!regIdCard(c.getIdCard())) {
                                        c.setIsTrue(0);
                                        c.setReason("身份证格式有误");
                                   } else if (regEmpName(c.getName())) {
                                        c.setIsTrue(0);
                                        c.setReason("姓名含数字或空格，无法校验");
                                   } else {
                                        nowIdCard = returnMap.get(c.getIdCard() + CommonConstants.DOWN_LINE_STRING + c.getName());
                                        if (nowIdCard != null) {
                                             c.setIsTrue(nowIdCard.getIsTrue());
                                             c.setReason(nowIdCard.getReason());
                                        } else {
                                             // 调用API校验
                                             if (nowApiNum < canApiNum) {
                                                  nowApiNum++;
                                                  ChecksUtil.checkIdCard(c,canCheckService.getCanCheck());
                                                  c.setCreateUser(userId);
                                                  c.setCreateTime(LocalDateTime.now());
                                                  c.setType(CommonConstants.ONE_INT);
                                                  returnMap.put(c.getIdCard() + CommonConstants.DOWN_LINE_STRING + c.getName(), c);
                                                  this.save(c);
                                                  nowMonthNum.setApiNum(nowMonthNum.getApiNum() + 1);
                                                  tCheckApiNumService.updateById(nowMonthNum);
                                             } else {
                                                  c.setIsTrue(0);
                                                  c.setReason("调用花钱的Api的条数已达上限：" + nowMonthNum.getCanApiNum() + "，请联系管理员处理！");
                                             }
                                        }
                                   }
                                   // 将同身份证的结果存储下来备用，防止撞库
                                   idCardMap.put(c.getIdCard(), c);
                              }
                         } else {
                              c.setIsTrue(0);
                              c.setReason("姓名身份证不可为空");
                         }
                    }
               } catch (Exception e) {
                    lockUpdate = new TCheckLock();
                    lockUpdate.setId(lock.getId());
                    lockUpdate.setDeleteFlag(CommonConstants.ONE_INT);
                    lockUpdate.setApiNum(nowApiNum);
                    tCheckLockService.updateById(lockUpdate);
                    throw new RuntimeException(e.getMessage() == null ? "校验身份证导入失败！" : "校验身份证导入失败：" + e.getMessage());
               } finally {
                    lockUpdate = new TCheckLock();
                    lockUpdate.setId(lock.getId());
                    lockUpdate.setDeleteFlag(CommonConstants.ONE_INT);
                    lockUpdate.setDeleteFlag(CommonConstants.ONE_INT);
                    lockUpdate.setApiNum(nowApiNum);
                    tCheckLockService.updateById(lockUpdate);
               }
               return new R<>(checkList);
          }
          return R.failed("数据为空！");
     }

	/**
      * @param content
      * @Description: 判断身份证格式：18位数字，17位数字+X，15位数字，14位数字+X
      * 格式正确返回true
      * @Author: hgw
      * @Date: 2022/5/13 11:53
      * @return: boolean
      **/
     private static boolean regIdCard(String content) {
          boolean flag = false;
          Pattern p = Pattern.compile("\\d{18}|\\d{17}X|\\d{15}|\\d{14}X");
          Matcher m = p.matcher(content);
          if (m.matches()) {
               flag = true;
          }
          return flag;
     }

     /**
      * @param content
      * @Description: 含数字，返回true
      * @Author: hgw
      * @Date: 2022/5/13 11:54
      * @return: boolean
      **/
     private static boolean regEmpName(String content) {
          boolean flag = false;
          Pattern p = Pattern.compile(".*\\d+.*|.*\\s+.*");
          Matcher m = p.matcher(content);
          if (m.matches()) {
               flag = true;
          }
          return flag;
     }

	@Override
	public TCheckIdCard checkIdCardSingle(TCheckIdCard tCheckIdCard) {
		tCheckIdCard.setIsTrue(CommonConstants.ZERO_INT);
		String idCard = tCheckIdCard.getIdCard();
		String name = tCheckIdCard.getName();
		if (Common.isEmpty(idCard) || Common.isEmpty(name)){
			tCheckIdCard.setIsTrue(CommonConstants.ZERO_INT);
			tCheckIdCard.setReason(CommonConstants.PARAM_IS_NOT_EMPTY);
			return tCheckIdCard;
		}
		// 校验姓名身份证规则
		if (!regIdCard(idCard)) {
			tCheckIdCard.setIsTrue(CommonConstants.ZERO_INT);
			tCheckIdCard.setReason("身份证格式有误");
			return tCheckIdCard;
		} else if (regEmpName(name)) {
			tCheckIdCard.setIsTrue(CommonConstants.ZERO_INT);
			tCheckIdCard.setReason("姓名含数字或空格，无法校验");
			return tCheckIdCard;
		}
		synchronized (this){
			TCheckIdCard checkIdCard = baseMapper.selectOne(Wrappers.<TCheckIdCard>query().lambda()
					.eq(TCheckIdCard::getIdCard,idCard)
					.eq(TCheckIdCard::getIsTrue,CommonConstants.ONE_INT)
					.last(CommonConstants.LAST_ONE_SQL));
			if (Common.isNotNull(checkIdCard)){
				if (name.equals(checkIdCard.getName())) {
					tCheckIdCard.setIsTrue(CommonConstants.ONE_INT);
				} else {
					tCheckIdCard.setIsTrue(CommonConstants.ZERO_INT);
					tCheckIdCard.setReason("姓名与身份证不一致，禁止添加");
				}
				return tCheckIdCard;
			} else {
				// 没找到正确的，再去找有没有错误的，如果还没有，再查
				List<TCheckIdCard> checkList = baseMapper.selectList(Wrappers.<TCheckIdCard>query().lambda()
						.eq(TCheckIdCard::getIdCard,idCard));
				if (checkList != null && !checkList.isEmpty()) {
					for (TCheckIdCard  c : checkList) {
						if (idCard.equals(c.getIdCard()) && name.equals(c.getName())) {
							tCheckIdCard.setIsTrue(CommonConstants.ZERO_INT);
							tCheckIdCard.setReason(c.getReason());
							return tCheckIdCard;
						}
					}
				}
				TCheckIdCard  c = new TCheckIdCard();
				c.setIdCard(idCard);
				c.setName(name);
				ChecksUtil.checkIdCard(c,canCheckService.getCanCheck());
				baseMapper.insert(c);
				tCheckIdCard.setIsTrue(c.getIsTrue());
				tCheckIdCard.setReason(c.getReason());
				return tCheckIdCard;
			}
		}
	}

	private Map<String, TCheckIdCard> getAllMapByList(List<String> idCardList) {
		Map<String, TCheckIdCard> returnMap = new HashMap<>();
		if (idCardList != null && !idCardList.isEmpty()) {
			List<TCheckIdCard> list = baseMapper.getAllListByList(idCardList);
			if (list != null && !list.isEmpty()) {
				for (TCheckIdCard c : list) {
					returnMap.put(c.getIdCard() + CommonConstants.DOWN_LINE_STRING + c.getName(), c);
				}
			}
		}
		return returnMap;
	}

	private Map<String, TCheckIdCard> getTrueMap(TCheckIdCard tCheckIdCard) {
		if (tCheckIdCard == null) {
			tCheckIdCard = new TCheckIdCard();
		}
		tCheckIdCard.setIsTrue(CommonConstants.ONE_INT);
		List<TCheckIdCard> list = baseMapper.getAllList(tCheckIdCard);
		Map<String, TCheckIdCard> returnMap = new HashMap<>();
		if (list != null && !list.isEmpty()) {
			for (TCheckIdCard c : list) {
				returnMap.put(c.getIdCard(), c);
			}
		}
		return returnMap;
	}

	private Map<String, TCheckIdCard> getTrueMapByList(List<String> idCardList) {
		Map<String, TCheckIdCard> returnMap = new HashMap<>();
		if (idCardList != null && !idCardList.isEmpty()) {
			List<TCheckIdCard> list = baseMapper.getTrueListByList(idCardList);
			if (list != null && !list.isEmpty()) {
				for (TCheckIdCard c : list) {
					returnMap.put(c.getIdCard(), c);
				}
			}
		}
		return returnMap;
	}

	@Override
	public R<List<TCheckIdCard>> checkSalaryIdCard(List<TCheckIdCard> checkList) {
		TCanCheck tCanCheck= canCheckService.getById(1);
		boolean canCheck = false;
		if (tCanCheck != null && tCanCheck.getCanCheck() == 1) {
			canCheck  = true;
		}
		YifuUser user = SecurityUtils.getUser();
		if (user == null || Common.isEmpty(user.getId())) {
			return R.failed("请登录！");
		}
		String nowMonth = DateUtil.addMonth(0);
		TCheckApiNum nowMonthNum = tCheckApiNumService.getById(nowMonth);
		int nowApiNum = tCheckLockService.getApiNumByMonth(nowMonth);
		if (nowMonthNum == null) {
			TCheckApiNum lastMonth = tCheckApiNumService.getById(DateUtil.addMonth(-1));
			int canApiNum = 10000;
			if (lastMonth != null && lastMonth.getCanApiNum() != null) {
				canApiNum = lastMonth.getCanApiNum();
			}
			nowMonthNum = new TCheckApiNum();
			nowMonthNum.setId(nowMonth);
			nowMonthNum.setCanApiNum(canApiNum);
			nowMonthNum.setApiNum(0);
			tCheckApiNumService.save(nowMonthNum);
		} else if (nowApiNum >= nowMonthNum.getCanApiNum()) {
			return R.failed("当月总条数：" + nowMonthNum.getCanApiNum() + "已到达上限!");
		}
		if (checkList != null && !checkList.isEmpty()) {
			TCheckLock lock = new TCheckLock();
			lock.setImportNum(checkList.size());
			lock.setApiNum(0);
			lock.setCreateMonth(nowMonth);
			lock.setCreateTime(LocalDateTime.now());
			lock.setCreateUser(user.getId());
			lock.setDeleteFlag(0);
			lock.setCreateUserName(user.getNickname());
			tCheckLockService.save(lock);
			int canApiNum = nowMonthNum.getCanApiNum();

			List<String> idCardList = new ArrayList<>();
			for (TCheckIdCard card: checkList) {
				if (card.getIdCard() != null) {
					idCardList.add(card.getIdCard());
				}
			}
			// 全部（身份证_姓名）
			Map<String, TCheckIdCard> returnMap = this.getAllMapByList(idCardList);
			// 正确的身份证
			Map<String, TCheckIdCard> trueMap = this.getTrueMapByList(idCardList);

			TCheckIdCard nowIdCard;
			TCheckIdCard lastCard;
			Map<String, TCheckIdCard> idCardMap = new HashMap<>();
			String userId = String.valueOf(user.getId());
			TCheckLock lockUpdate;
			int apiNum = 0;
			// 有一个错误，就不传200给前端
			boolean isTrue = true;
			try {
				for (TCheckIdCard c : checkList) {
					if (Common.isNotNull(c.getIdCard()) && Common.isNotNull(c.getName())) {
						lastCard = idCardMap.get(c.getIdCard());
						if (lastCard != null) {
							c.setIsTrue(lastCard.getIsTrue());
							c.setReason(lastCard.getReason());
						} else {
							nowIdCard = returnMap.get(c.getIdCard() + CommonConstants.DOWN_LINE_STRING + c.getName());
							if (nowIdCard != null) {
								c.setIsTrue(nowIdCard.getIsTrue());
								c.setReason(nowIdCard.getReason());
							} else {
								// 调用对的身份证信息
								nowIdCard = trueMap.get(c.getIdCard());
								if (nowIdCard != null) {
									if (nowIdCard.getName().equals(c.getName())) {
										c.setIsTrue(nowIdCard.getIsTrue());
										c.setReason(nowIdCard.getReason());
									} else {
										c.setIsTrue(CommonConstants.ZERO_INT);
										c.setReason("姓名错误！");
									}
								} else {
									// 校验姓名身份证规则
									if (!regIdCard(c.getIdCard())) {
										c.setIsTrue(0);
										c.setReason("身份证格式有误");
									} else if (regEmpName(c.getName())) {
										c.setIsTrue(0);
										c.setReason("姓名含数字或空格，无法校验");
									} else {
										// 调用API校验
										if (nowApiNum < canApiNum) {
											nowApiNum++;
											apiNum++;
											// 安全调用：
											this.doSafetyApi(c, canCheck, userId);
											returnMap.put(c.getIdCard() + CommonConstants.DOWN_LINE_STRING + c.getName(), c);

										} else {
											c.setIsTrue(0);
											c.setReason("调用花钱的Api的条数已达上限：" + canApiNum + "，请联系管理员处理！");
										}
									}
								}
							}
						}
						// 将同身份证的结果存储下来备用，防止撞库
						idCardMap.put(c.getIdCard(), c);
					} else {
						c.setIsTrue(0);
						c.setReason("姓名身份证不可为空");
					}
					if (isTrue && c.getIsTrue() == 0) {
						isTrue = false;
					}
				}
			} catch (Exception e) {
				returnMap.clear();
				trueMap.clear();
				lockUpdate = new TCheckLock();
				lockUpdate.setId(lock.getId());
				lockUpdate.setDeleteFlag(CommonConstants.ONE_INT);
				lockUpdate.setApiNum(apiNum);
				tCheckLockService.updateById(lockUpdate);
				throw new RuntimeException(e.getMessage() == null ? "校验身份证导入失败！" : "校验身份证导入失败：" + e.getMessage());
			} finally {
				returnMap.clear();
				trueMap.clear();
				lockUpdate = new TCheckLock();
				lockUpdate.setId(lock.getId());
				lockUpdate.setDeleteFlag(CommonConstants.ONE_INT);
				lockUpdate.setDeleteFlag(CommonConstants.ONE_INT);
				lockUpdate.setApiNum(apiNum);
				tCheckLockService.updateById(lockUpdate);
			}
			if (isTrue) {
				return R.ok();
			} else {
				return new R<>(CommonConstants.ONE_INT, "身份证姓名校验不通过！", checkList);
			}
		}
		return R.failed("数据为空！");
	}

	/**
	 * @Description: 多线程调用api，每次调用前查询一下数据库：
	 * @Author: hgw
	 * @Date: 2022/6/27 17:09
	 * @return: void
	 **/
	private void doSafetyApi(TCheckIdCard c, boolean canCheck, String userId) {
		TCheckIdCard check = new TCheckIdCard();
		check.setIdCard(c.getIdCard());
		Map<String, TCheckIdCard> checkMap = this.getAllMap(check);
		if (checkMap == null || checkMap.isEmpty()) {
			// 调用对的身份证信息
			Map<String, TCheckIdCard> trueMap = this.getTrueMap(check);
			check = trueMap.get(c.getIdCard());
			if (check != null) {
				if (check.getName().equals(c.getName())) {
					c.setIsTrue(check.getIsTrue());
					c.setReason(check.getReason());
				} else {
					c.setIsTrue(CommonConstants.ZERO_INT);
					c.setReason("姓名错误！");
				}
			} else {
				// 调用花钱的
				this.moneyCheck(c, canCheck, userId);
			}
		} else {
			check = checkMap.get(c.getIdCard() + CommonConstants.DOWN_LINE_STRING + c.getName());
			if (check != null) {
				c.setIsTrue(check.getIsTrue());
				c.setReason(check.getReason());
			} else {

				// 调用花钱的
				this.moneyCheck(c, canCheck, userId);
			}
		}
	}

	// 调用花钱的
	private void moneyCheck(TCheckIdCard c, boolean canCheck, String userId) {
		// 调用花钱的
		ChecksUtil.checkIdCard(c, canCheck);
		c.setCreateUser(userId);
		c.setCreateTime(LocalDateTime.now());
		c.setType(CommonConstants.ONE_INT);
		this.save(c);
	}

}
