package com.qmth.teachcloud.common.util;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.qmth.boot.tools.signature.SignatureEntity;
import com.qmth.boot.tools.signature.SignatureType;
import com.qmth.teachcloud.common.contant.SpringContextHolder;
import com.qmth.teachcloud.common.entity.BasicSchool;
import com.qmth.teachcloud.common.entity.TBSession;
import com.qmth.teachcloud.common.enums.ExceptionResultEnum;
import com.qmth.teachcloud.common.service.BasicSchoolService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletRequest;
import java.util.Optional;

/**
 * @Description: 第三方鉴权util
 * @Param:
 * @return:
 * @Author: wangliang
 * @Date: 2022/5/27
 */
public class AuthThirdUtil {
    private final static Logger log = LoggerFactory.getLogger(AuthThirdUtil.class);

    /**
     * 鉴权
     *
     * @param expireTime
     * @param authorization
     * @return
     */
    public static TBSession hasPermissionLogout(Long expireTime, String authorization) {
        RedisUtil redisUtil = SpringContextHolder.getBean(RedisUtil.class);
        HttpServletRequest request = ServletUtil.getRequest();
        String url = request.getServletPath();
        //验证authorization
        Optional.ofNullable(authorization).orElseThrow(() -> ExceptionResultEnum.AUTHORIZATION_INVALID.exception());
        Optional.ofNullable(expireTime).orElseThrow(() -> ExceptionResultEnum.TIME_INVALID.exception());

        String method = request.getMethod();
        final SignatureEntity info = SignatureEntity.parse(authorization, method, url, expireTime);
        Optional.ofNullable(info).orElseThrow(() -> ExceptionResultEnum.AUTHORIZATION_ERROR.exception());

        if (!url.equalsIgnoreCase(info.getUri())) {
            log.warn("url faile: url error");
            throw ExceptionResultEnum.AUTHORIZATION_ERROR.exception();
        }
        if (!method.equalsIgnoreCase(info.getMethod())) {
            log.warn("method faile: method error");
            throw ExceptionResultEnum.AUTHORIZATION_ERROR.exception();
        }
        if (info.getTimestamp() > expireTime) {
            log.warn("Authorization faile: session has expired, expire time=" + expireTime);
            throw ExceptionResultEnum.TIME_INVALID.exception();
        }
        if (SignatureType.TOKEN != info.getType()) {
            log.warn("Authorization faile: signature type is not Token");
            throw ExceptionResultEnum.AUTHORIZATION_ERROR.exception();
        }
        TBSession tbSession = (TBSession) redisUtil.getUserSession(info.getInvoker());
        Optional.ofNullable(tbSession).orElseThrow(() -> ExceptionResultEnum.AUTHORIZATION_ERROR.exception());
        if (!info.validate(tbSession.getAccessToken())) {
            log.warn("Authorization faile: token invalid, token is " + tbSession.getAccessToken());
            throw ExceptionResultEnum.AUTHORIZATION_ERROR.exception();
        }
        return tbSession;
    }

    /**
     * 鉴权
     *
     * @param expireTime
     * @param authorization
     * @return
     */
    public static BasicSchool hasPermission(Long expireTime, String authorization) {
        return commonHasPermission(expireTime, authorization);
    }

    /**
     * 鉴权
     *
     * @return
     */
    public static BasicSchool hasPermission() {
        return commonHasPermission(ServletUtil.getRequestTime(), ServletUtil.getRequestAuthorization());
    }

    /**
     * 公用方法
     *
     * @param expireTime
     * @param authorization
     * @return
     */
    protected static BasicSchool commonHasPermission(Long expireTime, String authorization) {
        BasicSchoolService basicSchoolService = SpringContextHolder.getBean(BasicSchoolService.class);
        HttpServletRequest request = ServletUtil.getRequest();
        String url = request.getServletPath();
        //验证authorization
        Optional.ofNullable(authorization).orElseThrow(() -> ExceptionResultEnum.AUTHORIZATION_INVALID.exception());
        Optional.ofNullable(expireTime).orElseThrow(() -> ExceptionResultEnum.TIME_INVALID.exception());

        String method = request.getMethod();
        final SignatureEntity info = SignatureEntity.parse(authorization, method, url, expireTime);
        Optional.ofNullable(info).orElseThrow(() -> ExceptionResultEnum.AUTHORIZATION_ERROR.exception());

        if (!url.equalsIgnoreCase(info.getUri())) {
            log.warn("url faile: url error");
            throw ExceptionResultEnum.AUTHORIZATION_ERROR.exception();
        }
        if (!method.equalsIgnoreCase(info.getMethod())) {
            log.warn("method faile: method error");
            throw ExceptionResultEnum.AUTHORIZATION_ERROR.exception();
        }
        if (info.getTimestamp() > expireTime) {
            log.warn("Authorization faile: session has expired, expire time=" + expireTime);
            throw ExceptionResultEnum.TIME_INVALID.exception();
        }
        if (SignatureType.SECRET != info.getType()) {
            log.warn("Authorization faile: signature type is not Secret");
            throw ExceptionResultEnum.AUTHORIZATION_ERROR.exception();
        }
        QueryWrapper<BasicSchool> basicSchoolQueryWrapper = new QueryWrapper<>();
        basicSchoolQueryWrapper.lambda().eq(BasicSchool::getAccessKey, info.getInvoker());
        BasicSchool basicSchool = basicSchoolService.getOne(basicSchoolQueryWrapper);
        Optional.ofNullable(basicSchool).orElseThrow(() -> ExceptionResultEnum.AUTHORIZATION_ERROR.exception("没有学校信息"));
        if (!info.validate(basicSchool.getAccessSecret())) {
            log.warn("Authorization faile: secret invalid, secret is " + basicSchool.getAccessSecret());
            throw ExceptionResultEnum.AUTHORIZATION_ERROR.exception();
        }
        return basicSchool;
    }
}
