package com.ycwl.basic.interceptor;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.ycwl.basic.annotation.IgnoreToken;
import com.ycwl.basic.constant.BaseContextHandler;
import com.ycwl.basic.constant.PermissionConstant;
import com.ycwl.basic.constant.RequestConstant;
import com.ycwl.basic.exception.CheckTokenException;
import com.ycwl.basic.exception.MissTokenException;
import com.ycwl.basic.exception.PermissionException;
import com.ycwl.basic.model.jwt.JwtInfo;
import com.ycwl.basic.utils.JwtTokenUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;

@Slf4j
@Component
public class AuthInterceptor implements HandlerInterceptor {

    @Autowired
    RedisTemplate redisTemplate;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (!(handler instanceof HandlerMethod handlerMethod)) {
            return true;
        }
        String requestURI = request.getRequestURI();

        // 获取类上面的注解
        IgnoreToken ignoreClassToken = handlerMethod.getBeanType().getAnnotation(IgnoreToken.class);
        // 获取方法上的注解
        IgnoreToken ignoreMethodToken = handlerMethod.getMethodAnnotation(IgnoreToken.class);
        if (ignoreClassToken != null || ignoreMethodToken != null) {
            // 放行
            return true;
        }

        // 放行白名单
        if (getWhite(request.getRequestURI())) {
            return true;
        }

        /*
        验证token
         */
        // 获取 token
        String token = getToken(request);
        if (StringUtils.isEmpty(token)) {
            log.error("==>  请求 header 缺少 Token [{}], URL [{}]", token, request.getRequestURL());
            throw new MissTokenException("请求头缺少token");
        }


        // 解析 token  & 验证 token 有效期
        JwtInfo jwtInfo;
        try {
            jwtInfo = JwtTokenUtil.parsingToken(token);
//            LocalDateTime expireTime = jwtInfo.getExpireTime();
//            if (LocalDateTime.now(ZoneId.systemDefault()).isAfter(expireTime)) {
//                throw new TokenExpireException("token过期");
//            }
            BaseContextHandler.setToken(token);
            BaseContextHandler.setName(jwtInfo.getName());
            BaseContextHandler.setUserId(String.valueOf(jwtInfo.getUserId()));
            BaseContextHandler.setAccount(jwtInfo.getAccount());
            BaseContextHandler.setPhone(jwtInfo.getPhone());
            BaseContextHandler.setRoleId(jwtInfo.getRoleId());
            BaseContextHandler.setUserExpireTime(jwtInfo.getExpireTime());
        } catch (CheckTokenException e) {
            throw new CheckTokenException("token无效");
        }

//        if (getBusinessWhite(requestURI)) {
//            if (!getPermission(jwtInfo.getRoleId(), requestURI)) {
//                throw new PermissionException("无权访问");
//            }
//        }

        return true;
    }

    public static void sendJsonMessage(HttpServletResponse response, Object obj) {

        ObjectMapper objectMapper = new ObjectMapper();
        response.setContentType("application/json; charset=utf-8");

        try (PrintWriter writer = response.getWriter()) {
            writer.print(objectMapper.writeValueAsString(obj));
            response.flushBuffer();
        } catch (IOException e) {
            log.warn("响应json数据给前端异常 -> {}", e.getMessage(), e);
        }

    }


    /**
     * 在请求完全结束后调用, 常用于清理资源等工作
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        BaseContextHandler.remove();
    }

    public String getToken(HttpServletRequest request) {
        String token = request.getHeader("token");
        if (StringUtils.isEmpty(token)) {
            if (request.getCookies() != null) {
                for (Cookie cookie : request.getCookies()) {
                    if (("token").equals(cookie.getName())) {
                        token = cookie.getValue();
                    }
                }
            }
        }
        return token;
    }


    //白名单swagger2
    private boolean getWhite(String path) {
        return StringUtils.containsAny(
                path,
                "springfox", "swagger", "v2",
                "webjars", "doc.html", "favicon.ico"
        );
    }

    /**
     * 业务接口白名单
     *
     * @param
     * @return
     */
    private boolean getBusinessWhite(String path) {
        if (path.contains(RequestConstant.UPDATE_PASSWORD)) {
            return false;
        }
        return true;
    }


    private boolean getPermission(String roleId, String url) {
        Object permissionUrl = redisTemplate.opsForValue().get(PermissionConstant.USER_PERMISSION_URL + roleId);
        if (permissionUrl != null) {
            List<String> permissionUrlList = (List<String>) permissionUrl;
            String urlWithParameters = url.substring(url.lastIndexOf("/") + 1, url.length());
            boolean flag = StringUtils.isNumeric(urlWithParameters);
            if (flag) {
                url = url.substring(0, url.lastIndexOf("/"));
            }
            for (String str : permissionUrlList) {
                if (str.equals(url)) {
                    return true;
                }

            }
        }
        return false;
    }

}
