package cn.quantgroup.xyqb.aspect.lock;


import cn.quantgroup.xyqb.Constants;
import cn.quantgroup.xyqb.model.JsonResult;
import cn.quantgroup.xyqb.util.IpUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Objects;

/**
 * 密码错误限次的校验
 *
 * @author 任文超
 * @version 1.0.0
 * @since 2017-11-23
 */
@Slf4j
@Aspect
@Component
public class PasswordErrorFiniteValidateAdvisor {

    @Autowired
    @Qualifier("stringRedisTemplate")
    private RedisTemplate<String, String> redisTemplate;

    /**
     * 密码错误限次切面
     */
    @Pointcut("@annotation(cn.quantgroup.xyqb.aspect.lock.PasswordErrorFiniteValidator)")
    private void passwordErrorFiniteValidate() {
    }

    /**
     * 在受保护的接口方法执行前, 执行锁状态校验
     *
     * @param pjp
     * @return
     * @throws Throwable
     */
    @Around("passwordErrorFiniteValidate()")
    private Object doFiniteValidate(ProceedingJoinPoint pjp) throws Throwable {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        // 客户端IP
        String clientIp = IpUtil.getRemoteIP(request);
        // 白名单
        if (IpUtil.whiteOf(clientIp)) {
            return pjp.proceed();
        }
        // 补充白名单
        if (redisTemplate.opsForSet().isMember(Constants.IPV4_LOCK_WHITE, clientIp)) {
            return pjp.proceed();
        }
        // 入口服务器IP
        if (StringUtils.startsWith(clientIp, IpUtil.IO_IP)) {
            return pjp.proceed();
        }
        // 黑名单
        if (redisTemplate.opsForSet().isMember(Constants.IPV4_LOCK_BLACK, clientIp)) {
            IpUtil.logIp(log, request);
            log.info("Lock_ipv4: black ip access:{}", clientIp);
            return JsonResult.buildErrorStateResult("登录失败", null);
        }
        String lockIpv4Key = getLockIpv4Key(clientIp);
        String lock = redisTemplate.opsForValue().get(lockIpv4Key);
        if (Objects.equals(Boolean.TRUE.toString(), lock)) {
            IpUtil.logIp(log, request);
            log.info("Lock_ipv4: locked ip access:{}", clientIp);
            return JsonResult.buildErrorStateResult("登录失败", null);
        }
        return pjp.proceed();
    }

    private static String getLockIpv4Key(String ipv4) {
        return Constants.IPV4_LOCK + ipv4;
    }

}
