package com.sckw.core.filter;

import com.alibaba.fastjson.JSON;
import com.sckw.core.model.constant.Global;
import com.sckw.core.model.enums.ClientTypeEnum;
import com.sckw.core.model.enums.SystemTypeEnum;
import com.sckw.core.utils.EncryUtil;
import com.sckw.core.utils.NumberUtils;
import com.sckw.core.utils.StringUtils;
import com.sckw.core.web.config.CustomConfig;
import com.sckw.core.web.constant.HttpStatus;
import com.sckw.core.web.constant.RequestConstant;
import com.sckw.core.web.context.LoginEntHolder;
import com.sckw.core.web.context.LoginUserHolder;
import com.sckw.core.web.model.LoginEntInfo;
import com.sckw.core.web.model.LoginUserInfo;
import com.sckw.core.web.response.HttpResult;
import com.sckw.core.web.response.ResponseUtil;
import com.sckw.redis.utils.RedissonUtils;
import jakarta.annotation.PostConstruct;
import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;

import java.io.IOException;
import java.util.*;

/**
 * @desc: 登录过滤
 * @author: czh
 * @date: 2023/6/14
 */
public class RequestCheckFilter implements Filter {

    @Autowired
    CustomConfig customConfig;

    /**
     * 直接放行不需要校验token的请求
     */
    private static final List<String> EXCLUDEPATH = new ArrayList<>();

    /**
     * 需要校验token但不用接口权限校验的请求
     */
    private static final List<String> WITHOUTPATH = new ArrayList<>();

    private static final String REGISTER = "/kwsEnt/register";

    /**
     * @desc: 初始化放行路径
     * @author: czh
     */
    @PostConstruct
    private void initExcludePath() {
        String links = customConfig.getLinks();
        if (StringUtils.isNotBlank(links)) {
            EXCLUDEPATH.addAll(Arrays.asList(links.split(Global.COMMA)));
        }
//        String withoutLinks = customConfig.getWithoutLinks();
//        if (StringUtils.isNotBlank(withoutLinks)) {
//            WITHOUTPATH.addAll(Arrays.asList(withoutLinks.split(Global.COMMA)));
//        }
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
                         FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        String token = request.getHeader(RequestConstant.TOKEN);
        String clientType = request.getHeader(RequestConstant.CLIENT_TYPE);
        String systemType = request.getHeader(RequestConstant.SYSTEM_TYPE);
        String requestUri = request.getRequestURI();

        /*1、非token校验接口放行*/
        if (EXCLUDEPATH.contains(requestUri)) {
            filterChain.doFilter(servletRequest, servletResponse);
            return;
        }

        /*2、校验token**/
        /*2.1、校验token非空*/
        if (StringUtils.isBlank(token)) {
            ResponseUtil.writer(response, HttpResult.error(HttpStatus.UN_LOGIN_CODE, HttpStatus.UN_LOGIN_MESSAGE));
            return;
        }

        /*2.2、token解析*/
        Map<String, Object> tokenMap = EncryUtil.descryV2(Global.PRI_KEY, token);
        if (tokenMap == null) {
            ResponseUtil.writer(response, HttpResult.error(HttpStatus.TOKEN_INVALID_CODE, HttpStatus.TOKEN_INVALID_MESSAGE));
            return;
        }

        /*2.3、从redis获取用户登录token*/
        Long userId = StringUtils.isNotBlank(tokenMap.get("userId")) ? NumberUtils.parseLong(tokenMap.get("userId")) : null;
        String redisUserToken = RedissonUtils.getString(Global.getFullUserTokenKey(clientType, userId));
        if (StringUtils.isBlank(redisUserToken)) {
            ResponseUtil.writer(response, HttpResult.error(HttpStatus.TOKEN_INVALID_CODE, HttpStatus.TOKEN_INVALID_MESSAGE));
            return;
        }

        /*2.4、请求token和redis中token不一致,说明账号在别处登录了*/
        if (!token.equals(redisUserToken)) {
            ResponseUtil.writer(response, HttpResult.error(HttpStatus.ACCOUNT_OTHER_LOGIN_CODE, HttpStatus.ACCOUNT_OTHER_LOGIN_MESSAGE));
            return;
        }

        /*3、校验登录用户信息*/
        String key = Global.getFullUserLoginKey(NumberUtils.parseInt(systemType), userId);
        String userInfoStr = RedissonUtils.getString(key);
        LoginUserInfo loginUserInfo = StringUtils.isNotBlank(userInfoStr) ? JSON.parseObject(userInfoStr, LoginUserInfo.class) : null;
        if (Objects.isNull(loginUserInfo)) {
            ResponseUtil.writer(response, HttpResult.error(HttpStatus.TOKEN_INVALID_CODE, HttpStatus.TOKEN_INVALID_MESSAGE));
            return;
        }


        //校验用户账号是否冻结
        if (loginUserInfo.getStatus() == Global.YES) {
            ResponseUtil.writer(response, HttpResult.error(HttpStatus.TOKEN_INVALID_CODE, "您的账号已被冻结，请联系系统管理员！"));
            return;
        }

        /*4、登录中的企业信息*/
        String loginEntStr = RedissonUtils.getString(Global.getFullUserEntKey(loginUserInfo.getEntId()));
        LoginEntInfo loginEntInfo = StringUtils.isNotBlank(loginEntStr) ? JSON.parseObject(loginEntStr, LoginEntInfo.class) : null;

        if (SystemTypeEnum.MANAGE.getCode().equals(Integer.parseInt(systemType))) {
            LoginUserHolder.set(loginUserInfo);
            LoginEntHolder.set(loginEntInfo);
            RedissonUtils.putString(Global.getFullUserTokenKey(clientType, userId), token, ClientTypeEnum.expireTime(clientType));
            RedissonUtils.putString(Global.getFullUserLoginKey(NumberUtils.parseInt(systemType), loginUserInfo.getId()), JSON.toJSONString(loginUserInfo), Global.APP_TOKEN_EXPIRE);
            RedissonUtils.putString(Global.getFullUserEntKey(loginEntInfo.getId()), JSON.toJSONString(loginEntInfo), Global.APP_TOKEN_EXPIRE);
            filterChain.doFilter(servletRequest, servletResponse);
            LoginUserHolder.remove();
            return;
        }

        if ((StringUtils.isBlank(loginEntStr) || loginEntInfo == null) && NumberUtils.parseInt(systemType) != SystemTypeEnum.MANAGE.getCode()) {
            ResponseUtil.writer(response, HttpResult.error(HttpStatus.TOKEN_INVALID_CODE, HttpStatus.UN_LOGIN_MESSAGE));
            return;
        } else {
            //校验用户企业是否冻结
            if (Objects.isNull(loginEntInfo) || loginEntInfo.getStatus() == Global.YES) {
                ResponseUtil.writer(response, HttpResult.error(HttpStatus.TOKEN_INVALID_CODE, "您所属企业已被冻结，请联系系统管理员！"));
                return;
            }

            //校验用户企业审批状态
            if (!loginEntInfo.getValid() && !REGISTER.equals(requestUri)) {
                if(loginEntInfo.getApproval() == Global.NO){
                    ResponseUtil.writer(response, HttpResult.error(HttpStatus.CODE_60603, HttpStatus.ENTCERTIFICATES_NOT_REGISTER));
                    return;
                }

                if(loginEntInfo.getApproval() == Global.NUMERICAL_THREE){
                    ResponseUtil.writer(response, HttpResult.error(HttpStatus.CODE_60603, HttpStatus.ENTCERTIFICATES_NOT_PASS));
                    return;
                }

                ResponseUtil.writer(response, HttpResult.error(HttpStatus.CODE_60603, HttpStatus.ENTCERTIFICATES_INVAILD));
                return;
            }
        }

        /*5、请求权限校验*/
        //非管理员有接口权限才放行
//        if (loginUserInfo.getIsMain() == Global.NO
//                && !WITHOUTPATH.contains(requestUri)
//                && !checkMenu(clientType, loginUserInfo.getId(), requestUri)) {
//            ResponseUtil.writer(response, HttpResult.error(HttpStatus.AUTHORITY_NO_CODE, HttpStatus.ACCESS_FIAL));
//            return;
//        }

        LoginUserHolder.set(loginUserInfo);
        LoginEntHolder.set(loginEntInfo);
        RedissonUtils.putString(Global.getFullUserLoginKey(NumberUtils.parseInt(systemType), loginUserInfo.getId()), JSON.toJSONString(loginUserInfo), Global.APP_TOKEN_EXPIRE);
        RedissonUtils.putString(Global.getFullUserEntKey(loginEntInfo.getId()), JSON.toJSONString(loginEntInfo), Global.APP_TOKEN_EXPIRE);
        RedissonUtils.putString(Global.getFullUserTokenKey(clientType, userId), token, ClientTypeEnum.expireTime(clientType));
        filterChain.doFilter(servletRequest, servletResponse);
        LoginUserHolder.remove();
        LoginEntHolder.remove();
    }


    /**
     * @param userId 用户菜单权限key  url 当前请求url
     * @return boolean
     * @desc: 校验url权限
     * @author: czh
     * @date: 2023/6/28
     */
    private boolean checkMenu(String clientType, Long userId, String url) {
        return RedissonUtils.contains(Global.REDIS_SYS_MENU_PREFIX + clientType + Global.COLON + userId, url);
    }

    public static void main(String[] args) {
        Map<String, Object> tokenMap = EncryUtil.descryV2(Global.PRI_KEY, "dade5058e78847ca5672263c5b821fc09d06083611ab0f6d076af88f082f0538569486c2369c2aae99f2a8fc7a7de07b57aa7ffadb3c958ef83cb50a10819703d3cb745c501326d65d50ed5aba830326eb64a75b0479f896763a9810e847f430");
        System.out.println(tokenMap);
    }
}
