package com.cirle.scientific.service.impl;

import com.cirle.scientific.dao.*;
import com.cirle.scientific.dto.QkjColumnistDTO;
import com.cirle.scientific.dto.WxUerInfoDTO;
import com.cirle.scientific.po.*;
import com.cirle.scientific.pojo.BizCodeEnum;
import com.cirle.scientific.pojo.Result;
import com.cirle.scientific.service.MemberService;
import com.cirle.scientific.utils.*;
import com.cirle.scientific.utils.UUID;
import com.cirle.scientific.utils.redis.DistributedLockCache;
import com.cirle.scientific.utils.weixin.WeixinpayConfig;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.support.atomic.RedisAtomicInteger;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Component
@Transactional
@Slf4j
public class MemberServiceImpl implements MemberService {

    @Autowired
    private MemberDao memberDao;

    @Autowired
    private QkjColumnistDetailDao qkjColumnistDetailDao;

    @Autowired
    private QkjColumnistDao qkjColumnistDao;

	@Autowired
	StringRedisTemplate stringRedisTemplate;

	@Autowired
	QkjMemberTaskInfoDao qkjMemberTaskInfoDao;

	@Autowired
	QkjMemberOpenidDao memberOpenidDao;


	@Autowired
	DistributedLockCache lockCache;

	/**
	 * 时间间隔（分钟）
	 */
	public static final int TIME_INTERVAL = 30;
	/**
	 * 登录失败重试次数上限
	 */
	public static final int FAILED_RETRY_TIMES = 3;
	/**
	 * redis记录用户登录失败次数key
	 */
	public static final String USER_LOGIN_FAILED_COUNT = "USER:LOGIN:FAILED:COUNT:";

	@Override
	public QkjMember findByMemCard(String memCard) {
		return memberDao.findByMemCard(memCard);
	}

	@Override
	public List<QkjColumnistDTO> getColumnistByObjTypeAndobjId(Integer objType, Integer objId) {
		List<QkjColumnistDetail> list = qkjColumnistDetailDao.findByobjTypeAndobjId(2, objId);
	    if (list.size() != 0) {
	    		List<QkjColumnistDTO> dtos = new ArrayList<QkjColumnistDTO>();
	    		for(QkjColumnistDetail cd : list){
	    			dtos.add(makeColumnListDto(cd.getMemCard()));
	    		}
	    		return dtos;
	    }
	    return null;
    }

	public QkjColumnistDTO makeColumnListDto(String columnistMemcard) {
        QkjColumnist mem = qkjColumnistDao.findByMemCard(columnistMemcard);
        if (mem != null) {
        		QkjColumnistDTO columnistDTO = CopyUtil.copy(mem, QkjColumnistDTO.class);
            return columnistDTO;
        }
        return null;
    }

	@Override
	@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
	public QkjMember memberLogin(WxUerInfoDTO wxUerInfoDTO, Integer memRegisterSource) {
		log.info("进入用户微信登录service");
		QkjMember member = null;
		try {
			member = memberDao.findByWxId(wxUerInfoDTO.getUnionid());
			if (member != null && member.getMemCard() != null) {
				log.info("微信昵称为：" + wxUerInfoDTO.getNickname() + "的用户已存在，直接登录");
				// 更新是否关注公众号
				if (wxUerInfoDTO.getSubscribe() != null) {
					member.setSubscribe(wxUerInfoDTO.getSubscribe());
				}
				// 更新最后一次登录时间
				member.setMemLastloginTime(Calendar.getInstance());
				member = memberDao.save(member);
				// return member;
			} else {
//				// 新注册用户
//				log.info("微信昵称为：" + wxUerInfoDTO.getNickname() + "的用户不存在，创建用户");
//				member = new QkjMember();
//				member.setMemCard(UUID.getUUID());
//				member.setMemNickname(wxUerInfoDTO.getNickname());
//				member.setMemMobile(null);
//				member.setMemRegisterSource(memRegisterSource);
//				member.setMemRegisterTime(Calendar.getInstance());
//				member.setMemHeadimg(wxUerInfoDTO.getHeadimgurl());
//				member.setMemStatus(0);
//				member.setWxId(wxUerInfoDTO.getUnionid());
//				member.setMemLastloginTime(Calendar.getInstance());

				member = memberDao.save(member);
			}
			return member;

		} catch (Exception e) {
			e.getStackTrace();
			log.error("用户微信登录service出现异常：" + e.getCause());

			return null;
		}

	}

	@Override
	@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
	public QkjMember memberLogin(String memMobile, Integer memRegisterSource, String wxId, String memNickname, String openId, String memHeadimg, Integer subscribe) {
		log.info("进入用户微信登录service");
		QkjMember member = null;
		try {
			member = memberDao.findByMemMobile(memMobile);
			if (member != null && member.getMemCard() != null) {
				log.info("手机号用户已存在，直接登录");
				if(StringUtils.isNotBlank(wxId)){
					member.setSubscribe(subscribe);
					member.setWxId(wxId);
				}
				// 更新最后一次登录时间
				member.setMemLastloginTime(Calendar.getInstance());
				//补全userid
				if (Objects.isNull(member.getUserId())) {
					LocalDateTime time = LocalDateTimeUtil.getByCalendar(member.getMemRegisterTime());
					Long userId = generateUserId(time);
//					for (int i = 0; i < 5; i++) {
//						if (userId == 0L) {//如果当天的满了顺延一下
//							time = time.plusDays(1);
//							userId = generateUserId(time);
//						}
//					}
					member.setUserId(userId);
				}

				member = memberDao.save(member);
				// return member;
			} else {
				// 新注册用户
				log.info("手机后用户不存在，创建用户");
				member = new QkjMember();
				member.setMemCard(UUID.getUUID());
				member.setMemNickname(StringUtils.isNotBlank(memNickname)?memNickname:makeMobileNickname(memMobile));
				member.setMemMobile(memMobile);
				member.setMemRegisterSource(memRegisterSource);
				member.setMemRegisterTime(Calendar.getInstance());
				member.setMemHeadimg(StringUtils.isNotBlank(memHeadimg)?memHeadimg:"https://files.qkyxzx.com/html5/mem_headimg_default.png");
				member.setMemStatus(0);
				member.setWxId(wxId);
				member.setSubscribe(subscribe);
				member.setMemLastloginTime(Calendar.getInstance());
				member.setUserId(generateUserId(LocalDateTime.now()));
				member = memberDao.save(member);

				QkjMemberTaskInfo taskInfo = new QkjMemberTaskInfo();
				taskInfo.setMemCard(member.getMemCard());
				qkjMemberTaskInfoDao.save(taskInfo);
			}

			//保存微信用户的openId，用于后期的模板推送
			if(memRegisterSource==1 && openId != null){
				QkjMemberOpenid memberOpenid = memberOpenidDao.findByMemCardAndAppId(member.getMemCard(), WeixinpayConfig.appId);
				if(memberOpenid == null){
					memberOpenid = new QkjMemberOpenid();
				}
				memberOpenid.setMemCard(member.getMemCard());
				memberOpenid.setAppId(WeixinpayConfig.appId);
				memberOpenid.setOpenId(openId);
				memberOpenidDao.save(memberOpenid);
			}

			return member;

		} catch (Exception e) {
			e.getStackTrace();
			log.error("用户微信登录service出现异常：" + e.getCause());
			return null;
		}
	}

	@Override
	public Integer findUserIntegral(String memCard) {
		if (StringUtils.isNotBlank(memCard)) {
			QkjMemberTaskInfo byMemCard = qkjMemberTaskInfoDao.findByMemCard(memCard);
			if (byMemCard != null) {
				return byMemCard.getMemTotalPoints();
			}
			return -1;
		}
		return -1;
	}

	@Override
	public Result<QkjMember> checkPwd(String ip, Integer memRegisterSource, String memMobile, String password,String from) {
		//密码为空
		if (StringUtils.isEmpty(password)) {
			return Result.failed(BizCodeEnum.PASSWD_ERROR);
		}
		QkjMember member = memberDao.findByMemMobile(memMobile);
		//用户不存在
		if (member == null) {
			member = memberDao.findByMemNickname(memMobile);
			if(member == null){
				return Result.failed(BizCodeEnum.NO_REGISTER);
			}
		}
		String key = USER_LOGIN_FAILED_COUNT +from+ memMobile;
		RedisAtomicInteger counter = getRedisCounter(key);

		if (counter.get() >= FAILED_RETRY_TIMES) {
			return Result.failed("登录失败次数已达上限，请稍后再试。");
		}

		if( !password.equals(member.getPasswd())){
			// 失败次数 + 1
			counter.getAndIncrement();
			return Result.failed("密码错误,错误次数【"+counter.get()+"】次，最大错误次数【"+FAILED_RETRY_TIMES+"】");
		}

		//更新登录时间
		member.setMemLastloginTime(Calendar.getInstance());
		QkjMember save = memberDao.save(member);
		return  Result.success(save);
	}

	@Override
	public QkjMember register(String memMobile, Integer memRegisterSource, Integer subscribe, String passwd, String memNickName) {
		// 新注册用户
		QkjMember member = null;
		try {
			member = new QkjMember();
			member.setMemCard(UUID.getUUID());
			member.setUserId(generateUserId(LocalDateTime.now()));
			String nickName = StringUtils.isBlank(memNickName) ? makeMobileNickname(memMobile) : memNickName;
			member.setMemNickname(nickName);
			member.setMemMobile(memMobile);
			member.setMemRegisterSource(memRegisterSource);
			member.setMemRegisterTime(Calendar.getInstance());
			member.setMemHeadimg("https://files.qkyxzx.com/html5/mem_headimg_default.png");
			member.setMemStatus(0);
			member.setWxId("");
			member.setSubscribe(subscribe);
			member.setMemLastloginTime(Calendar.getInstance());
			member.setPasswd(passwd);
			member = memberDao.save(member);

			QkjMemberTaskInfo taskInfo = new QkjMemberTaskInfo();
			taskInfo.setMemCard(member.getMemCard());
			qkjMemberTaskInfoDao.save(taskInfo);
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
		return member;
	}

	//生成用户ID
	private Long generateUserId(LocalDateTime memRegisterTime) {
		if (Objects.isNull(memRegisterTime)) {
			return null;
		}
		//先得到当前的ID生成到啥 程度了
		//先判断是否是当天第一个注册的是的话 ID为1

		LocalDateTime startOfDay = LocalDateTimeUtil.withTimeAtStartOfDay(memRegisterTime);
		LocalDateTime endOfDay = LocalDateTimeUtil.withTimeAtEndOfDay(memRegisterTime);
		Long maxUserIdOld = memberDao.getMaxUserId(startOfDay, endOfDay);
		if (Objects.isNull(maxUserIdOld)) {
			LocalDate nowData = memRegisterTime.toLocalDate();
			String dateAsString = LocalDateTimeUtil.getDateAsString(nowData, DatePatternConst.DATE_STAMP_TWO);
			dateAsString = dateAsString + "00001";
			maxUserIdOld = Long.valueOf(dateAsString);
		} else {
			maxUserIdOld = maxUserIdOld + 1;
		}
		return maxUserIdOld;
	}

	@Override
	public QkjMember weixinLoginOAuth(WxUerInfoDTO wxUerInfoDTO) {
		log.info("weixinLoginOAuth join wxUerInfoDTO:{}", wxUerInfoDTO);
		QkjMember member = null;
		try {
			member = memberDao.findByWxId(wxUerInfoDTO.getUnionid());
			if (member != null && member.getMemCard() != null) {
				log.info("weixinLoginOAuth 微信昵称为：" + wxUerInfoDTO.getNickname() + "的用户已存在，直接登录");
				// 更新是否关注公众号
				if (wxUerInfoDTO.getSubscribe() != null) {
					member.setSubscribe(wxUerInfoDTO.getSubscribe());
				}
				// 更新最后一次登录时间
				member.setMemLastloginTime(Calendar.getInstance());
				//更新微信头像
				if(StringUtils.isNotBlank(wxUerInfoDTO.getHeadimgurl())){
					member.setMemHeadimg(wxUerInfoDTO.getHeadimgurl());
				}
				//补全userid
				if (Objects.isNull(member.getUserId())) {
					LocalDateTime time = LocalDateTimeUtil.getByCalendar(member.getMemRegisterTime());
					Long userId = generateUserId(time);
//					for (int i = 0; i < 5; i++) {
//						if (userId == 0L) {//如果当天的满了顺延一下
//							time = time.plusDays(1);
//							userId = generateUserId(time);
//						}
//					}
					member.setUserId(userId);
				}
				member = memberDao.save(member);
			}
			return member;

		} catch (Exception e) {
			log.error("weixinLoginOAuth e：" + e.getCause());
		}
		return member;
	}

	@Override
	public List<QkjMember> getQkjMemberList(List<String> memCards) {
		if(CollectionUtils.isEmpty(memCards)){
			return Collections.emptyList();
		}
		log.info("getQkjMemberList memCards size:{}", memCards.size());
		List<QkjMember> all = Lists.newArrayList();
		List<List<String>> lists = QkListUtil.splitList(memCards, 500);
		lists.forEach(ids ->{
			List<QkjMember> allBymemCards = memberDao.findAllBymemCards(ids);
			if(CollectionUtils.isNotEmpty(allBymemCards)){
				all.addAll(allBymemCards);
			}
		});
		return all;
	}

	private String makeMobileNickname(String memMobile) {
		return memMobile.substring(0, 3) + "****" + memMobile.substring(7);
	}
	/**
	 * 根据key获取计数器
	 *
	 * @param key key
	 * @return
	 */
	private RedisAtomicInteger getRedisCounter(String key) {
		RedisAtomicInteger counter =
				new RedisAtomicInteger(key, stringRedisTemplate.getConnectionFactory());
		if (counter.get() == 0) {
			// 设置过期时间，10分钟
			counter.expire(TIME_INTERVAL, TimeUnit.MINUTES);
		}
		return counter;
	}
}
