/*
 *    Copyright (c) 2018-2025, lengleng All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * Neither the name of the yifu4cloud.com developer nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 * Author: lengleng (wangiegie@gmail.com)
 */
package com.yifu.cloud.plus.v1.check.service.impl;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yifu.cloud.plus.v1.check.constant.ChecksConstants;
import com.yifu.cloud.plus.v1.check.entity.TCheckBankNo;
import com.yifu.cloud.plus.v1.check.mapper.TCheckBankNoMapper;
import com.yifu.cloud.plus.v1.check.service.TCanCheckService;
import com.yifu.cloud.plus.v1.check.service.TCheckBankNoService;
import com.yifu.cloud.plus.v1.check.utils.ChecksUtil;
import com.yifu.cloud.plus.v1.check.vo.CheckBankNoVo;
import com.yifu.cloud.plus.v1.check.vo.CheckBatchVo;
import com.yifu.cloud.plus.v1.yifu.common.core.constant.CommonConstants;
import com.yifu.cloud.plus.v1.yifu.common.core.exception.ErrorCodes;
import com.yifu.cloud.plus.v1.yifu.common.core.util.Common;
import com.yifu.cloud.plus.v1.yifu.common.core.util.MsgUtils;
import com.yifu.cloud.plus.v1.yifu.common.core.util.R;
import com.yifu.cloud.plus.v1.yifu.common.core.util.RedisUtil;
import com.yifu.cloud.plus.v1.yifu.social.vo.TPaymentInfoVo;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

import static java.lang.Thread.sleep;

/**
 * 银行卡卡号 校验
 *
 * @author fxj
 * @date 2022-06-20 19:56:33
 */
@RequiredArgsConstructor
@Service
public class TCheckBankNoServiceImpl extends ServiceImpl<TCheckBankNoMapper, TCheckBankNo> implements TCheckBankNoService {

	private final RedisUtil redisUtil;

	private final TCanCheckService canCheckService;

	@Override
	public R<TCheckBankNo> checkBankNo(String name, String cardNo) {
		synchronized (this){
			TCheckBankNo  checkBankNo = baseMapper.selectOne(Wrappers.<TCheckBankNo>query().lambda()
					.eq(TCheckBankNo::getBankNo, cardNo)
					.eq(TCheckBankNo::getName, name)
					.last(CommonConstants.LAST_ONE_SQL));
			if (Common.isNotNull(checkBankNo)){
				if ("01".equals(checkBankNo.getResult())) {
					return R.ok(checkBankNo);
				} else {
					return R.failed(checkBankNo);
				}
			}
			R<TCheckBankNo> resR = ChecksUtil.checkBankNoTwo(name,cardNo,canCheckService.getCanCheck());
			if (Common.isNotNull(resR) && Common.isNotNull(resR.getData())){
				baseMapper.insert(resR.getData());
			}
			return resR;
		}
	}

	@Override
	public CheckBankNoVo checkBankNoTwo(String name, String cardNo) {
		CheckBankNoVo vo = new CheckBankNoVo();
		if (Common.isEmpty(name)  || Common.isEmpty(cardNo)){
			vo.setRes(R.failed(MsgUtils.getMessage(ErrorCodes.CHECKS_BANK_NO_REQUEST_PARAM_ERROR)));
			return vo;
		}
		synchronized (this){
			TCheckBankNo  checkBankNo = baseMapper.selectOne(Wrappers.<TCheckBankNo>query().lambda()
					.eq(TCheckBankNo::getBankNo,cardNo)
					.eq(TCheckBankNo::getName,name)
					.last(CommonConstants.LAST_ONE_SQL));
			if (Common.isNotNull(checkBankNo)){
				vo.setRes(R.ok(checkBankNo));
				return vo;
			}
			R<TCheckBankNo> resR = ChecksUtil.checkBankNoTwo(name,cardNo,canCheckService.getCanCheck());
			if (Common.isNotNull(resR) && Common.isNotNull(resR.getData())){
				baseMapper.insert(resR.getData());
			}
			vo.setRes(resR);
			return vo;
		}
	}

	@Override
	public CheckBatchVo checkBankNoBatch(List<TCheckBankNo> list) {
		Date dateS = new Date();
		final String startS = String.valueOf(dateS.getTime());

		CheckBatchVo vo = new CheckBatchVo();
		List<String> noList = new ArrayList<>();
		for (TCheckBankNo no : list) {
			if (Common.isNotNull(no.getBankNo())) {
				noList.add(no.getBankNo());
			}
		}
		Map<String, TCheckBankNo> noMap = new HashMap<>();
		if (!noList.isEmpty()) {
			List<TCheckBankNo> checkBankNoList = baseMapper.getListByNoList(noList);
			if (checkBankNoList != null && !checkBankNoList.isEmpty()) {
				for (TCheckBankNo no : checkBankNoList) {
					noMap.put(no.getBankNo(), no);
				}
			}
		}
		List<TCheckBankNo> noCurlist = new ArrayList<>();
		TCheckBankNo cur;
		final Map<String, Boolean> bankMap = new HashMap<>();
		for (TCheckBankNo check : list) {
			cur = noMap.get(check.getBankNo());
			if (cur != null) {
				if (CommonConstants.ZERO_ONE.equals(cur.getResult())) {
					bankMap.put(cur.getBankNo(), cur.getName().equals(check.getName()));
				} else {
					if (cur.getName().equals(check.getName())) {
						bankMap.put(cur.getBankNo(), false);
					} else {
						noCurlist.add(check);
					}
				}
			} else {
				noCurlist.add(check);
			}
		}
		final List<TCheckBankNo> saveList = new ArrayList<>();
		if (!noCurlist.isEmpty()) {
			boolean canCheck = canCheckService.getCanCheck();
			if (noCurlist.size()>=50) {
				int l = 4;
				for (int k=0;k<l;k++) {
					if ((k+1)==l) {
						final List<TCheckBankNo> finalList = noCurlist.subList(k * (noCurlist.size() / l), noCurlist.size());
						if (canCheck) {
							doThread(bankMap, startS, finalList);
						} else {
							doNomal(bankMap, saveList, finalList);
						}
					} else {
						final List<TCheckBankNo> finalList = noCurlist.subList(k * (noCurlist.size() / l), (k + 1) * (noCurlist.size() / l));
						if (canCheck) {
							doThread(bankMap, startS, finalList);
						} else {
							doNomal(bankMap, saveList, finalList);
						}
					}
				}
			} else {
				if (canCheck) {
					doThread(bankMap, startS, noCurlist);
				} else {
					doNomal(bankMap, saveList, noCurlist);
				}
			}
			if (canCheck) {
				Date date = new Date();
				long start = date.getTime();
				int maxTime = (noCurlist.size()*200);
				long start2 = date.getTime();
				while (Thread.activeCount() > 2 && (start2-start) < maxTime) {
					Thread.yield();
					date = new Date();
					start2 = date.getTime();
				}
			}
			//fo (TCheckBankNo no : noCurlist)
				// 原代码
				/*resR = ChecksUtil.checkBankNoTwo(no.getName(), no.getBankNo(), canCheck)
				f (Common.isNotNull(resR) && resR.getCode() == CommonConstants.SUCCESS
						&& Common.isNotNull(resR.getData()))
					newNo = resR.getData()
					bankMap.put(no.getBankNo(), CommonConstants.ZERO_ONE.equals(newNo.getResult()))
					saveList.add(newNo)
				 else
					bankMap.put(no.getBankNo(), false)
				*/
			if (!saveList.isEmpty()) {
				this.saveBatch(saveList);
			}
		}
		Map<String, Boolean> bankMapS =	(Map<String, Boolean>) redisUtil.get(startS);
		if (bankMapS != null && !bankMapS.isEmpty()) {
			bankMap.putAll(bankMapS);
		}
		vo.setCheckMap(bankMap);
		return vo;
	}

	private void doThread(Map<String, Boolean> bankMap, String startS,List<TCheckBankNo> finalList) {
		new Thread(() -> {
			List<TCheckBankNo> saveList = new ArrayList<>();
			for (int i = 0; i< finalList.size(); i++) {
				final TCheckBankNo no = finalList.get(i);
				setBankMap(bankMap, startS, no, saveList);
			}
			if (!saveList.isEmpty()) {
				this.saveBatch(saveList);
			}
		}).start();
	}

	private void doNomal(Map<String, Boolean> bankMap, List<TCheckBankNo> saveList, List<TCheckBankNo> finalList) {
		TCheckBankNo no;
		for (int i = 0; i< finalList.size(); i++) {
			 no = finalList.get(i);
				final TCheckBankNo newNo = new TCheckBankNo();
				newNo.setBankNo(no.getBankNo());
				newNo.setName(no.getName());
				newNo.setMessage(ChecksConstants.CHECK_CONFIG_ACCESS);
				newNo.setResult("01");
				newNo.setType(CommonConstants.ONE_STRING);
				newNo.setRemark(ChecksConstants.CHECK_CONFIG_ACCESS);
				saveList.add(newNo);
				bankMap.put(no.getBankNo(), true);
		}
	}

	public void setBankMap(Map<String, Boolean> bankMap, String startS, TCheckBankNo no, List<TCheckBankNo> saveList) {
		// 1.调用银行卡信息校验api
		R<TCheckBankNo> resR = ChecksUtil.checkBankNoTwoMethod(no.getName(), no.getBankNo());
		if (Common.isNotNull(resR) && resR.getCode() == CommonConstants.SUCCESS
				&& Common.isNotNull(resR.getData())) {
			TCheckBankNo newNo = resR.getData();
			bankMap.put(no.getBankNo(), CommonConstants.ZERO_ONE.equals(newNo.getResult()));
			saveList.add(newNo);
		} else {
			bankMap.put(no.getBankNo(), false);
		}
		Map<String, Boolean> bankMapS =	(Map<String, Boolean>) redisUtil.get(startS);
		if (bankMapS== null) {
			bankMapS = new HashMap<>(bankMap);
		}
		redisUtil.set(startS, bankMapS, 600L);
	}

	/*public static void setBankMapByi(Map<Integer, Boolean> bankMap,int i){
		bankMap.put(i,true);
	}

	public static void main(String[] args) {
		Map<Integer, Boolean> bankMap = new HashMap<>();
		int j=100;

		List<Integer> aList = new ArrayList<>();
		for (int k=0;k<50;k++) {
			aList.add(k);
		}
		int l = 4;
		for (int k=0;k<l;k++) {
			if ((k+1)==l) {
				final List<Integer> finalList = aList.subList(k * (aList.size() / l), aList.size());
				new Thread(() -> {
					for (int i=0;i<finalList.size();i++) {
						final Integer finalI = finalList.get(i);
						setBankMapByi(bankMap, finalI);
					}
				}).start();
			} else {
				final List<Integer> finalList = aList.subList(k * (aList.size() / l), (k + 1) * (aList.size() / l));
				new Thread(() -> {
					for (int i=0;i<finalList.size();i++) {
						final Integer finalI = finalList.get(i);
						setBankMapByi(bankMap, finalI);
					}
				}).start();
			}
		}

		while (Thread.activeCount() > 2) {
			Thread.yield();
		}
		for (int i : bankMap.keySet()) {
			System.out.println(i);
		}
	}*/

}
