package com.inkasso.auth.scanner;

import com.google.common.collect.Lists;
import com.inkasso.auth.domain.PermissionDO;
import com.inkasso.auth.interfaces.Permission;
import com.inkasso.auth.interfaces.Permissions;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * @author 张超
 * @date 2021/10/22
 */
public class PermissionScanner implements BeanPostProcessor {

  private static List<PermissionDO> permissionDOList = Lists.newArrayList();

  private static Map<String, PermissionDO> permissionMap = null;


  @Override
  public Object postProcessBeforeInitialization(Object bean, String beanName) {
    String parentPath = null;
    Permissions permissionBeanAnno = bean.getClass().getAnnotation(Permissions.class);
    if (permissionBeanAnno != null) {
      //查看类上面是否有ReqestMapping注解
      RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(bean.getClass(),
          RequestMapping.class);
      if (requestMapping != null) {
        String[] parentPaths = requestMapping.path();
        if (parentPaths.length > 0) {
          parentPath = parentPaths[0];
        }
      }
      //说明该类中含有权限注解需要 需要找到类中的方法
      Method[] methods = bean.getClass().getMethods();
      if (methods != null && methods.length > 0) {
        for (Method m : methods) {

          Permission permissionAnno = AnnotatedElementUtils.findMergedAnnotation(m,
              Permission.class);
          if (permissionAnno != null) {

            RequestMapping methodRequestMapping = AnnotatedElementUtils.findMergedAnnotation(m,
                RequestMapping.class);
            if (methodRequestMapping == null) {
              throw new RuntimeException(bean.getClass().getName() + "." + m.getName()
                  + "中 Permission注解需要和RequestMapping注解一起使用");
            }
            RequestMethod[] requestMethods = methodRequestMapping.method();
            String[] methodPath = methodRequestMapping.path();
            if (requestMethods.length == 0 || methodPath.length == 0) {
              throw new RuntimeException(
                  bean.getClass().getName() + "." + m.getName() + "中 RequestMapping注解请遵循restful风格");
            }
            PermissionDO permissionDO = new PermissionDO();
            permissionDO.setId(bean.getClass().getSimpleName()+"$"+m.getName());
            permissionDO.setCode(permissionAnno.code());
            permissionDO.setName(permissionAnno.name());
            permissionDO.setRequireCheck(permissionAnno.check());
            permissionDO.setModuleName(permissionBeanAnno.name());
            permissionDO.setModuleCode(permissionBeanAnno.code());
            permissionDO.setMethod(methodRequestMapping.method()[0].name());
            permissionDO.setUrl(getRequestPath(parentPath, methodPath[0]));

            permissionDOList.add(permissionDO);

          }
        }
      }
    }
    //校验权限对象判断是否重复

    return bean;
  }

  /**
   * 获取全部权限点集合
   *
   * @return
   */
  public static List<PermissionDO> getPermissionList() {
    return permissionDOList;
  }

  /**
   * 获取需要校验权限的权限点
   *
   * @return
   */
  public static Map<String, PermissionDO> getPermissionMap() {
    if (permissionMap == null) {
      permissionMap = permissionDOList.stream()
          .filter(permissionDO -> permissionDO.getRequireCheck()).collect(
              Collectors.toMap(PermissionDO::getCode, Function.identity(), (key1, key2) -> key2));

    }
    return permissionMap;
  }


  private String getRequestPath(String parentPath, String methodPath) {

    StringBuffer sb = new StringBuffer();
    sb.append(parentPath)
        .append("/")
        .append(methodPath);
    String oldUlr = changeStr(sb.toString());
    //清空buffer
    sb.setLength(0);
    //进行一个逻辑操作将多余的/ 取出且 将带有{xxx} 的 偷换成 *
    boolean charflag = false;
    for (int i = 0; i < oldUlr.length(); i++) {

      if ('/' == oldUlr.charAt(i)) {
        if (!charflag) {
          sb.append(oldUlr.charAt(i));
        }
        charflag = true;
      } else {
        charflag = false;
        sb.append(oldUlr.charAt(i));
      }

    }
    return sb.toString();
  }

  /**
   * 替换路径中 带有 {xxxxx} --> {*}
   *
   * @param old
   * @return
   */
  private String changeStr(String old) {
    if (StringUtils.hasLength(old)) {
      return old;
    }
    String regex = "\\{([^}])*\\}";
    Pattern pattern = Pattern.compile(regex);
    Matcher matcher = pattern.matcher(old);
    while (matcher.find()) {
      old = old.replace(matcher.group(), "*");
    }
    return old;
  }
}
