package com.lightinit.hsdataplatform.handler;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.lightinit.hsdataplatform.common.WebUtilsPro;
import com.lightinit.hsdataplatform.entity.Admin;
import com.lightinit.hsdataplatform.model.ResultState;
import com.lightinit.hsdataplatform.model.ResultStateCode;
import com.lightinit.hsdataplatform.model.admin.ModuleActionListItemModel;
import com.lightinit.hsdataplatform.service.IAdminService;
import com.lightinit.hsdataplatform.service.IRoleService;
import com.lightinit.hsdataplatform.service.IShiroPermissionsService;
import com.lightinit.hsdataplatform.service.admin.IModuleMgrService;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;

/**
 * Created by Mr.Yao on 2016/1/25.
 */
public class AuthInterceptor extends HandlerInterceptorAdapter {

    private static final Logger logger = LoggerFactory.getLogger(AuthInterceptor.class);

    @Autowired
    private IRoleService roleService;
    @Autowired
    private IAdminService adminService;
    @Autowired
    private IShiroPermissionsService shiroPermissionsService;
    @Autowired
    private IModuleMgrService moduleMgrService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if(!(handler instanceof HandlerMethod)) {
            return true;
        }
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Object clazz = handlerMethod.getBean();
        List<ModuleActionListItemModel> moduleActionList = moduleMgrService.getModuleActionList();

        // 获取模块编码
        RequestMapping controllerRequestMapping = clazz.getClass().getDeclaredAnnotation(RequestMapping.class);
        final List<String> moduleMappingUrls = new ArrayList<>();
        if (controllerRequestMapping != null && controllerRequestMapping.value() != null){
            moduleMappingUrls.addAll(Arrays.asList(controllerRequestMapping.value()));
        }
        String moduleCode = "";
        if (moduleMappingUrls.size() > 0){
            Optional<ModuleActionListItemModel> optionalModuleAction = moduleActionList.stream().filter((q) -> {
                for (String mappingUrl : moduleMappingUrls) {
                    if (StringUtils.isEmpty(q.getMenuaction())){
                        continue;
                    }
                    String[] dbUrls = q.getMenuaction().split("\\+");
                    if (Arrays.asList(dbUrls).contains(mappingUrl)){
                        return true;
                    }
                }
                return false;
            }).findFirst();
            if (optionalModuleAction.isPresent()){
                moduleCode = optionalModuleAction.get().getMenucode();
            }
        }

        // 获取功能编码
        RequestMapping actionRequestMapping = handlerMethod.getMethod().getDeclaredAnnotation(RequestMapping.class);
        final List<String> actionMappingUrls = new ArrayList<>();
        if (actionRequestMapping != null && actionRequestMapping.value() != null){
            actionMappingUrls.addAll(Arrays.asList(actionRequestMapping.value()));
        }
        String actionCode = "";
        if (actionMappingUrls.size() > 0){
            Optional<ModuleActionListItemModel> optionalModuleAction = moduleActionList.stream().filter((q) -> {
                for (String mappingUrl : actionMappingUrls) {
                    if (StringUtils.isEmpty(q.getActionUrl())){
                        continue;
                    }
                    String[] dbUrls = q.getActionUrl().split("\\+");
                    if (Arrays.asList(dbUrls).contains(mappingUrl)){
                        return true;
                    }
                }
                return false;
            }).findFirst();
            if (optionalModuleAction.isPresent()){
                actionCode = optionalModuleAction.get().getActionCode();
            }
        }

        // 组合权限
        String permission = moduleCode;
        if (StringUtils.isNotEmpty(permission)){
            if (StringUtils.isNotEmpty(actionCode)){
                permission += ":" + actionCode;
            }
        }else {
            permission = actionCode;
        }

        // 判断权限
        String relativeUrl = request.getRequestURI();
        Subject subject = SecurityUtils.getSubject();
        boolean isPermitted = subject.isPermitted(StringUtils.isEmpty(permission) ? "*:*" : permission);
        if (!isPermitted){
            logger.debug("无权访问");
            if (WebUtilsPro.isAjaxRequest(request)){
                ResultState resultState = new ResultState();
                resultState.setStateCode(ResultStateCode.NO_PERMISSION);
                resultState.setMsg("无权访问");
                WebUtilsPro.writeJson(response, resultState);
            }else {
                response.sendRedirect("/403.html");
            }
        }
        return isPermitted;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        if (null == modelAndView)
            return;
        Subject user = SecurityUtils.getSubject();
        if (null == user)
            return;
        Object objectUserName = user.getPrincipal();
        String UserShowName="游客";
        if (null != objectUserName) {
            String currentUsername = (String) user.getPrincipal();
            if(StringUtils.isEmpty(currentUsername)){
                return;
            }else {
                Admin mUser = adminService.SelectOne(currentUsername);
                if(mUser!=null){
                    UserShowName=mUser.getShowname();
                }
            }
        }
        modelAndView.addObject("showname", UserShowName);
    }
}
