package cn.freemud.aop;

import cn.freemud.constant.CommonRedisKeyConstant;
import cn.freemud.entities.vo.ThirdPartLogVo;
import cn.freemud.enums.CommonResponseResult;
import cn.freemud.inteceptor.CommonServiceException;
import cn.freemud.redis.RedisCache;
import cn.freemud.utils.LogUtil;
import com.freemud.api.assortment.datamanager.entity.db.AssortmentOpenPlatformConfig;
import com.freemud.api.assortment.datamanager.entity.vo.AssortmentCustomerInfoVo;
import com.freemud.api.assortment.datamanager.manager.AssortmentOpenPlatformConfigManager;
import com.freemud.api.assortment.datamanager.manager.customer.AssortmentCustomerInfoManager;
import com.freemud.application.sdk.api.base.SDKCommonBaseContextWare;
import com.freemud.application.sdk.api.log.LogThreadLocal;
import com.freemud.application.sdk.api.log.ThirdPartyLog;
import lombok.extern.slf4j.Slf4j;
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.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

/**
 * All rights Reserved, Designed By www.freemud.cn
 *
 * @version V1.0
 * @Title: LogAspect
 * @Package cn.freemud.aop
 * @Description: 日志打印切面
 * @author: zhenghuan.yang
 * @date: 2018/5/26 10:13
 * @Copyright: 2018 www.freemud.cn Inc. All rights reserved.
 * 注意：本内容仅限于上海非码科技内部传阅，禁止外泄以及用于其他的商业目
 */
@Slf4j
@Aspect
@Component
public class WebAspect {

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private AssortmentOpenPlatformConfigManager assortmentOpenPlatformConfigManager;

    @Autowired
    private AssortmentCustomerInfoManager assortmentCustomerInfoManager;
    /**
     * 白名单key
     */
    private static final String KEY = "exclude.url";

    private static final String NOT_AUTHORIZED_KEY = "not.authorized.url";
    /**
     * 是否校验
     */
    private static final int STATE = 1;

    private static final String SESSION_ID_STR = "sessionId";

    private static final String APP_CHANNEL = "3";

    @Pointcut("execution(* cn.freemud.controller..*.*(..))")
    public void webAspect() {
    }

    @Around("webAspect()")
    public Object doBeforeController(ProceedingJoinPoint joinPoint) throws Throwable {
        RequestAttributes ra = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes sra = (ServletRequestAttributes) ra;
        HttpServletRequest request = sra.getRequest();
        String sessionId = request.getHeader(SESSION_ID_STR);
        if(!StringUtils.isEmpty(sessionId)) {
            String requestUrl = request.getRequestURI();
            List<String> notFilterUrls = Arrays.asList(getNotFilterUrl(CommonRedisKeyConstant.SAAS_NOT_FILTER_URL, KEY).split(","));
            // 是否授权验证
            AssortmentCustomerInfoVo userInfo = assortmentCustomerInfoManager.getCustomerInfoByObject(sessionId);
            if (!notFilterUrls.contains(requestUrl)) {
                if(userInfo == null) {
                    throw new CommonServiceException(CommonResponseResult.USER_UNAUTHORIZED);
                }
                // app 没有unionId得概念,   并且app上是thirdMemberId概念。 不需要做校验
                if(!Objects.equals(userInfo.getChannel(), APP_CHANNEL)) {
                    if(StringUtils.isEmpty(userInfo.getMemberId())) {
                        throw new CommonServiceException(CommonResponseResult.USER_UNAUTHORIZED);
                    }
                    List<String> unauthorizedUrls = Arrays.asList(getNotFilterUrl(CommonRedisKeyConstant.SAAS_NOT_AUTHORIZED_URL, NOT_AUTHORIZED_KEY).split(","));
                    if (!unauthorizedUrls.contains(requestUrl) && StringUtils.isEmpty(userInfo.getUnionId())) {
                        throw new CommonServiceException(CommonResponseResult.USER_UNAUTHORIZED);
                    }
                } else {
                    // app上是thirdMemberId概念
                }
            }
            Object[] args = joinPoint.getArgs();
            for (Object arg : args) {
                if (arg instanceof Object) {
                    PropertyDescriptor targetPd = BeanUtils.getPropertyDescriptor(arg.getClass(), SESSION_ID_STR);
                    if (targetPd == null) {
                        continue;
                    }
                    Method writeMethod = targetPd.getWriteMethod();
                    if (writeMethod != null) {
                        writeMethod.setAccessible(true);
                        writeMethod.invoke(arg, sessionId);
                        break;
                    }
                }
            }
        }
        Object result = null;
        try {
            result = joinPoint.proceed();
        } catch (Exception ex) {
            throw ex;
        }
        return result;
    }

    @Pointcut("execution(* cn.freemud.service.thirdparty..*.*(..))")
    public void clientLog() {
    }

    @Around("clientLog()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        long start = System.currentTimeMillis();
        Object result = null;
        try {
            result = joinPoint.proceed();
        } catch (Exception ex) {
            ThirdPartLogVo thirdPartLogVo = LogUtil.createThirdPartLogVo(joinPoint);
            LogUtil.thirdPartError(start, System.currentTimeMillis(), thirdPartLogVo, null);
            throw ex;
        }
        ThirdPartLogVo thirdPartLogVo = LogUtil.createThirdPartLogVo(joinPoint);
        // 打印第三方出参日志
        ThirdPartyLog.infoConvertJson(LogThreadLocal.getTrackingNo(), SDKCommonBaseContextWare.getAppName(),start,System.currentTimeMillis(),
                thirdPartLogVo.getUri(),thirdPartLogVo.getRequestBody(),result);
        return result;
    }

    public String getNotFilterUrl(String redisKey, String configKey) {
        String notFilterUrl;
        try {
            notFilterUrl = redisCache.getValue(redisKey);
        } catch (Exception e) {
            notFilterUrl = redisCache.getValue(redisKey);
        }
        if (org.apache.commons.lang.StringUtils.isBlank(notFilterUrl)) {
            AssortmentOpenPlatformConfig config = assortmentOpenPlatformConfigManager.selectOpenPlatformConfigByKey(configKey, STATE);
            if (config != null) {
                notFilterUrl = config.getGlobalValue();
                redisCache.save(redisKey, notFilterUrl);
            }
        }
        return notFilterUrl;
    }

}
