package com.qmth.themis.exam.interceptor;

import com.google.gson.Gson;
import com.qmth.themis.business.constant.SystemConstant;
import com.qmth.themis.business.dto.AuthDto;
import com.qmth.themis.business.dto.cache.TEStudentCacheDto;
import com.qmth.themis.business.entity.TBSession;
import com.qmth.themis.business.entity.TEStudent;
import com.qmth.themis.business.service.CacheService;
import com.qmth.themis.business.service.TEStudentService;
import com.qmth.themis.business.util.RedisUtil;
import com.qmth.themis.business.util.ServletUtil;
import com.qmth.themis.common.enums.ExceptionResultEnum;
import com.qmth.themis.common.enums.Platform;
import com.qmth.themis.common.exception.BusinessException;
import com.qmth.themis.common.signature.SignatureInfo;
import com.qmth.themis.common.signature.SignatureType;
import com.qmth.themis.exam.config.DictionaryConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.Objects;
import java.util.Set;

/**
 * @Description: 鉴权拦截器
 * @Param:
 * @return:
 * @Author: wangliang
 * @Date: 2020/6/27
 */
public class AuthInterceptor implements HandlerInterceptor {
    private final static Logger log = LoggerFactory.getLogger(AuthInterceptor.class);

    @Resource
    CacheService cacheService;

    @Resource
    DictionaryConfig dictionaryConfig;

    @Resource
    TEStudentService teStudentService;

    @Resource
    RedisUtil redisUtil;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object object) throws Exception {
        log.info("exam HandlerInterceptor preHandle is come in");
        String url = request.getServletPath();
        String method = request.getMethod();
        if (url.equalsIgnoreCase(SystemConstant.ERROR)) {
            throw new BusinessException(ExceptionResultEnum.NOT_FOUND);
        }
        Platform platform = Platform.valueOf(ServletUtil.getRequestPlatform());
        String deviceId = ServletUtil.getRequestDeviceId();
        String authorization = ServletUtil.getRequestAuthorization();
        String time = ServletUtil.getRequestTime();
        log.info("platform:{},deviceId:{},authorization:{},method:{},time:{}", platform, deviceId, authorization, method, time);
        Long userId = null;
//        Long timestamp = Long.parseLong(ServletUtil.getRequestTime(request));
//        if (!SystemConstant.expire(timestamp.longValue())) {
//            final SignatureInfo info = SignatureInfo
//                    .parse(method, url, timestamp, ServletUtil.getRequestAuthorization(request));
        //测试
        final SignatureInfo info = SignatureInfo
                .parse(authorization);
        if (Objects.nonNull(info) && info.getType() == SignatureType.TOKEN) {
            String sessionId = info.getInvoker();
            TBSession tbSession = (TBSession) redisUtil.getUserSession(sessionId);
            if (Objects.isNull(tbSession)) {
                throw new BusinessException(ExceptionResultEnum.LOGIN_NO);
            } else {
                if (info.validate(tbSession.getAccessToken()) && info.getTimestamp() < tbSession.getExpireTime()
                        && platform.name().equalsIgnoreCase(tbSession.getPlatform()) && Objects.equals(deviceId, tbSession.getDeviceId())) {
                    userId = Long.parseLong(tbSession.getIdentity());
                    Long expireTime = tbSession.getExpireTime();
                    //手机端的token时长为一个月，所以会出现缓存没有的情况
                    if (expireTime <= System.currentTimeMillis()) {//先判断时间是否过期
                        throw new BusinessException(ExceptionResultEnum.LOGIN_NO);
                    }
                    TEStudentCacheDto teStudentCacheDto = (TEStudentCacheDto) redisUtil.getStudent(userId);
                    if (Objects.isNull(teStudentCacheDto)) {
                        TEStudent teStudent = teStudentService.getById(userId);
                        Gson gson = new Gson();
                        teStudentCacheDto = gson.fromJson(gson.toJson(teStudent), TEStudentCacheDto.class);
                        redisUtil.setStudent(teStudent.getId(), teStudentCacheDto);
                    }

                    request.setAttribute(SystemConstant.SESSION, tbSession);
                    request.setAttribute(SystemConstant.STUDENT_ACCOUNT, teStudentCacheDto);

                    AuthDto authDto = (AuthDto) redisUtil.get(SystemConstant.studentOauth + "::" + userId);
                    //验证权限
                    if (Objects.isNull(authDto)) {
                        authDto = cacheService.addStudentCache(userId);
                    }
                    request.setAttribute(SystemConstant.ORG, authDto.getTbOrg());
                    //系统管理员拥有所有权限
//                    if (authDto.getRoleCodes().contains(RoleEnum.SUPER_ADMIN.name())) {
//                        return true;
//                    }
                    //系统公用接口不拦截
                    List<String> sysUrls = dictionaryConfig.systemUrlDomain().getUrls();
                    int sysCount = (int) sysUrls.stream().filter(s -> {
                        return s.equalsIgnoreCase(url);
                    }).count();
                    if (sysCount > 0) {
                        return true;
                    }
                    Set<String> urls = authDto.getUrls();
                    int count = (int) urls.stream().filter(s -> {
                        return s.equalsIgnoreCase(url);
                    }).count();
                    if (count == 0) {
                        throw new BusinessException(ExceptionResultEnum.UN_AUTHORIZATION);
                    }
                } else {
                    throw new BusinessException(ExceptionResultEnum.AUTHORIZATION_ERROR);
                }
            }
        } else {
            throw new BusinessException(ExceptionResultEnum.AUTHORIZATION_ERROR);
        }
//        } else {
//            throw new BusinessException(ExceptionResultEnum.AUTHORIZATION_ERROR);
//        }
        response.setStatus(ExceptionResultEnum.SUCCESS.getStatusCode());
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request,
                           HttpServletResponse response,
                           Object o, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest request,
                                HttpServletResponse response,
                                Object o, Exception e) throws Exception {
    }
}
