package com.diagbot.config.security;

import com.diagbot.exception.CommonException;
import com.diagbot.exception.ServiceErrorCode;
import com.diagbot.facade.TokenFacade;
import com.diagbot.util.HttpUtils;
import com.diagbot.util.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.authentication.AccountExpiredException;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.stereotype.Service;

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

/**
 * @Description: 自定义权限拦截
 * @author: gaodm
 * @time: 2018/8/23 13:46
 */
@Service
public class UrlAccessDecisionManager implements AccessDecisionManager {
    @Autowired
    private TokenFacade tokenFacade;

    @Override
    public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {
        HttpServletRequest request = ((FilterInvocation) object).getHttpRequest();
        String url, method;
        String tokenStr = HttpUtils.getHeaders(request).get("Authorization");
        if (!request.getMethod().equals("OPTIONS") && StringUtil.isEmpty(tokenStr)) {
            tokenStr = HttpUtils.getHeaders(request).get("authorization");
        }
        //用户是否被顶掉校验
        if (StringUtil.isNotEmpty(tokenStr) && !matchNotCheckUrl(request)) {
            tokenStr = tokenStr.replaceFirst("Bearer ", "");
            int res = tokenFacade.newVerifyToken(tokenStr, 1);
            if (-1 == res) {
                throw new CommonException(ServiceErrorCode.LONGIN_ERROE);
            } else if (-2 == res) {
                throw new CommonException(ServiceErrorCode.USER_POWER_UP);
            }
        }

        if (matchPermitAllUrl(request)) {
            return;
        }
        if ("anonymousUser".equals(authentication.getPrincipal())) {
            throw new AccessDeniedException("no right");
        } else {
            if (StringUtil.isNotEmpty(tokenStr)) {
                tokenStr = tokenStr.replaceFirst("Bearer ", "");
//                Boolean res = tokenFacade.verifyToken(tokenStr, 1);
                int res = tokenFacade.newVerifyToken(tokenStr, 1);
                if (-1 == res) {
                    throw new CommonException(ServiceErrorCode.LONGIN_ERROE);
                } else if (1 != res) {
                    throw new AccountExpiredException("token expire");
                }
            }
            for (GrantedAuthority ga : authentication.getAuthorities()) {
                String[] authority = ga.getAuthority().split(";");
                url = authority[0];
                method = authority[1];
                if (matchers(url, request)) {
                    if (method.equals(request.getMethod()) || "ALL".equals(method)) {
                        return;
                    }
                }
            }
        }
        throw new AccessDeniedException("no right");
    }


    @Override
    public boolean supports(ConfigAttribute attribute) {
        return true;
    }

    @Override
    public boolean supports(Class<?> clazz) {
        return true;
    }

    private Boolean matchPermitAllUrl(HttpServletRequest request) {
        if (matchers("/swagger/**", request)
                || matchers("/v2/**", request)
                || matchers("/swagger-ui.html/**", request)
                || matchers("/swagger-resources/**", request)
                || matchers("/webjars/**", request)
                || matchers("/druid/**", request)
                || matchers("/actuator/**", request)
                || matchers("/hystrix/**", request)
                || matchers("/sys/user/getJwt", request)
                || matchers("/sys/user/getCaptcha", request)
                || matchers("/sys/user/getHospitalMark", request)
                || matchers("/sys/user/getJwtNoPass", request)
                || matchers("/sys/user/refreshJwt", request)
                || matchers("/sys/dictionaryInfo/getDictionary", request)
                || matchers("/sys/user/checkToken", request)
                || matchers("/oauth/token", request)
                || matchers("/oauth/check_token", request)
                || matchers("/cache/clear", request)
                || matchers("/qc/behospitalInfo/execule", request)
                || matchers("/qc/behospitalInfo/analyze_rpc", request)
                || matchers("/qc/behospitalInfo/analyze_api", request)
                || matchers("/qc/behospitalInfo/analyze_run", request)
                || matchers("/qc/module/getById", request)
                || matchers("/qc/module/getModuleMap", request)
                || matchers("/qc/cases/getQcCases", request)
                || matchers("/qc/behospitalInfo/page", request)
                || matchers("/qc/casesEntryHospital/getQcCasesEntryAll", request)
                || matchers("/qc/casesEntryHospital/getQcCasesAll", request)
                || matchers("/qc/behospitalInfo/getByBehospitalCode", request)
                || matchers("/bas/dept/getList", request)
                || matchers("/bas/dept/getListUser", request)
                || matchers("/qc/behospitalInfo/page_dept", request)
                || matchers("/qc/behospitalInfo/page_person", request)
                || matchers("/qc/behospitalInfo/page_group", request)
                || matchers("/qc/casesEntryHospital/findQcCasesEntry", request)
                || matchers("/qc/behospitalInfo/exportExcel", request)
//                || matchers("/qc/dataimport/import", request)
//                || matchers("/qc/dataimport/test", request)
                || matchers("/qc/behospitalInfo/exportExcel", request)
                || matchers("/qc/behospitalInfo/exportQcresult", request)
                || matchers("/qc/behospitalInfo/exportQcresultByDept", request)
                || matchers("/qc/behospitalInfo/exportQcresultByGroup", request)
                || matchers("/qc/abnormal/getQcAnnormalMode", request)
                || matchers("/qc/dataimport/import", request)
                || matchers("/qc/dataimport/dataimportPrepare", request)
//                || matchers("/qc/dataimport/test", request)
                || matchers("/sys/user/pageset/getPageSet", request)
                || matchers("/sys/user/pageset/savePageSet", request)
                || matchers("/sys/user/pageset/getDefaultPageSet", request)
                || matchers("/consoleByDept/getDept", request)
                || matchers("/console/entryRejectPercent", request)
                || matchers("/console/qcResultLevelPercent", request)
                || matchers("/console/averageStatistics", request)
                || matchers("/console/entryByDept", request)
                || matchers("/console/entryCountGroupByCase", request)
                || matchers("/console/entryCountGroupByCasePage", request)
                || matchers("/console/entryCountGroupByEntry", request)
                || matchers("/console/entryCountGroupByEntryPage", request)
                || matchers("/console/entryCountGroupXYByEntryPage", request)
                || matchers("/console/entryGroupByEntryInnerPage", request)
                || matchers("/console/getAverageDayNum", request)
                || matchers("/console/getAverageDayNumPage", request)
                || matchers("/console/getAverageFee", request)
                || matchers("/console/getAverageFeePage", request)
                || matchers("/console/getAverageScore", request)
                || matchers("/console/getAverageScoreByDeptClass", request)
                || matchers("/console/getAverageScoreByDeptPage", request)
                || matchers("/console/getLevelResultDept", request)
                || matchers("/console/homePageLevelLimit", request)
                || matchers("/console/homePageLevelStatistics", request)
                || matchers("/console/homePageLevelStatisticsXY", request)
                || matchers("/console/export/homePageLevelXYExport", request)
                || matchers("/consoleByDept/homePageLevelStatisticsXYByDept", request)
                || matchers("/print/export/homePageLevelXYExportByDept", request)
                || matchers("/consoleByDept/entryCountGroupXYByEntryPageDept", request)
                || matchers("/print/export/entryCountGroupXYByExportDept", request)
                || matchers("/consoleByDept/qcResultShortXYPageByDept", request)
                || matchers("/print/export/qcResultShortXYPageExportDept", request)
                || matchers("/consoleByDept/badLevelXYPageByDept", request)
                || matchers("/print/export/badUnQualifiedLevelPageXYExportByDept", request)
                || matchers("/print/export/badQualifiedLevelPageXYExportByDept", request)
                || matchers("/console/leaveHosCount", request)
                || matchers("/console/levelPercentGroupByDeptPage", request)
                || matchers("/console/levelStatistics", request)
                || matchers("/console/levelStatisticsByDeptClass", request)
                || matchers("/console/mrCount", request)
                || matchers("/console/mrStatistics", request)
                || matchers("/console/medicalRecordIndicator", request)
                || matchers("/console/codingMonthly", request)
                || matchers("/console/qcResultShortPage", request)
                || matchers("/console/qcResultShortXYPage", request)
                || matchers("/console/resultStatistics", request)
                || matchers("/console/resultStatisticsByDeptPage", request)
                || matchers("/console/homePageMRCount", request)
                || matchers("/console/qcCheckStatistics", request)
                || matchers("/console/unModifyMRStatistics", request)
                || matchers("/console/unModifyMRPage", request)
                || matchers("/console/reHos31DaysPage", request)
                || matchers("/console/beHosCount", request)
                || matchers("/console/casesEntryStatisticsById", request)
                || matchers("/console/hmImproveMRPage", request)
                || matchers("/console/qcCheckMRPage", request)
                || matchers("/consoleByDept/entryCountGroupByCaseAndDept", request)
                || matchers("/consoleByDept/entryCountGroupByCaseAndDeptPage", request)
                || matchers("/consoleByDept/entryCountGroupByEntryAndDept", request)
                || matchers("/consoleByDept/entryCountGroupByEntryAndDeptPage", request)
                || matchers("/consoleByDept/entryGroupByEntryAndDeptInnerPage", request)
                || matchers("/consoleByDept/homePageLevelByDeptLimit", request)
                || matchers("/consoleByDept/homePageLevelStatisticsByDept", request)
                || matchers("/consoleByDept/leaveHosCountByDept", request)
                || matchers("/consoleByDept/levelStatisticsByDept", request)
                || matchers("/consoleByDept/mrCountByDept", request)
                || matchers("/consoleByDept/qcResultShortByDeptPage", request)
                || matchers("/consoleByDept/resultStatisticsByDeptAndDoctorPage", request)
                || matchers("/console/export/homePageLevelExport", request)
                || matchers("/console/export/entryGroupByEntryExport", request)
                || matchers("/console/export/levelExport", request)
                || matchers("/console/entryStatistics", request)
                || matchers("/console/export/levelExport_TZ", request)
                || matchers("/console/export/getAverageDayNumExport", request)
                || matchers("/console/export/getAverageFeeExport", request)
                || matchers("/console/export/levelPercentGroupByDeptExport", request)
                || matchers("/console/export/entryCountGroupByEntryExport", request)
                || matchers("/console/export/entryCountGroupXYByEntryExport", request)
                || matchers("/console/export/entryCountGroupByCaseExport", request)
                || matchers("/console/export/entryStatisticsExport", request)
                || matchers("/console/export/qcResultShortPageExport", request)
                || matchers("/console/export/qcResultShortXYPageExport", request)
                || matchers("/console/export/leaveHosMrPageExport", request)
                || matchers("/console/export/qcCheckStatisticsExport", request)
                || matchers("/console/export/unModifyMRPageExport", request)
                || matchers("/console/export/unModifyMRStatisticsExport", request)
                || matchers("/console/export/reHos31DaysPageExport", request)
                || matchers("/console/export/hmImproveMRPageExport", request)
                || matchers("/console/export/qcCheckMRPageExport", request)
                || matchers("/qc/data/sendDoctorInfos", request)
                || matchers("/qc/data/sendDeptInfos", request)
                || matchers("/qc/data/sendRecordTypes", request)
                || matchers("/qc/data/sendMrRecordIng", request)
                || matchers("/qc/data/sendMrContent", request)
                || matchers("/qc/data/sendMrRecord", request)
                || matchers("/qc/data/sendPatientInfo", request)
                || matchers("/qc/data/sendDoctorAdvice", request)
                || matchers("/qc/data/sendHomePageIng", request)
                || matchers("/qc/data/sendHomePage", request)
                || matchers("/qc/data/sendHomeDiagnose", request)
                || matchers("/qc/data/sendHomeOperation", request)
                || matchers("/qc/data/sendCrisis", request)
                || matchers("/qc/data/deleteFlag", request)
                || matchers("/qc/data/placeFile", request)
                || matchers("/qc/data/sendLisResults", request)
                || matchers("/qc/data/sendPacsResults", request)
                || matchers("/qc/data/getColumnZhAndCh", request)
                || matchers("/qc/data/analyseRec", request)
                || matchers("/qc/data/hisDataDeal", request)
                || matchers("/qc/data_str/sendAdmissionNote", request)
                || matchers("/qc/data_str/sendBloodResult", request)
                || matchers("/qc/data_str/sendBloodTransfusion", request)
                || matchers("/qc/data_str/sendConsultationApply", request)
                || matchers("/qc/data_str/sendConsultationNote", request)
                || matchers("/qc/data_str/sendConsultationRecord", request)
                || matchers("/qc/data_str/sendConsultationResult", request)
                || matchers("/qc/data_str/sendCrisisNote", request)
                || matchers("/qc/data_str/sendDeathDiscussion", request)
                || matchers("/qc/data_str/sendDeathNote", request)
                || matchers("/qc/data_str/sendDifficultCase", request)
                || matchers("/qc/data_str/sendFirstRecord", request)
                || matchers("/qc/data_str/sendIllCritically", request)
                || matchers("/qc/data_str/sendIllSeriousl", request)
                || matchers("/qc/data_str/sendLeaveHospital", request)
                || matchers("/qc/data_str/sendOperativeFirstRecord", request)
                || matchers("/qc/data_str/sendOperativeNote", request)
                || matchers("/qc/data_str/sendWardRecord", request)
                || matchers("/qc/data_str/sendTransferOutNote", request)
                || matchers("/qc/data_str/sendTransferInNote", request)
                || matchers("/qc/data_str/sendRescueNote", request)
                || matchers("/qc/data_str/sendPeriodConclusion", request)
                || matchers("/qc/data_str/sendPreoperativeDiscussion", request)
                || matchers("/qc/data_str/sendTalkInform", request)
                || matchers("/qc/data_str/sendInformedConsent", request)
                || matchers("/qc/data_str/sendContent", request)
                || matchers("/qc/doctoradvice/getPage", request)
                || matchers("/qc/medPacsInfo/getCheckPage", request)
                || matchers("/qc/medLisInfo/getExaminePage", request)
                || matchers("/qc/behospitalInfo/analyzeCds", request)
                || matchers("/qc/medLisInfo/getExamineSonPage", request)
                || matchers("/console/medicalCheckForm", request)
                || matchers("/console/medicalCheckTitle", request)
                || matchers("/console/export/medicalCheckExport", request)
                || matchers("/console/export/medicalCheckInnerExport", request)
                || matchers("/console/badLevelPage", request)
                || matchers("/console/badLevelXYPage", request)
                || matchers("/console/export/badUnQualifiedLevelPagePageExport", request)
                || matchers("/console/export/badQualifiedLevelPagePageExport", request)
                || matchers("/console/export/badUnQualifiedLevelPageXYExport", request)
                || matchers("/console/export/badQualifiedLevelPageXYExport", request)
                || matchers("/qc/medNurse/getMedNursePage", request)
                || matchers("/qc/medRecordOther/getMedRecordOtherPage", request)
                || matchers("/qc/medRecordOther/getMedRecordContentOther", request)
                || matchers("/qc/behospitalInfo/exportQcresultByPerson", request)
                || matchers("/consoleByDept/beHosCountByDept", request)
                || matchers("/consoleByDept/casesEntryStatisticsByDept", request)
                || matchers("/bas/doctor/getList", request)
                || matchers("/consoleByDept/homePageOrGoodLevelByDept", request)
                || matchers("/print/export/homePageLevelExportByDept", request)
                || matchers("/print/export/homeUnQualifiedPageOrLevelExportByDept", request)
                || matchers("/print/export/homeQualifiedPageOrLevelExportByDept", request)
                || matchers("/print/export/entryGroupExportByDeptPage", request)
                || matchers("/print/export/entryGroupExportByDeptCase", request)
                || matchers("/print/export/entryGroupExportByDeptEntry", request)
                || matchers("/print/export/qcResultShortExportByDeptPage", request)
                || matchers("/print/export/levelExportByDept", request)
                || matchers("/consoleByDept/entryStatisticsByDept", request)
                || matchers("/print/export/entryStatisticsExportByDept", request)
                || matchers("/consoleByDept/leaveHosMRPageByDept", request)
                || matchers("/print/export/leaveHosMrPageExportByDept", request)
                || matchers("/consoleByDept/qcCheckStatisticsByDept", request)
                || matchers("/print/export/qcCheckStaExportByDept", request)
                || matchers("/consoleByDept/qcCheckMRPageByDept", request)
                || matchers("/print/export/qcCheckMRPageExportByDept", request)
                || matchers("/consoleByDept/hmImproveMRPageByDept", request)
                || matchers("/print/export/improveMRExportByDept", request)
                || matchers("/consoleByDept/reHos31DaysPageByDept", request)
                || matchers("/print/export/reHos31DaysPageExportByDept", request)
                || matchers("/consoleByDept/unModifyMRSByDept", request)
                || matchers("/print/export/unModifyMRSExportByDept", request)
                || matchers("/consoleByDept/unModifyMRPageByDept", request)
                || matchers("/print/export/unModifyMRPageExportByDept", request)
                || matchers("/consoleByDept/medicalCheckFormKs", request)
                || matchers("/print/export/medicalCheckExportByDept", request)
                || matchers("/consoleByDept/medicalCheckTitleKs", request)
                || matchers("/console/qualityControl", request)
                || matchers("/console/export/qualityControlExport", request)
                || matchers("/consoleByDept/qualityControlByDept", request)
                || matchers("/print/export/qualityControlExportByDept", request)
                || matchers("/qc/behospitalInfo/getMedQualityCoList", request)
                || matchers("/console/saveMedicaIndicator", request)
                || matchers("/qc/medCheckInfo/createMedBeHospitalInfoType", request)
                || matchers("/qc/medCheckInfo/addMedCheckInfo", request)
                || matchers("/qc/dataEdit/getDataEdit", request)
                || matchers("/qc/dataEdit/saveDataEdit", request)
                || matchers("/qc/analysis/addMedClickInfo", request)
                || matchers("/qc/analysis/getQcClickDeptList", request)
                || matchers("/qc/analysis/getQcClick", request)
                || matchers("/qc/analysis/getQcClickByExport", request)
                || matchers("/qc/analysis/getQcClickInnerPage", request)
                || matchers("/qc/analysis/getQcClickInnerPageByExport", request)
                || matchers("/qc/analysis/getEntryDefectImprove", request)
                || matchers("/qc/analysis/getEntryDefectImproveByExport", request)
                || matchers("/qc/analysis/getEntryDefectImproveInner", request)
                || matchers("/qc/analysis/getDefectImproveInnerByExport", request)
                || matchers("/qc/analysisDept/getEntryDefectImproveDept", request)
                || matchers("/qc/analysisDept/getEntryDefectImproveByDeptExport", request)
                || matchers("/qc/analysisDept/getEntryDefectImproveInnerDept", request)
                || matchers("/qc/analysisDept/getDefectImproveInnerByDeptExport", request)
                || matchers("/qc/behospitalInfo/historyAnalyze", request)
                || matchers("/qc/behospitalInfo/operationLog", request)
                || matchers("/qc/behospitalInfo/decodeData", request)
                || matchers("/qc/behospitalInfo/encryptData", request)
                || matchers("/qc/appealExamineInfo/getComplaintRecord", request)
                || matchers("/qc/appealExamineInfo/getAppealReview", request)
                || matchers("/qc/appealExamineInfo/approved", request)
                || matchers("/qc/appealExamineInfo/rejected", request)
                || matchers("/qc/appealExamineInfo/getApprovedView", request)
                || matchers("/qc/appealExamineInfo/getAppealReviewDictionary", request)
                || matchers("/qc/appealExamineInfo/getAuditNumber", request)
                || matchers("/qc/appealExamineInfo/getAppealReviewExport", request)
                || matchers("/qc/appealExamineInfo/getComplaintRecordExport", request)
                || matchers("/qc/appealExamineInfo/getComplaintDetailMsg", request)
                || matchers("/qc/appealInfo/addAppealInfo", request)
                || matchers("/qc/appealInfo/addAppealInfoApi", request)
                || matchers("/qc/appealInfo/getReviewer", request)
                || matchers("/qc/appealInfo/getReviewerApi", request)
                || matchers("/qc/behospitalInfo/addCase", request)
                || matchers("/qc/behospitalInfo/delCase", request)
                || matchers("/qc/behospitalInfo/logicDelCase", request)
                || matchers("/qc/behospitalInfo/updCase", request)
                || matchers("/qc/appealInfo/getAppealOperationType", request)
                || matchers("/qc/appealInfo/cancelAppealInfo", request)
                || matchers("/qc/appealInfo/cancelAppealInfoApi", request)
                || matchers("/qc/appealInfo/getAppealInfo", request)
                || matchers("/qc/appealInfo/getAppealDept", request)
                || matchers("/qc/appealInfo/getAppealMode", request)
                || matchers("/qc/appealInfo/getUserRole", request)
                || matchers("/qc/mode/getModes", request)
                || matchers("/consoleByDoctor/**", request)
                || matchers("/qc/getDoctorDetail/**", request)
                || matchers("/qcView/data/*", request)
                || matchers("/medDefectFeedback/*", request)
                || matchers("/medNewsNotice/**", request)
                || matchers("/h5/statistics/**", request)
                || matchers("/logManage/**", request)
                || matchers("/qc/qcType/add", request)
                || matchers("/qc/qcType/update", request)
                || matchers("/qc/qcType/copy", request)
                || matchers("/str/FirstRecord/infos", request)
                || matchers("/str/WardRecord/infos", request)
                || matchers("/str/ConsultationApply/infos", request)
                || matchers("/str/ConsultationResult/infos", request)
                || matchers("/str/OperativeFirstRecord/infos", request)
                || matchers("/str/DeathDiscussion/infos", request)
                || matchers("/str/PreoperativeDiscussion/infos", request)
                || matchers("/str/OperativeNote/infos", request)
                || matchers("/str/IllCritically/infos", request)
                || matchers("/str/DeathNote/infos", request)
                || matchers("/str/LeaveHospital/infos", request)
                || matchers("/str/CrisisNote/infos", request)
                || matchers("/str/RescueNote/infos", request)
                || matchers("/str/TransferOutNote/infos", request)
                || matchers("/str/TransferInNote/infos", request)
                || matchers("/str/AdmissionNote/infos", request)
                || matchers("/str/DifficultCase/infos", request)
                || matchers("/str/BloodTransfusion/infos", request)
                || matchers("/str/PeriodConclusion/infos", request)
                || matchers("/str/IllSeriousl/infos", request)
                || matchers("/", request)) {
            return true;
        }
        return false;
    }

    private boolean matchers(String url, HttpServletRequest request) {
        AntPathRequestMatcher matcher = new AntPathRequestMatcher(url);
        if (matcher.matches(request)) {
            return true;
        }
        return false;
    }

    private boolean matchNotCheckUrl(HttpServletRequest request) {
        if (matchers("/swagger/**", request)
                || matchers("/v2/**", request)
                || matchers("/swagger-ui.html/**", request)
                || matchers("/swagger-resources/**", request)
                || matchers("/webjars/**", request)
                || matchers("/druid/**", request)
                || matchers("/actuator/**", request)
                || matchers("/hystrix/**", request)
                || matchers("/sys/user/getJwt", request)
                || matchers("/sys/user/logout", request)
                || matchers("/sys/user/getCaptcha", request)
                || matchers("/sys/user/getHospitalMark", request)
                || matchers("/sys/user/getJwtNoPass", request)
                || matchers("/sys/user/refreshJwt", request)
                || matchers("/sys/dictionaryInfo/getDictionary", request)
                || matchers("/sys/user/checkToken", request)
                || matchers("/oauth/token", request)
                || matchers("/oauth/check_token", request)
                || matchers("/cache/clear", request)) {
            return true;
        }
        return false;
    }
}
