package com.inkasso.adapter;

import com.inkasso.adapter.bean.AbstractUser;
import com.inkasso.adapter.exception.ServiceException;
import com.inkasso.adapter.exception.enums.ExceptionEnum;
import com.inkasso.adapter.interfaces.AvoidRepeatableCommit;
import com.inkasso.adapter.web.LoginUserHolder;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.data.redis.core.RedisTemplate;

import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;

@Aspect
public class AvoidRepeatableCommitCheckBean {

  private static Logger logger = LoggerFactory.getLogger(AvoidRepeatableCommitCheckBean.class);

  @Autowired
  private RedisTemplate redisTemplate;

  private static final String PREFIX = "AvoidRepeatableCommit";
  private static final String MARK = ":";


  @Pointcut("@annotation(com.inkasso.adapter.interfaces.AvoidRepeatableCommit)")
  public void repeatableCommit() {
  }

  @Around("repeatableCommit()")
  public Object check(ProceedingJoinPoint point) throws Throwable {
    MethodSignature signature = (MethodSignature) point.getSignature();
    Method method = signature.getMethod();
    AvoidRepeatableCommit annotation = AnnotatedElementUtils.findMergedAnnotation(method,
        AvoidRepeatableCommit.class);
    String key = annotation.key();
    AbstractUser abstractUser = LoginUserHolder.get();
    String redisKey = getKey(key, abstractUser);
    Object o = redisTemplate.opsForValue().get(redisKey);
    if(o!=null){
      throw new ServiceException(400, ExceptionEnum.SAME_REQUEST);
    }else{
      redisTemplate.opsForValue().set(redisKey,true,5, TimeUnit.SECONDS);
    }
    Object result = point.proceed();
    redisTemplate.delete(redisKey);

    return result;

  }


  @AfterThrowing(value = "repeatableCommit()", throwing = "exception")
  public void doAfterThrowingAdvice(JoinPoint joinPoint, Throwable exception) {
    try {
      MethodSignature signature = (MethodSignature) joinPoint.getSignature();
      Method method = signature.getMethod();
      AvoidRepeatableCommit annotation = AnnotatedElementUtils.findMergedAnnotation(method,
          AvoidRepeatableCommit.class);
      String key = annotation.key();
      AbstractUser abstractUser = LoginUserHolder.get();
      String redisKey = getKey(key, abstractUser);
      redisTemplate.delete(redisKey);
    } catch (Exception ex) {
    }
  }


  private String getKey(String key, AbstractUser user) {
    StringBuffer sb = new StringBuffer();
    String s = sb.append(PREFIX).append(MARK).append(key).append(user.getId())
        .toString();
    return s;
  }

}