package com.jkcredit.invoice.credit;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.jkcredit.invoice.common.ApiResult;
import com.jkcredit.invoice.common.DataResult;
import com.jkcredit.invoice.common.RequestApi;
import com.jkcredit.invoice.common.ResponseCode;
import com.jkcredit.invoice.model.entity.customer.Customer;
import com.jkcredit.invoice.service.customer.CustomerService;
import com.jkcredit.invoice.util.CorsFilterCheckUtil;
import com.jkcredit.invoice.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.math.BigDecimal;
import java.net.URLDecoder;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;

import static com.jkcredit.invoice.common.CommonConst.CONTEXT_PATH;
import static com.jkcredit.invoice.common.CommonConst.PATH;
import static com.jkcredit.invoice.common.CommonConst.STATIC_PATH;
import static com.jkcredit.invoice.common.CommonConst.USER_PATH;

/**
 * @Description: 跨域请求拦截器
 * @Author: mashengyi
 * @Date: 2021/9/12
 */
@Slf4j
public class SimpleCoreFilter implements Filter {


    private static final String PASS_API = "api=credit.sec.data";
    private static final String PASS_GATEWAY = "/gateway";
    private static final String PASS_REST = "/api/rest";
    /**
     * 全局定义ApiConstant
     */
    private final static Map<String, String> API_MAPS = new HashMap<String, String>() {
        {


            //无车、自有车 公共下游客户调用接口
            put("COMPANY_ADD_V1", "1");//自有车 无车、企业注册
            put("COMPANY_QUERY_V1", "1");//自有车 无车、企业查询
            put("PROTOCOL_ADD_V1", "1");//自有车 无车、协议上传
            put("PROTOCOL_STATUS_V1", "1");//自有车 无车、协议上传状态查询

            //无车下游客户调用接口
            put("VEHICLE_REGISTER", "1");//车辆备案
            put("VEHICLE_REGISTER_QUERY", "1");//车辆备案查询
            put("WAY_BILL_START", "1");// 实时运单开始指令
            put("WAY_BILL_END", "1");//实时运单结束指令
            put("WAY_BILL_HISTORY_START", "1");//历史运单开始指令
            put("WAY_BILL_HISTORY_END", "1");// 历史运单结束指令
            put("WAY_BILL_NUM_FIND_INVOICE", "1");// 运单号查询发票数据
            put("FIND_NO_SEARCH_NUM", "1");//获取未查询过发票的运单编号
            put("BALANCE_QUERY", "1");//账号余额查询
            put("RED_INK_INVOICE_QUERY", "1");//红冲发票查询
            put("WAY_BILL_NUM_FIND_OWNER_INVOICE", "1");// 运单号查询发票数据 透传上游，自己使用，不对外
            put("COMPANY_COMPANYDETAILADD", "1");// 上传企业开票经办人和营业执照信息
            put("COMPANY_COMPANYOPERATOREDIT", "1");// 变更企业开票经办人
            put("COMPANY_COMPANYOPERATOREDITCONFIRM", "1");// 确认变更企业开票经办人
            put("COMPANY_UPLOADOPERATOREVIDENCE", "1");// 上传企业开票经办人证明附件
            put("WAYBILL_OPERATORSENDCODE", "1");// 运单开票前发送验证码
            put("WAYBILL_OPERATORVALIDCODE", "1");// 运单开票前短信确认

            //自有车下游客户调用接口
            put("CARD_BIND_QUERY_LIST_V1", "1"); //用户卡列表查询
            put("CARD_QUERY_CARD_V1", "1");//卡信息查询
            put("CARD_BINDING_V1", "1");//下发短信验证码
            put("CARD_VALID_CODE_V1", "1");//自有车卡绑定接口、自有车输入参数接口
            put("CARD_TRADE_V1", "1");//交易查询
            put("B2B_INVOICE_APPLY_V1", "1");//申请开票
            put("B2B_INVOICE_QUERY_V1", "1");//已开发票查询
            put("B2B_INVOICE_APPL_QUERY_V1", "1");//按申请查询
            put("B2B_INVOICE_PACKAGE_V1", "1");//发票下载
            put("CARD_UNBIND_V1", "1");//卡解绑
            put("B2B_INVOICE_APPL_QUERY_V1", "1");//按照申请ID查询发票
            put("B2B_CHANGE_CARD_V1", "1");//用户卡换绑
            put("B2B_CHANGE_CARD_QUERY_V1", "1");//用户卡换绑查询
            put("B2B_QUERY_TRADE_APPLY_V1", "1");//按交易查申请

        }
    };
    /**
     * 这些映射无需进行api/appSecret等参数校验，故过滤
     */
    private final static String[] NO_TOKEN_API_PATHS = {

            /**
             * 前台映射
            */
            "/**/favicon.ico",
            "/favicon.ico",
            "/swagger-ui.html",
            "/webjars/**",
            "/webjars/springfox-swagger-ui/springfox.css",
            "/webjars/springfox-swagger-ui/springfox.js",
            "/webjars/springfox-swagger-ui/swagger-ui-bundle.js",
            "/webjars/springfox-swagger-ui/swagger-ui.css",
            "/webjars/springfox-swagger-ui/swagger-ui-standalone-preset.js",
            "/swagger-resources/configuration/ui",
            "/swagger-resources/configuration/security",
            "/swagger-resources",
            "/v2/api-docs",

            /**
             * 客户管理
            */
            "/customer/findCustomer",
            "/customer/findCustomerRecharge",
            "/customer/findCustomerRechargeMoney",
            "/customer/findCustomerRecList",
            "/customer/findCustomerRecListExport",
            "/customer/addCustomer",
            "/customer/updateCustomer",
            "/customer/addCustomer",
            "/customer/customeRecStop",
            "/customer/customeRecStart",
            "/customer/customerRecAdd",
            "/customer/customRecharge",
            "/customer/customeRec",
            "/customer/contractAdd",
            "/customer/promiseAdd",
            "/customer/contractDownload",
            "/customer/generateWord",
            "/customer/findCustomerRecTimeList",
            "/customer/findCustomerMoney",
            "/customer/customeRecQueryListByPage",
            "/customer/customerChangeList",
            "/customer/customerChangeInfo",
            "/customer/customeRecQueryUpper",
            "/customer/contractStatusFail",
            "/customer/contractStatusProcess",
            "/customer/contractStatusSuccess",
            "/customer/customeRecQueryList",
            "/customer/customerRecEditMail",

            //无车企业开票人管理
            "/customerCompany/detailAdd",
            "/customerCompany/operatorEvidenceAdd",
            "/customerCompany/page",
            "/customerCompany/noCarCompanyMangerQuery",
            "/customerCompany/updateNoCarCompanyManger",
            "/customerCompany/updateNoCarCompanyMangerConfirm",
            "/customerCompany/sendCode",
            "/customerCompany/confirmCode",
            //登陆管理
            "/auth/login/loginOut",

            //无车管理
            "/noCar/findCarRec",
            "/noCar/findBillWay",
            "/noCar/findBillWayCust",
            "/noCar/findImportBillWay",
            "/noCar/findBatchFileList",
            "/noCar/updateStatus",
            "/noCar/updateStatusByCompany",
            "/noCar/findBatchList",
            "/noCar/findNocarInvoicesStatic",
            "/noCar/findNocarInvoicesHis",
            "/noCar/findBillWayHis",
            "/noCar/batchImportNocarBillWayHis",
            "/noCar/batchImprotBillWayFile",
            "/noCar/batchImprotBillWay",
            "/noCar/batchImprotHistoryBillWay",
            "/noCar/batchImprotEndBillWay",
            "/noCar/findBillWayException",
            "/noCar/findNocarInvoices",
            "/noCar/findNocarInvoicesStatic",
            "/noCar/findNocarCalculateInfoStatis",
            "/noCar/findNocarCalculateInfo",
            "/noCar/templateDownload",
            "/noCar/downloadWayBillFile",
            "/noCar/batchImportNocarInvoices",
            "/noCar/batchImportNocarBillWay",

            //自由车管理
            "/selfCar/selfCarUnBind",
            "/selfCar/findTradesUpper",
            "/selfCar/findTrades",
            "/selfCar/findSelfCarInvoices",
            "/selfCar/findSelfcarCalculateInfo",
            "/selfCar/findSelfcarCalculateInfoSta",
            "/selfCar/getTradeList",
            "/selfCar/applTradeList",
            "/selfCar/findSelfcarInvoiceByTime",
            "/selfCar/batchImportSelfcarInvoices",
            "/selfCar/batchImportSelfcarTrades",
            "/selfCar/updateTrades",

            //参数管理
            "/param",
            "/param/page",
            "/param/updateParam",


            "/lowerService/customeRec",
            "/lowerService/customeRecQueryList",
            "/lowerService/customeRecQueryUpper",
            "/lowerService/customeRecQuery",

            "/noCarService/noCarBillStart",
            "/noCarService/noCarBillEnd",
            "/noCarService/noCarHisWaybillStart",
            "/noCarService/noCarHisWaybillEnd",
            "/noCarService/noCarVoiceQuery",
            "/noCarService/hCVoiceQuery",
            "/noCarService/hCVoiceUpdate",
            "/noCarService/monthAccQuery",
            "/noCarService/monthAccQueryAll",
            "/noCarService/monthAccUpdate",
            "/noCarService/customerCarRec",
            "/noCarService/customeRecUpperQuery",
            "/noCarService/customerCarRecQuery",
            "/noCarService/migrateData",

            "/selfCarService/getTradeList",
            "/selfCarService/applInvoice",
            "/selfCarService/getSelfCarInvoicesByTime",
            "/selfCarService/getSelfCarInvoicePackage",
            "/selfCarService/getSelfCarInvoicesByAppl",
            "/selfCarService/customerETCQuery",
            "/selfCarService/queryEtcInfo",
            "/selfCarService/customerETCRec",
            "/selfCarService/customerETCRecValid",
            "/selfCarService/customerCarUnRec",
            "/selfCarService/getApplyQueryByTradeIds",

            "/auth/login",
            "/role/list",
            "/user",
            "/user/updateUser",
            "/user/page",
            "/user/restPassword",
            "/user/lock",
            "/selfCar/recoverApplyId"
    };
    @Autowired
    CustomerService customerService;
    @Autowired
    InterfaceCheckServer interfaceCheckServer;

    public static String getsrt(String startkeystr, String endstr, String str) {
        int customerindex = str.indexOf(startkeystr);
        String temp = str.substring(customerindex + startkeystr.length());
        int endindex = temp.indexOf(endstr);
        String sss = temp.substring(0, endindex);
        return sss;
    }

    public static String getsrt1(String startkeystr, String str) {
        int customerindex = str.indexOf(startkeystr);
        String temp = str.substring(customerindex + startkeystr.length());
        return temp;
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;
        HttpServletResponse httpResponse = (HttpServletResponse) servletResponse;
        httpResponse.addHeader("Access-Control-Allow-Methods", "GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS,TRACE");
        String methodOptions = "OPTIONS";
        if (httpRequest.getMethod().equals(methodOptions)) {
            httpResponse.setStatus(HttpServletResponse.SC_ACCEPTED);
            return;
        }
        /**
         * 这些映射无需进行api/appSecret等参数校验，故过滤
         */
        boolean flag = (!Arrays.asList(NO_TOKEN_API_PATHS).contains(httpRequest.getRequestURI()));
        if (httpRequest.getRequestURI().contains(USER_PATH) || PATH.equals(httpRequest.getRequestURI()) || httpRequest.getRequestURI().contains(STATIC_PATH) || httpRequest.getRequestURI().contains(CONTEXT_PATH)) {
            flag = false;
        }
        if (flag) {

            // 创建客户唯一标识ID，以当前时间作为前缀，uuid为后缀
            String requestid = new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date()) + ","
                    + UUID.randomUUID().toString();

            long startTime = System.currentTimeMillis();
            String flagUuid = UUID.randomUUID().toString();
            RequestApi requestApi = new RequestApi();
            ResponseCode responseCode = checkToken(httpRequest, httpResponse, startTime, flagUuid, requestApi);
            if (!Objects.equals(responseCode, ResponseCode.SUCCESS)) {
                log.error("FILE - SimpleCORSFilterError = {}", responseCode + " ,requestURI = {" + httpRequest.getRequestURI() + "}");
                httpResponse.setContentType("application/json; charset=utf-8");
                httpResponse.setCharacterEncoding("utf-8");
                PrintWriter writer = httpResponse.getWriter();
                writer.write(new ObjectMapper().writeValueAsString(ApiResult.failure(responseCode, requestid)));
                log.error("[FILE - SimpleCORSFilter-] return result=" + responseCode.toString() + " , param is api=" + requestApi.getApi() + " , data=" + requestApi.getData() + " , appKey=" + requestApi.getAppKey() + " , appSecret=" + requestApi.getAppSecret() + " ,timeCost=" + (System.currentTimeMillis() - startTime) + "ms" + " , flag=" + flagUuid);
                return;
            } else {
                log.info("SUCCESS - SimpleCORSFilterWarn = {}", responseCode + " ,requestURI = {" + httpRequest.getRequestURI() + "}");


                DataResult dataResult = interfaceCheckServer.doJumpHandler(requestApi.getAppKey(), requestApi.getApi(), requestApi.getData(), requestid);
                if (null == dataResult) {
                    dataResult = new DataResult();
                    dataResult.setData(3);
                    dataResult.setCode(200);
                    dataResult.setRequestid(requestid);
                    dataResult.setMsg("无法认证");
                }
                httpResponse.setContentType("application/json; charset=utf-8");
                httpResponse.setCharacterEncoding("utf-8");
                PrintWriter writer = httpResponse.getWriter();
                writer.write(new ObjectMapper().writeValueAsString(ApiResult.failure(dataResult)));
                log.info("[SUCCESS - SimpleCORSFilter-] return result=" + dataResult.toString() + " , param is api=" + requestApi.getApi() + " , data=" + StringUtil.removeJSonField(requestApi.getData(),"base64Str") + " , appKey=" + requestApi.getAppKey() + " , appSecret=" + requestApi.getAppSecret() + " ,timeCost=" + (System.currentTimeMillis() - startTime) + "ms" + " , flag=" + flagUuid);
                return;
            }
        }

        filterChain.doFilter(httpRequest, servletResponse);
    }

    @Override
    public void destroy() {

    }

    private String getApi(String request) {
        return CorsFilterCheckUtil.getApi(request);
    }

    private String getAppKey(String request) {
        return CorsFilterCheckUtil.getAppKey(request);
    }

    private String getAppSecret(String request) {
        return CorsFilterCheckUtil.getAppSecret(request);
    }

    private String getData(String request) {
        return CorsFilterCheckUtil.getData(request);
    }

    /**
     * 用户 Token 校验
     *
     * @param request
     * @param response
     * @return
     */
    private ResponseCode checkToken(HttpServletRequest request, HttpServletResponse response, long startTime, String flag, RequestApi requestApi) {
        try {


            if (null != request && null != request.getQueryString() && !PASS_API.equals(request.getQueryString())) {
                return ResponseCode.UNKNOWN_ERROR;
            }

            if (null != request && null != request.getQueryString() && !PASS_GATEWAY.equals(request.getRequestURI())) {
                return ResponseCode.UNKNOWN_ERROR;
            }


            if (null != request && null == request.getQueryString() && !PASS_REST.equals(request.getRequestURI())) {
                return ResponseCode.UNKNOWN_ERROR;
            }

            if (null == request) {
                return ResponseCode.UNKNOWN_ERROR;
            }

            if (null != request && null == request.getQueryString() && null == request.getRequestURI()) {
                return ResponseCode.UNKNOWN_ERROR;
            }

            String jsonObject1 = getOpenApiRequestData(request);
            String api = getApi(jsonObject1);
            String appKey = getAppKey(jsonObject1);
            String appSecret = getAppSecret(jsonObject1);
            String data = getData(jsonObject1);
            requestApi.setApi(api);
            requestApi.setData(data);
            requestApi.setAppSecret(appSecret);
            requestApi.setAppKey(appKey);
            log.info("[-SimpleCORSFilter-] query param api=" + api + " , data=" + StringUtil.removeJSonField(data,"base64Str") + " , appKey=" + appKey + " , appSecret=" + appSecret + " , flag=" + flag);
            if (StringUtils.isEmpty(api) || StringUtils.isEmpty(data) || StringUtils.isEmpty(appKey) || StringUtils.isEmpty(appSecret)) {
                return ResponseCode.UNKNOWN_ERROR;
            }


            Customer customer = new Customer();
            customer.setCustomerName(appKey);
            customer.setAppSecret(appSecret);
            Customer customer1 = customerService.getCustomerByAppKeyAndAppSecret(customer);
            if (null == customer1 || customer1.getAccstatus() != 0) {
                return ResponseCode.ACCOUNT_NOT_EXIST;
            }
            if (null != customer1 && !appSecret.equals(customer1.getAppSecret())) {
                return ResponseCode.SIGN_ERROR;
            }
            if (!API_MAPS.containsKey(api)) {
                return ResponseCode.CUSTOMER_QUERY_ERROR;
            }
            boolean flags = false;

            if (0 >= new BigDecimal(customer1.getAccountBalance()).compareTo(new BigDecimal(0.0))) {
                flags = true;
            }
            if (isaBoolean(api, customer1)) {
                flags = false;
            }
            if (flags) {
                return ResponseCode.BALANCE_QUERY_ERROR;
            }


        } catch (Exception e) {
            log.error("Token 校验失败,{}:{}", e.getClass().getName(), e.getMessage());
            return ResponseCode.MEDIA_TYPE_NOT_SUPPORT_ERROR;
        }
        return ResponseCode.SUCCESS;
    }

    private boolean isaBoolean(String api, Customer customer1) {
        return 0 == new BigDecimal(customer1.getAccountBalance()).compareTo(new BigDecimal(0.0))
                && ("WAY_BILL_NUM_FIND_INVOICE".equals(api) || "B2B_INVOICE_QUERY_V1".equals(api));
    }

    public String getOpenApiRequestData(HttpServletRequest request) {
        String str = "";
        try {

            request.setCharacterEncoding("UTF-8");

            int contentLength = request.getContentLength();

            if (contentLength < 0) {
                return null;
            }
            byte[] buffer = new byte[contentLength];
            for (int i = 0; i < contentLength; ) {

                int readlen = request.getInputStream().read(buffer, i, contentLength - i);
                if (readlen == -1) {
                    break;
                }
                i += readlen;
            }

            String charEncoding = request.getCharacterEncoding();
            if (charEncoding == null) {
                charEncoding = "UTF-8";
            }
            str = new String(buffer, charEncoding) + "&";
            str = URLDecoder.decode(str, "UTF-8");


            return str;

        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

}
