package com.sv.service.api;

import com.github.pagehelper.PageHelper;
import com.sv.dto.api.MemberTokenDTO;
import com.sv.entity.Member;
import com.sv.entity.MemberToken;
import com.sv.mapper.MemberTokenMapper;
import com.ydd.framework.core.common.Pagination;
import com.ydd.framework.core.common.utils.ValidationUtils;
import com.ydd.framework.core.service.impl.BaseServiceImpl;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang.RandomStringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;

/**
 * Service - 用户token
 *
 * @author lihong
 * @since 2018-08-02
 */
@Service
@Transactional(readOnly = true)
public class MemberTokenService extends BaseServiceImpl{

	private final Logger logger = LoggerFactory.getLogger(MemberTokenService.class);

	/**
	 * 过期秒数
	 */
	public static final Integer ACCESS_TOKEN_EXPIRED_SECONDS = 7200;

	@Resource
	private MemberTokenMapper memberTokenMapper;
	@Resource
	private MemberService memberService;

	@Resource
	private MemberIdCacheService memberIdCacheService;
	/**
	 * 创建用户token
	 *
	 * @param memberToken 用户token
	 */
	@Transactional
    public void save(MemberToken memberToken) {
		if (memberToken.getId() != null && memberToken.getId() > 0) {
			// 更新
			memberTokenMapper.update(memberToken);
		} else {
			// 新建
			memberTokenMapper.insert(memberToken);
		}
	}

	/**
	 * 更新用户token
 	 *
	 * @param memberToken 用户token
	 */
	@Transactional
    public void update(MemberToken memberToken) {
		memberTokenMapper.update(memberToken);
	}

	/**
	 * 删除用户token
	 *
	 * @param id 编号
   	 * @return 删除数量
	 */
	@Transactional
    public Integer delete(Integer id) {
		if (id == null || id <= 0) {
			return 0;
		}
		return memberTokenMapper.delete(id);
	}

	/**
	 * 删除用户token
	 *
	 * @param ids 编号数组
	 * @return 删除数量
	 */
	@Transactional
    public Integer deleteByIds(Integer[] ids) {
		if (ids == null || ids.length == 0) {
			return 0;
		}
		return memberTokenMapper.deleteByIds(ids);
	}

	/**
	 * 查询用户token
	 *
	 * @param id 编号
	 * @return 用户token
	 */
	public MemberToken findById(Integer id) {
		return memberTokenMapper.findById(id);
	}

	/**
	 * 查询用户token
	 *
	 * @param pagination 分页信息
	 * @return 分页结果
	 */
	public Pagination findPage(Pagination pagination) {
		PageHelper.startPage(pagination.getPage(), pagination.getPageSize());
		PageHelper.orderBy("id desc");
		pagination.setQueryResult(memberTokenMapper.findAll());
		return pagination;
	}

	/**
	 * 查询访问凭证
	 * @param memberId
	 * @param refreshFlag
	 * @return
	 */
	@Transactional
	public MemberTokenDTO findDTOByMemberId(Integer memberId, Boolean refreshFlag) {
		return findDTOByMember(memberService.findAndVerifyById(memberId), refreshFlag);
	}

	/**
	 * 查询访问凭证
	 * 若不存在，则自动创建
	 *
	 * @param member
	 * @param refreshFlag
	 * @return
	 */
	@Transactional
	public MemberTokenDTO findDTOByMember(Member member, Boolean refreshFlag) {
		ValidationUtils.assertNotNull(member, refreshFlag);

		MemberToken memberToken = findByMember(member, refreshFlag);
		return wrapperDTO(memberToken);
	}

	/**
	 * 查询会员授权<br/>
	 * 若不存在，则自动创建
	 *
	 * @param member      会员
	 * @param refreshFlag 刷新标志
	 * @return 会员授权
	 */
	@Transactional
	public MemberToken findByMember(Member member, Boolean refreshFlag) {
		ValidationUtils.assertNotNull(member, refreshFlag);


		MemberToken memberToken = memberTokenMapper.findByMemberId(member.getId());

		if (memberToken == null) {
			memberToken = create(member.getId(),member.getPlatformId(), Boolean.TRUE);
		}

		// 强制更新凭证
		if (Boolean.TRUE.equals(refreshFlag)) {
			// 删除缓存中的memberId和merchantId
			memberIdCacheService.remove(memberToken.getAccessToken());

			refreshToken(memberToken);
			memberTokenMapper.update(memberToken);

			// 将memberId缓存到Redis中
			memberIdCacheService.cacheMemberId(memberToken.getMemberId(), memberToken.getAccessToken());
		}
		return memberToken;
	}

	/**
	 * 创建会员授权
	 *
	 * @param memberId  会员编号
	 * @param forceFlag 强制创建
	 * @return 会员授权
	 */
	@Transactional
	public MemberToken create(Integer memberId,Integer platformId, Boolean forceFlag) {
		MemberToken memberToken = null;

		if (forceFlag == null || Boolean.FALSE.equals(forceFlag)) {
			memberToken = memberTokenMapper.findByMemberId(memberId);
		}

		if (memberToken != null) {
			return memberToken;
		}

		memberToken = new MemberToken();
		memberToken.setMemberId(memberId);
		memberToken.setPlatformId(platformId);
		refreshToken(memberToken);
		memberTokenMapper.insert(memberToken);
		return memberToken;
	}

	/**
	 * 刷新凭证
	 *
	 * @param memberToken 访问凭证
	 */
	private void refreshToken(MemberToken memberToken) {
		memberToken.setAccessToken(generateAccessToken(memberToken.getMemberId()));
		memberToken.setRefreshToken(generateRefreshToken(memberToken.getMemberId()));
		memberToken.setExpireTime(DateUtils.addSeconds(getCurrentTime(), ACCESS_TOKEN_EXPIRED_SECONDS));
	}

	/**
	 * 生成访问凭证
	 *
	 * @param memberId 会员编号
	 * @return 访问凭证
	 */
	private String generateAccessToken(Integer memberId) {
		return DigestUtils.md5Hex(RandomStringUtils.random(6) + System.currentTimeMillis() + memberId);
	}

	/**
	 * 生成置换凭证
	 *
	 * @param memberId 会员编号
	 * @return 置换凭证
	 */
	public String generateRefreshToken(Integer memberId) {
		return DigestUtils.md5Hex(RandomStringUtils.random(6) + System.currentTimeMillis() + memberId);
	}

	/**
	 * 实体转DTO
	 *
	 * @param authorization 实体
	 * @return DTO
	 */
	private MemberTokenDTO wrapperDTO(MemberToken authorization) {
		MemberTokenDTO dto = new MemberTokenDTO();
		dto.setAccessToken(authorization.getAccessToken());
		dto.setRefreshToken(authorization.getRefreshToken());
		dto.setExpiredIn(ACCESS_TOKEN_EXPIRED_SECONDS);
		return dto;
	}

	/**
	 * 退出登录
	 */
	public void logout(Integer memberId) {
		ValidationUtils.assertNotNull(memberId);

		// 查询会员访问凭证
		MemberToken memberToken = findByMemberId(memberId, Boolean.FALSE);

		if (memberToken == null) {
			return;
		}

		// 删除Redis中的memberId
		memberIdCacheService.remove(memberToken.getAccessToken());
	}

	@Transactional
	public MemberToken findByMemberId(Integer memberId, Boolean refreshFlag) {
		return findByMember(memberService.findAndVerifyById(memberId), refreshFlag);
	}

}

