package cn.ey.biz.module.system.service.category.dynamic.handler;

import cn.ey.biz.common.pojo.PageParam;
import cn.ey.biz.common.pojo.R;
import cn.ey.biz.common.util.json.JsonUtils;
import cn.ey.biz.module.system.api.category.dto.CategoryDynamicReq;
import cn.ey.biz.module.system.enums.ErrorCodeConstants;
import cn.ey.biz.module.system.enums.category.CategoryCodeEnum;
import cn.ey.biz.module.system.enums.category.CategoryFunctionEnum;
import cn.ey.biz.module.system.framework.dynamic_api.core.handler.RequestHandler;
import cn.ey.biz.module.system.service.category.dynamic.provider.CategoryRequestProvider;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestParam;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
import java.util.Map;

import static cn.ey.biz.common.exception.util.ServiceExceptionUtil.exception;

/**
 * 字典接口请求处理器
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class CategoryRequestHandler implements RequestHandler {
    private final CategoryRequestProvider categoryRequestProvider;

    public static final String CATEGORY_CODE = "categoryCode";
    public static final String FUNCTION_TYPE = "functionType";
    public static final String PAGE_NO = "pageNo";
    public static final String PAGE_SIZE = "pageSize";
    public static final String STATUS = "status";

    @Override
    public R invoke(HttpServletRequest request, HttpServletResponse response,
                    @PathVariable(required = false) Map<String, Object> pathVariables, @RequestHeader(required = false) Map<String, Object> defaultHeaders,
                    @RequestParam(required = false) Map<String, Object> parameters, @RequestBody(required = false) Map<String, Object> requestBody) {
        if (hasRequestParamsErrors(parameters)) {
            throw exception(ErrorCodeConstants.CATEGORY_DATA_REQUEST_PARAMETER_ERROR, JsonUtils.toJsonString(parameters));
        }
        String categoryCode = (String) parameters.get(CATEGORY_CODE);
        String functionType = (String) parameters.get(FUNCTION_TYPE);
        Integer pageNo = (Integer) parameters.get(PAGE_NO);
        Integer pageSize = (Integer) parameters.get(PAGE_SIZE);
        try {
            CategoryDynamicReq req = new CategoryDynamicReq().setCategoryCode(categoryCode).setFunctionType(functionType)
                    .setPathVariables(pathVariables)
                    .setDefaultHeaders(defaultHeaders)
                    .setParameters(parameters)
                    .setRequestBody(requestBody)
                    .setPageParam(pageNo != null && pageSize != null ? new PageParam().setPageNo(pageNo).setPageSize(pageSize) : null);
            if (CategoryFunctionEnum.DEFAULT.getCode().equals(functionType)) {
                // default
                return R.success(categoryRequestProvider.fixedDictPro(req));
            } else if (CategoryFunctionEnum.DEFAULT_PAGEFUL.getCode().equals(functionType)) {
                // pageful
                return R.success(categoryRequestProvider.fixedDictProPageable(req));
            } else if (CategoryFunctionEnum.DEFAULT_NON_CACHE.getCode().equals(functionType))  {
                // non cache
                return R.success(categoryRequestProvider.fixedDictProNonCache(req));
            } else {
                // custom
                return R.success(categoryRequestProvider.strategyDictPro(request, response, req));
            }
        } catch (NoSuchMethodException e1) {
            throw exception(ErrorCodeConstants.CATEGORY_DATA_REQUEST_PARAMETER_ERROR, functionType);
        } catch (InvocationTargetException e2) {
            throw exception(ErrorCodeConstants.CATEGORY_DATA_REQUEST_ERROR, e2.getCause().getMessage());
        } catch (Exception e) {
            log.error("CategoryRequestHandler->invoke error:{}", e.getMessage(), e);
            throw exception(ErrorCodeConstants.CATEGORY_DATA_REQUEST_ERROR);
        }
    }

    public R invoke(Map<String, Object> parameters, Map<String, Object> requestBody) {
        return this.invoke(null, null, null, null, parameters, requestBody);
    }

    private boolean hasRequestParamsErrors(Map<String, Object> parameters) {
        List<String> categoryCodeList = categoryRequestProvider.canJoinCategoryCodeList();
        String categoryCode = (String) parameters.get(CATEGORY_CODE);
        String functionType = (String) parameters.get(FUNCTION_TYPE);
        boolean errorCategoryCode = parameters.get(CATEGORY_CODE) == null
                || (parameters.get(CATEGORY_CODE) != null && !categoryCodeList.contains(categoryCode));
        boolean errorFunctionCode = parameters.get(FUNCTION_TYPE) == null;
        boolean errorCustomFunctionCode =
                !CategoryFunctionEnum.DEFAULT.getCode().equals(functionType)
                        && !CategoryFunctionEnum.DEFAULT_PAGEFUL.getCode().equals(functionType)
                        && CategoryCodeEnum.getByCode(categoryCode) != null
                        && !CategoryCodeEnum.getByCode(categoryCode).categoryFunctionEnums().contains(functionType);

        return errorCategoryCode || errorFunctionCode || errorCustomFunctionCode;
    }
}
