package com.yeejoin.amos.boot.biz.common.aop;

import com.alibaba.fastjson.JSONObject;
import com.yeejoin.amos.boot.biz.common.bo.CompanyBo;
import com.yeejoin.amos.boot.biz.common.bo.DepartmentBo;
import com.yeejoin.amos.boot.biz.common.bo.ReginParams;
import com.yeejoin.amos.boot.biz.common.bo.RoleBo;
import com.yeejoin.amos.boot.biz.common.utils.RedisKey;
import com.yeejoin.amos.boot.biz.common.utils.RedisUtils;
import com.yeejoin.amos.component.feign.model.FeignClientResult;
import com.yeejoin.amos.feign.privilege.Privilege;
import com.yeejoin.amos.feign.privilege.model.AgencyUserModel;
import com.yeejoin.amos.feign.privilege.model.CompanyModel;
import com.yeejoin.amos.feign.privilege.model.DepartmentModel;
import com.yeejoin.amos.feign.privilege.model.RoleModel;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.typroject.tyboot.core.auth.exception.AuthException;
import org.typroject.tyboot.core.foundation.context.RequestContext;
import org.typroject.tyboot.core.foundation.utils.Bean;
import org.typroject.tyboot.core.foundation.utils.ValidationUtil;

import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * controller层切面 用于用户数据缓存 供 sql自动填充使用
 *
 * @author Admin
 */
@Aspect
@Component
@Order(value = 0)
public class ControllerAop {
    /**
     * saveUserRedis设置过期时间
     */
    @Value("${redis.cache.failure.time}")
    private Long redisRegionTimeSecond;

    @Autowired
    private RedisUtils redisUtils;

    @Pointcut("(execution(public * com.yeejoin.amos.boot.module.*.biz.controller..*(..)) "
    		+ "|| execution(public * com.yeejoin.amos.*.business.controller..*(..)))"
    		+ " && !@annotation(org.springframework.scheduling.annotation.Scheduled))")
    public void userCache() {

    }

    @Before("userCache()")
    public void doBefore(JoinPoint joinPoint) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        //TODO tyboot 框架拦截器已缓存数据
        String token = RequestContext.getToken();
        // 平台studio配置的下载接口token从url里取
        if (ValidationUtil.isEmpty(token)) {
            fillRequestContext(request);
            token = RequestContext.getToken();
        }
        // 不需要添加请求头的接口
        String[] url = new String[]{"/api/user/selectInfo", "/api/user/save/curCompany", "/jcs/command/lookHtmlText"};
        // 获取请求路径
        if (Arrays.asList(url).contains(request.getRequestURI())) {
            return;
        }
        if (token != null) {
            String pattern = RedisKey.buildPatternKey(token);
            //验证token有效性，防止token失效
            AgencyUserModel userModel;
            try {
                FeignClientResult<AgencyUserModel> agencyUserModel = Privilege.agencyUserClient.getme();
                userModel = agencyUserModel.getResult();
                if (userModel == null) {
                    throw new Exception("无法获取用户信息");
                }
            } catch (Exception e) {
                //删除失效token缓存
                redisUtils.getAndDeletePatternKeys(pattern);
                throw new RuntimeException(e.getMessage());
            }
            saveUserRedis(userModel, token);
        } else {
            throw new AuthException("请求未包含认证信息.");
        }
    }

    private void saveUserRedis(AgencyUserModel user, String token) {
        String authToken = RedisKey.buildReginKey(user.getUserId(), token);
        if (redisUtils.hasKey(authToken)) {
            return;
        }
        CompanyBo company = new CompanyBo();
        DepartmentBo department = new DepartmentBo();
        RoleBo role = new RoleBo();
        CompanyModel companyM = user.getCompanys().get(0);
        Bean.copyExistPropertis(companyM, company);
        Map<Long, List<DepartmentModel>> mapDepartments = user.getCompanyDepartments();
        DepartmentModel departmentM = mapDepartments.get(companyM.getSequenceNbr()).get(0);
        Bean.copyExistPropertis(departmentM, department);
        Map<Long, List<RoleModel>> roles = user.getOrgRoles();
        Long sequenceNbr;
        if (departmentM == null) {
            sequenceNbr = null;
        } else {
            sequenceNbr = departmentM.getSequenceNbr();
        }
        RoleModel roleM = null;
        if (sequenceNbr == null) {
            roleM = roles.get(companyM.getSequenceNbr()).get(0);
        } else {
            roleM = roles.get(sequenceNbr).get(0);
        }
        Bean.copyExistPropertis(roleM, role);
        ReginParams reginParams = new ReginParams();
        reginParams.setCompany(company);
        reginParams.setRole(role);
        reginParams.setDepartment(department);
        reginParams.setUserModel(user);
        redisUtils.set(authToken, JSONObject.toJSONString(reginParams), redisRegionTimeSecond);
    }

    @AfterReturning(returning = "ret", pointcut = "userCache()")
    public void doAfterReturning(Object ret) throws Throwable {
        //统一redis管理
//        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
//        HttpServletRequest request = attributes.getRequest();
//        String token = request.getHeader("token");
//        if (token != null) {
//            GlobalCache.paramMap.remove(token);
//        }
    }

    private void fillRequestContext(HttpServletRequest request) {
        String token = request.getParameterMap().get("token")[0];
        String product = request.getParameterMap().get("product")[0];
        String appKey = request.getParameterMap().get("appKey")[0];
        RequestContext.setToken(token);
        RequestContext.setProduct(product);
        RequestContext.setAppKey(appKey);
    }
}
