package com.cyksj.service.mange.account;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Validator;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Assert;
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.cyksj.common.constant.Constant;
import com.cyksj.common.exception.BusinessRuntimeException;
import com.cyksj.common.util.Jsons;
import com.cyksj.common.util.StringUtil;
import com.cyksj.mapper.*;
import com.cyksj.mapper.manage.AutoUpdateAccountPwdLogMapper;
import com.cyksj.mapper.manage.cms.CmsUserMapper;
import com.cyksj.mapper.sys.SysEmailMapper;
import com.cyksj.model.entity.*;
import com.cyksj.model.excel.ExcelAccountData;
import com.cyksj.model.manage.views.AccountView;
import com.cyksj.model.request.DelAccountTripsReq;
import com.cyksj.model.views.CmsUserVO;
import com.cyksj.model.views.ExpiredAccountDataView;
import com.cyksj.redis.RedisService;
import com.cyksj.service.mail.CommonMailService;
import com.cyksj.service.mange.AccountCommonService;
import com.cyksj.service.mange.CmsAccountService;
import com.cyksj.service.mange.CmsGroupService;
import com.cyksj.service.sys.SysConfigService;
import com.ejlchina.searcher.BeanSearcher;
import com.ejlchina.searcher.param.Operator;
import com.ejlchina.searcher.util.MapUtils;
import com.google.common.collect.Lists;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.*;

/**
 * @author chan
 * @date 2022/9/27 6:23 PM
 */
@Slf4j
@Service("cms")
@RequiredArgsConstructor
public class CmsAccountServiceImpl extends ServiceImpl<AccountMapper, Account> implements CmsAccountService {
	private final AccountMapper accountMapper;

	private final AccountUpdatePasswordRecordMapper accountUpdatePasswordRecordMapper;

	private final CmsUserMapper cmsUserMapper;

	private final AutoUpdateAccountPwdLogMapper autoUpdateAccountPwdLogMapper;

	private final BeanSearcher beanSearcher;

	private final CmsGroupService cmsGroupService;

	private final RedisService redisService;

	private final AccountCommonService accountCommonService;

	private final SysConfigService sysConfigService;

	private final SysEmailMapper sysEmailMapper;

	private final GoodsDonMapper goodsDonMapper;

	private final AccountBlockedReplaceRecordMapper accountBlockedReplaceRecordMapper;

	private final CommonMailService commonMailService;

	private final DelAccountRecordMapper delAccountRecordMapper;

	private final GroupsMapper groupsMapper;

	private final GroupsRelationMapper relationMapper;

	@Override
	public IPage<ExpiredAccountDataView> getExpiredAccountView(Boolean isCorpWx, String customerService, Long goodsId, Long skuId, String account, Boolean renewStatus, Boolean handleStatus, String cnAccount, String usAccount, Integer userId, String startTime, String endTime, String now, Long offset, Long limit) {
		return accountMapper.getExpiredAccountView(isCorpWx, customerService, goodsId, skuId, account, renewStatus, handleStatus, cnAccount, usAccount, userId, startTime, endTime, now, new Page<>(offset, limit));
	}

	@Override
	public List<ExcelAccountData> getExpiredAccountViewNoPage(Boolean isCorpWx, String customerService, Long goodsId, Long skuId, String account, Boolean renewStatus, Boolean handleStatus, String cnAccount, String usAccount, Integer userId, String startTime, String endTime, String now) {
		return accountMapper.getExpiredAccountViewNoPage(isCorpWx, customerService, goodsId, skuId, account, renewStatus, handleStatus, cnAccount, usAccount, userId, startTime, endTime, now);
	}

	@Override
	public List<OrderDon> getNoAppleOneOrderDon(List<Long> skuIds, Date yesZeroDate, Date thisZeroDate, List<String> noOrderStatus) {
		return accountMapper.getNoAppleOneOrderDon(skuIds, yesZeroDate, thisZeroDate, noOrderStatus);
	}

	@Override
	public List<AccountView> getExpiredAllAccount() {
		return accountMapper.getExpiredAllAccount();
	}

	@Override
	public void saveRecord(Long operateUserId, Long accountId, String oldPassword, String newPassword, String type) {
		AccountUpdatePasswordRecord record = new AccountUpdatePasswordRecord();
		record.setAccountId(accountId);
		record.setOperateUserId(operateUserId);
		Optional.ofNullable(cmsUserMapper.selectById(operateUserId))
				.ifPresent(admin -> record.setOperator(admin.getNickname()));
		record.setOldPassword(oldPassword);
		record.setNewPassword(newPassword);
		record.setType(type);
		accountUpdatePasswordRecordMapper.insert(record);
	}

	@Override
	public void recordAutoUpdatePwd(Long accountId, String account, String oldPwd, String newPwd, String operateIp) {
		AutoUpdateAccountPwdLog log = new AutoUpdateAccountPwdLog();

		log.setAccountId(accountId);
		log.setAccount(account);
		log.setOldPwd(oldPwd);
		log.setNewPwd(newPwd);
		log.setOperateLocation(StringUtil.getRealAddressByIP(operateIp));
		log.setOperateIp(operateIp);

		autoUpdateAccountPwdLogMapper.insert(log);
	}

	@Override
	public void assignDeleteCustomerAccount(Long customerServiceId) {
		List<AccountView> accountViews = beanSearcher.searchAll(AccountView.class, MapUtils.builder()
				.field(AccountView::getCustomerServiceId, customerServiceId)
				.build());
		if (accountViews.size() > 0) {
			List<CmsUserVO> customers = beanSearcher.searchAll(CmsUserVO.class, MapUtils.builder()
					.field(CmsUserVO::getId, customerServiceId).op(Operator.NotEqual)
					.field(CmsUserVO::getRoleNames, "客服").op(Operator.Contain)
					.build());
			if (customers.size() > 0) {
				log.info("删除客服id:{},分配其未修改的过期账号,账号数量:{}", customerServiceId, accountViews.size());
				assignCustomerAccount(customers, accountViews);
			}
		}
	}

	@Override
	public void assignCustomerAccount(List<CmsUserVO> customers, List<AccountView> accountViews) {
		int customerSize = customers.size();

		int accountSize = accountViews.size();

		if (accountSize < customerSize) {
			accountViews.forEach(account -> {
				int randomIndex = RandomUtil.randomInt(customerSize);
				CmsUserVO customer = customers.get(randomIndex);
				accountMapper.update(null, Wrappers.lambdaUpdate(Account.class)
						.set(Account::getCustomerServiceId, customer.getId())
						.eq(Account::getId, account.getId()));
			});
			return;
		}

		int num = accountSize / customerSize;

		int remain = accountSize % customerSize;

		List<List<AccountView>> partition = Lists.partition(accountViews, num);
		for (int i = 0; i < customerSize; i++) {
			List<AccountView> expiredAccounts = partition.get(i);
			CmsUserVO customer = customers.get(i);
			expiredAccounts.forEach(ea -> {
				Long accountId = ea.getId();
				accountMapper.update(null, Wrappers.lambdaUpdate(Account.class)
						.set(Account::getCustomerServiceId, customer.getId())
						.eq(Account::getId, accountId));
			});
		}
		if (remain > 0) {
			log.info("分配多余的过期账号给客服");
			List<AccountView> remainExpiredAccount = partition.get(customerSize);
			remainExpiredAccount.forEach(remainAccount -> {
				int randomIndex = RandomUtil.randomInt(customerSize);
				log.info("获取的随机下标:{}", randomIndex);
				CmsUserVO customer = customers.get(randomIndex);
				log.info("随机分配的客服是:{}", customer.getNickname());
				Long accountId = remainAccount.getId();
				accountMapper.update(null, Wrappers.lambdaUpdate(Account.class)
						.set(Account::getCustomerServiceId, customer.getId())
						.eq(Account::getId, accountId));
			});
		}
	}

	@Override
	@Transactional(rollbackFor = Throwable.class)
	public void analysisChatGPTAccount(Long goodsId, Long skuId, List<Object> accountList) {
		insertAccount(goodsId, skuId, accountList);
	}

	@Override
	public void analysisAmericaAppidAccount(Long goodsId, Long skuId, List<Object> accountList) {
		insertAccount(goodsId, skuId, accountList);
	}

	@Override
	public void readFileAndImportEmail(MultipartFile file) throws Exception {
		InputStream in = null;
		BufferedReader br = null;
		String regex = "----";
		List<SysEmail> sysEmails = new ArrayList<>();
		List<String> error = new ArrayList<>();
		try {
			in = file.getInputStream();
			br = new BufferedReader(new InputStreamReader(file.getInputStream()));
			String content = null;
			while ((content = br.readLine()) != null) {
				String[] split = content.split(regex);
				if (split.length > 1) {
					String email = split[0];
					String password = split[1];
					if (!StrUtil.hasEmpty(email, password)) {
						SysEmail sysEmail = new SysEmail();
						sysEmail.setEmail(email);
						sysEmail.setPassword(password);
						sysEmails.add(sysEmail);
					}
				}else {
					error.add(split[0]);
				}
			}
			if (CollUtil.isNotEmpty(sysEmails)) {
				Lists.partition(sysEmails, 1000).forEach(data -> {
					sysEmailMapper.batchInsert(data);
				});
			}
		} finally {
			if (br != null) {
				br.close();
			}
			if (in != null) {
				in.close();
			}
		}
		System.out.println(Jsons.toJson(error));
	}

	/**
	 *
	 * @param goodsId
	 * @param skuId
	 * @param accountList
	 */
	public void insertAccount(Long goodsId, Long skuId, List<Object> accountList) {
		if (CollUtil.isEmpty(accountList)) {
			throw BusinessRuntimeException.getInstance("文件数据为空");
		}
		String cache = RedisService.key.IMPORT_ACCOUNT_CACHE_KEY.getNameFormat(goodsId);
		if (!redisService.setNx(cache, goodsId, RedisService.key.IMPORT_ACCOUNT_CACHE_KEY.getTimeout())) {
			throw BusinessRuntimeException.getInstance("后台程序正在导入账号中...");
		}
		List<Long> special_email_goods_ids = new ArrayList<>();
		SysConfig sysConfig = sysConfigService.getOne(Wrappers.lambdaQuery(SysConfig.class)
				.eq(SysConfig::getSysKey, Constant.SPECIAL_GOODS_ACCOUNT_IMPORT_KEY).last("limit 1"));
		if (sysConfig != null) {
			try {
				special_email_goods_ids.addAll(Jsons.parseList(sysConfig.getSysValue(), Long.class));
			} catch (Exception e) {
			}
		}
		String regex;
		String regex2 = "---";
		if (goodsId == 29l) {
			regex = "\\|";
		} else {
			regex = "----";
		}
		try {
			accountList.forEach(accountData -> {
				Map<String, Object> map = Jsons.toMap(accountData);
				Account insert = new Account();
				insert.setGoodsId(goodsId);
				if (map.keySet().size() >= 5) {
					String account = map.get("0").toString();
					String password = map.get("1").toString();
					String friend = map.get("2").toString();
					String work = map.get("3").toString();
					String parents = map.get("4").toString();
					String secret;
					if (map.keySet().size() == 6) {
						String country = map.get("5").toString();
						secret = String.format(Constant.NEW_APPID_SECRET, friend, work, parents, country);
					} else {
						secret = String.format(Constant.NEW_APPID_NO_COUNTRY_SECRET, friend, work, parents);
					}
					insert.setAccount(account);
					insert.setPassword(password);
					insert.setSecret(secret);
				} else {
					String params = map.get("0").toString();
					String[] part;
					//兼容
					if (params.contains(regex2) && !params.contains(regex)) {
						part = params.split(regex2);
					} else {
						part = params.split(regex);
					}
					if (part.length >= 2) {
						String account = part[0];
						String password = part[1];
						insert.setAccount(account);
						insert.setPassword(password);
						if (part.length > 2 && part.length < 9) {
							//google36、辅助邮箱
							//46 Google Bard
							if (special_email_goods_ids.contains(goodsId)) {
								String email = part[2];
								insert.setEmail(email);
							} else {
								//chatGPT 邮箱密码
								String gptEmailPwd = part[2];
								insert.setGptEmailPwd(gptEmailPwd);
							}
						}
						if (goodsId.equals(31l)) {
							if (part.length >= 9) {
								StringBuilder sb = new StringBuilder();
								String country = part[part.length - 1];
								if (country.contains("国")) {
									sb.append(part[part.length - 1]);
									sb.append(Constant.ONE_EMPTY);
									sb.append(part[part.length - 2]);
									sb.append(Constant.ONE_EMPTY);
								}
								for (int i = 2; i < part.length; i++) {
									if (part[i].contains("朋友")) {
										sb.append("朋友");
										sb.append(Constant.ONE_EMPTY);
										sb.append(part[i + 1]);
										i++;
									}
									if (part[i].contains("工作")) {
										sb.append("工作");
										sb.append(Constant.ONE_EMPTY);
										sb.append(part[i + 1]);
										i++;
									}
									if (part[i].contains("父母")) {
										sb.append("父母");
										sb.append(Constant.ONE_EMPTY);
										sb.append(part[i + 1]);
										i++;
									}
									if (part[i].contains("菜")) {
										sb.append("一道菜");
										sb.append(Constant.ONE_EMPTY);
										sb.append(part[i + 1]);
										i++;
									}
									if (part[i].contains("书")) {
										sb.append("一本书");
										sb.append(Constant.ONE_EMPTY);
										sb.append(part[i + 1]);
										i++;
									}
									if (part[i].contains("专辑")) {
										sb.append("一张专辑");
										sb.append(Constant.ONE_EMPTY);
										sb.append(part[i + 1]);
										i++;
									}
								}
								String string = sb.toString();
								if (string.contains("菜")) {
									StringBuilder builder = new StringBuilder();
									string = builder.append("生日").append(Constant.ONE_EMPTY).append(part[2]).append(Constant.ONE_EMPTY).append(string).toString();
								}
								insert.setSecret(string);
							} else {
								//密保
								if (part.length > 5) {
									String friends = part[2];
									String works = part[3];
									String parents = part[4];
									String birthday = part[5];
									String secret = String.format(Constant.NEW_APPID_NO_COUNTRY_SECRET_DATE, birthday, friends, works, parents);
									insert.setSecret(secret);
								}
							}
						}
					}
				}
				String account = insert.getAccount();
				if (StrUtil.isEmpty(account)) {
					return;
				}
				//重复不再重新插入
				if (accountCommonService.checkIsDupAccount(goodsId, account)) {
					return;
				}
				this.save(insert);
				//是否存在未发车的车队
				GroupsTrips waiting = cmsGroupService.getOne(Wrappers.lambdaQuery(GroupsTrips.class)
						.eq(GroupsTrips::getSkuId, skuId)
						.eq(GroupsTrips::getStatus, GroupsTrips.Status.waiting).last("limit 1"));
				if (waiting != null) {
					waiting.setAccountId(insert.getId());
					try {
						cmsGroupService.setAccount(waiting);
					} catch (Exception e) {
						//自动配置车队
						setGroupsTrips(skuId, insert.getId());
					}
				} else {
					//自动配置车队
					setGroupsTrips(skuId, insert.getId());
				}
			});
		} catch (Exception e) {
			log.error(StringUtil.getErrorText(e));
		}
		redisService.del(cache);
	}

	public void setGroupsTrips(Long skuId, Long accountId) {
		//自动配置车队
		GroupsTrips groupsTrips = new GroupsTrips();
		groupsTrips.setSkuId(skuId);
		groupsTrips.setAccountId(accountId);
		cmsGroupService.issuance(groupsTrips, null, false);
	}

	@Override
	public void batchImportBlockedAccount(Long goodsId, List<Object> accountBlockedList) {
		GoodsDon goodsDon = goodsDonMapper.selectById(goodsId);
		Assert.notNull(goodsDon, "平台不存在");
		List<AccountBlockedReplaceRecord> list = new ArrayList<>();
		accountBlockedList.forEach(accountBlocked->{
			Map<String, Object> map = Jsons.toMap(accountBlocked);
			String blockedAccount = map.get("0").toString();
			if (!Validator.isEmail(blockedAccount)) {
				return;
			}
			AccountBlockedReplaceRecord accountBlockedReplaceRecord = new AccountBlockedReplaceRecord();
			accountBlockedReplaceRecord.setGoodsId(goodsId);
			accountBlockedReplaceRecord.setAccount(blockedAccount);
			list.add(accountBlockedReplaceRecord);
			if (list.size() == 400) {
				accountBlockedReplaceRecordMapper.batchInsert(list);
				list.clear();
			}
		});
		if (list.size() > 0) {
			accountBlockedReplaceRecordMapper.batchInsert(list);
		}
	}

	@Override
	public String nfUpgradeDevice(Long accountId) throws Exception {
		Account at = accountMapper.selectById(accountId);
		if (at == null || at.getGoodsId() != 1l) {
			throw BusinessRuntimeException.getInstance("只支持奈飞账号");
		}
		String account = at.getAccount();
		String password = at.getPassword();
		if (StrUtil.hasEmpty(account, password)) {
			throw BusinessRuntimeException.getInstance("账户异常");
		}
		String code = commonMailService.getTicketMailCode(at.getGoodsId(), at.getAccount(), at.getRelateEmail(), at.getGptEmailPwd(), at.getCreatedTime(), null, 1, false);
		return code;
	}

	@Override
	public String getAccountEmailCode(Long accountId) throws Exception {
		Account at = accountMapper.selectById(accountId);
		String account = at.getAccount();
		String password = at.getPassword();
		if (StrUtil.hasEmpty(account, password)) {
			throw BusinessRuntimeException.getInstance("账户异常");
		}
		String code = commonMailService.getTicketMailCode(at.getGoodsId(), at.getAccount(), at.getRelateEmail(), at.getGptEmailPwd(), at.getCreatedTime(), null, null, false);
		return code;
	}

	@Override
	@Transactional(rollbackFor = Throwable.class)
	public void batchDeleteAccountTrips(DelAccountTripsReq delAccountTripsReq, long adminId) throws Exception {
		CmsUser cmsUser = cmsUserMapper.selectById(adminId);
		List<Long> accountIds = delAccountTripsReq.getAccountIds();
		DelAccountRecord delAccountRecord = null;
		if (CollUtil.isNotEmpty(accountIds)) {
			for (Long accountId : accountIds) {
				Account account = accountMapper.selectById(accountId);
				if (account == null) {
					continue;
				}
				GroupsTrips groupsTrips = groupsMapper.selectOne(Wrappers.lambdaQuery(GroupsTrips.class)
						.eq(GroupsTrips::getAccountId, accountId)
						.last("limit 1"));
				if (groupsTrips != null) {
					Integer selectCount = relationMapper.selectCount(Wrappers.lambdaQuery(GroupsRelation.class)
							.eq(GroupsRelation::getGroupsId, groupsTrips.getId())
							.ne(GroupsRelation::getUserId, 0));
					//车队上存在用户不删除 下个循环
					if (selectCount > 0) {
						continue;
					}
					groupsMapper.deleteById(groupsTrips.getId());
					relationMapper.delete(Wrappers.lambdaQuery(GroupsRelation.class)
							.eq(GroupsRelation::getGroupsId, groupsTrips.getId()));
				}
				delAccountRecord = new DelAccountRecord();
				if (cmsUser != null) {
					delAccountRecord.setOperator(cmsUser.getNickname());
				}
				delAccountRecord.setAccountInfo(Jsons.toJson(account));
				delAccountRecordMapper.insert(delAccountRecord);
				accountMapper.deleteById(accountId);

			}
		}

		//通过车队批量删除
		List<Long> groupsIds = delAccountTripsReq.getGroupsIds();
		if (CollUtil.isNotEmpty(groupsIds)) {
			for (Long groupsId : groupsIds) {
				GroupsTrips groupsTrips = groupsMapper.selectById(groupsId);
				if (groupsTrips == null) {
					continue;
				}
				Integer selectCount = relationMapper.selectCount(Wrappers.lambdaQuery(GroupsRelation.class)
						.eq(GroupsRelation::getGroupsId, groupsTrips.getId())
						.ne(GroupsRelation::getUserId, 0));
				//车队上存在用户不删除 下个循环
				if (selectCount > 0) {
					continue;
				}
				groupsMapper.deleteById(groupsTrips.getId());
				relationMapper.delete(Wrappers.lambdaQuery(GroupsRelation.class)
						.eq(GroupsRelation::getGroupsId, groupsTrips.getId()));
				Long accountId = groupsTrips.getAccountId();
				if (accountId != null) {
					Account account = accountMapper.selectById(accountId);
					if (account != null) {
						delAccountRecord = new DelAccountRecord();
						if (cmsUser != null) {
							delAccountRecord.setOperator(cmsUser.getNickname());
						}
						delAccountRecord.setAccountInfo(Jsons.toJson(account));
						delAccountRecordMapper.insert(delAccountRecord);
						accountMapper.deleteById(accountId);
					}
				}
			}
		}
	}
}
