package cn.ibizlab.codegen.model;

import cn.ibizlab.codegen.utils.Inflector;
import cn.ibizlab.codegen.utils.StringAdvUtils;
import com.alibaba.fastjson.JSONObject;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.Accessors;
import net.ibizsys.model.dataentity.service.IPSDEMethodDTO;
import net.ibizsys.model.dataentity.service.IPSDEServiceAPIMethod;
import net.ibizsys.model.dataentity.service.IPSDEServiceAPIMethodInput;
import net.ibizsys.model.service.IPSSubSysServiceAPIDEMethod;
import net.ibizsys.model.service.IPSSubSysServiceAPIDTO;
import net.ibizsys.model.service.IPSSubSysServiceAPIMethodInput;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Getter
@Setter
@NoArgsConstructor
@Accessors(chain = true)
public class ClientMethodModel extends BaseModel {

    private static String[] ignoreMethodNames = new String[]{"GET", "CREATE", "UPDATE", "REMOVE"};
    private static String[] booleanMethodNames = new String[]{"CREATE", "UPDATE", "SAVE", "CREATEBATCH", "UPDATEBATCH", "REMOVEBATCH", "SAVEBATCH"};

    private static Map<String, String> lang = new HashMap<String, String>() {{
        put("GET", "获取");
        put("CREATE", "创建");
        put("UPDATE", "更新");
        put("SAVE", "保存");
        put("REMOVE", "删除");
        put("GETDRAFT", "草稿");
        put("CHECKKEY", "校验");
    }};

    private ClientModel client;

    private ClientEntityModel clientEntity;

    private List<ClientEntityRSModel> parentClientEntities;

    public String getTags() {
        return clientEntity.getApiName();
    }

    private String notes;

    private String clientName;

    public String getClientName() {
        if (lang.containsKey(clientName.toUpperCase()))
            return lang.get(clientName.toUpperCase()) + clientName;
        else if (clientName.toUpperCase().startsWith("FETCH"))
            return "查询" + clientName;
        return clientName;
    }

    public ClientMethodModel(ClientEntityModel clientEntityModel, List<ClientEntityRSModel> parentClientEntities, IPSSubSysServiceAPIDEMethod iPSSubSysServiceAPIDEMethod) {
        this.opt = iPSSubSysServiceAPIDEMethod;
        this.clientEntity = clientEntityModel;
        this.client = clientEntityModel.getClient();
        this.parentClientEntities = parentClientEntities;
        this.setCodeName(iPSSubSysServiceAPIDEMethod.getCodeName());
        this.setName(iPSSubSysServiceAPIDEMethod.getName());
        this.clientName = ObjectUtils.isEmpty(iPSSubSysServiceAPIDEMethod.getLogicName()) ? iPSSubSysServiceAPIDEMethod.getName() : iPSSubSysServiceAPIDEMethod.getLogicName();
        this.notes = clientEntityModel.getCodeName() + "-" + name;
    }

    public IPSSubSysServiceAPIDEMethod getPSSubSysServiceAPIDEMethod() {
        return (IPSSubSysServiceAPIDEMethod) opt;
    }

    public String getMethodName() {
        String strName = super.getName();
        if (!CollectionUtils.isEmpty(parentClientEntities)) {
            strName += "By";
            for (ClientEntityRSModel parent : parentClientEntities) {
                strName += StringAdvUtils.pascalcase(parent.getParentIdFieldCodeName());
            }
        }
        return strName;
    }

    private String requestPath;

    public String getRequestPath() {
        if (requestPath == null) {
            String path = "";
            if (!CollectionUtils.isEmpty(parentClientEntities)) {
                for (ClientEntityRSModel apiRs : parentClientEntities) {
                    String strMajorEntityPlurlize = Inflector.getInstance().pluralize(StringAdvUtils.camelcase(apiRs.getMajorEntityCodeName()).toLowerCase());
                    path = String.format("/%s/{%s}", strMajorEntityPlurlize, StringAdvUtils.camelcase(apiRs.getParentIdFieldCodeName())) + path;
                }
            }

            //主键
            String strPlurlize = Inflector.getInstance().pluralize(StringAdvUtils.camelcase(clientEntity.getCodeName()).toLowerCase());
            if (getPSSubSysServiceAPIDEMethod().isNeedResourceKey() && (!"save".equalsIgnoreCase(name))) {
                path = path + String.format("/%s/{%s}", strPlurlize, StringAdvUtils.camelcase(clientEntity.getEntity().getKeyField().getCodeName()));
            } else {
                path = path + String.format("/%s", strPlurlize);
            }

            //方法名
            if (!ArrayUtils.contains(ignoreMethodNames, this.getName().toUpperCase())) {
                path = path + String.format("/%s", this.getCodeName().toLowerCase());
            }
            requestPath = path;
        }
        return requestPath;
    }

    public String getRequestPath2() {
        if (!ObjectUtils.isEmpty(this.getRequestPath()))
            return requestPath.substring(1);
        return "";
    }

    private List pathVariables;

    public List getPathVariables() {
        if (pathVariables == null) {
            pathVariables = new ArrayList();
            if (!CollectionUtils.isEmpty(parentClientEntities)) {
                for (ClientEntityRSModel apiRs : parentClientEntities) {
                    String strMajorEntityPlurlize = Inflector.getInstance().pluralize(StringAdvUtils.camelcase(apiRs.getMajorEntityCodeName()).toLowerCase());
                    JSONObject pathVariable = new JSONObject();
                    pathVariable.put("name", apiRs.getParentIdFieldCodeName());
                    pathVariable.put("type", PropType.findType(apiRs.getParentIdFieldType()));
                    pathVariables.add(0, pathVariable);
                }
            }
            if (getPSSubSysServiceAPIDEMethod().isNeedResourceKey() && (!"save".equalsIgnoreCase(name))) {
                JSONObject pathVariable = new JSONObject();
                pathVariable.put("name", clientEntity.getEntity().getKeyField().getCodeName());
                pathVariable.put("type", clientEntity.getEntity().getKeyField().getType());
                pathVariables.add(pathVariable);
            }
        }
        return pathVariables;
    }

    public String getBody() {
        if (!ObjectUtils.isEmpty(getInParam())) {
            return getInParam() + " " + getInParamName();
        }
        return null;
    }

    public IPSSubSysServiceAPIDTO getInputDTO() {
        return getPSSubSysServiceAPIDEMethod().getPSSubSysServiceAPIMethodInput().getPSSubSysServiceAPIDTO();
    }

    public IPSSubSysServiceAPIDTO getReturnDTO() {
        if (getPSSubSysServiceAPIDEMethod().getPSSubSysServiceAPIMethodReturn() == null || getPSSubSysServiceAPIDEMethod().getPSSubSysServiceAPIMethodReturn().getPSSubSysServiceAPIDTO() == null)
            return getInputDTO();
        return getPSSubSysServiceAPIDEMethod().getPSSubSysServiceAPIMethodReturn().getPSSubSysServiceAPIDTO();
    }

    private String inParam;
    private String inParam2;

    public String getInParam() {
        if (inParam == null) {
            String param = this.getClientEntity().getCodeName();
            IPSSubSysServiceAPIMethodInput iPSSubSysServiceAPIMethodInput = getPSSubSysServiceAPIDEMethod().getPSSubSysServiceAPIMethodInput();
            if (iPSSubSysServiceAPIMethodInput != null && iPSSubSysServiceAPIMethodInput.getPSSubSysServiceAPIDTO() != null)
                param = iPSSubSysServiceAPIMethodInput.getPSSubSysServiceAPIDTO().getName().replace("FilterDTO", "SearchContext");

            if ("KEYFIELD".equalsIgnoreCase(iPSSubSysServiceAPIMethodInput.getType()) || this.getName().equalsIgnoreCase("Remove")) {
                param = "";
                inParam2 = clientEntity.getEntity().getKeyField().getType().java;
                inParamName = StringAdvUtils.camelcase(clientEntity.getEntity().getKeyField().getCodeName());
                inParamName2 = StringAdvUtils.camelcase(clientEntity.getEntity().getKeyField().getCodeName());
            } else if ("KEYFIELDS".equalsIgnoreCase(iPSSubSysServiceAPIMethodInput.getType())) {
                param = "List<" + clientEntity.getEntity().getKeyField().getType().java + ">";
                inParam2 = param;
                inParamName = "list";
                inParamName2 = "list";
            } else if ("DTO".equalsIgnoreCase(iPSSubSysServiceAPIMethodInput.getType())) {
                inParam2 = clientEntity.getEntity().getCodeName();
                inParamName = "dto";
                inParamName2 = "domain";
            } else if ("DTOS".equalsIgnoreCase(iPSSubSysServiceAPIMethodInput.getType())) {
                param = "List<" + param + ">";
                inParam2 = "List<" + clientEntity.getEntity().getCodeName() + ">";
                inParamName = "dtos";
                inParamName2 = "domains";
            }
            inParam = param;

            inParam = inParam.replace("DTO","");
        }
        return inParam;
    }

    public boolean isNeedDto2Domain() {
        if ("FETCH".equalsIgnoreCase(getPSSubSysServiceAPIDEMethod().getMethodType()))
            return false;
        IPSSubSysServiceAPIMethodInput iPSSubSysServiceAPIMethodInput = getPSSubSysServiceAPIDEMethod().getPSSubSysServiceAPIMethodInput();
        if (iPSSubSysServiceAPIMethodInput == null)
            return false;

        return "DTOS".equalsIgnoreCase(iPSSubSysServiceAPIMethodInput.getType()) || "DTO".equalsIgnoreCase(iPSSubSysServiceAPIMethodInput.getType());
    }

    public boolean isListIn() {
        IPSSubSysServiceAPIMethodInput iPSSubSysServiceAPIMethodInput = getPSSubSysServiceAPIDEMethod().getPSSubSysServiceAPIMethodInput();
        if (iPSSubSysServiceAPIMethodInput == null)
            return false;
        return "KEYFIELDS".equalsIgnoreCase(iPSSubSysServiceAPIMethodInput.getType()) || "DTOS".equalsIgnoreCase(iPSSubSysServiceAPIMethodInput.getType());
    }

    private String inParamName;
    private String inParamName2;


    public boolean isListReturn() {
        if (getPSSubSysServiceAPIDEMethod().getPSSubSysServiceAPIMethodReturn() == null)
            return false;
        if ("DTOS".equalsIgnoreCase(getPSSubSysServiceAPIDEMethod().getPSSubSysServiceAPIMethodReturn().getType())
                || "OBJECTS".equalsIgnoreCase(getPSSubSysServiceAPIDEMethod().getPSSubSysServiceAPIMethodReturn().getType())
                || "SIMPLES".equalsIgnoreCase(getPSSubSysServiceAPIDEMethod().getPSSubSysServiceAPIMethodReturn().getType()))
            return true;
        return false;
    }

    public String typeReturn() {
        if (isListReturn()) {
            if ("SIMPLES".equalsIgnoreCase(getPSSubSysServiceAPIDEMethod().getPSSubSysServiceAPIMethodReturn().getType()))
                return PropType.findType(this.getPSSubSysServiceAPIDEMethod().getPSSubSysServiceAPIMethodReturn().getStdDataType()).java;
            else if ("DTOS".equalsIgnoreCase(getPSSubSysServiceAPIDEMethod().getPSSubSysServiceAPIMethodReturn().getType())
                    || "OBJECTS".equalsIgnoreCase(getPSSubSysServiceAPIDEMethod().getPSSubSysServiceAPIMethodReturn().getType()))
                return this.getPSSubSysServiceAPIDEMethod().getPSSubSysServiceAPIMethodReturn().getName();
        }
        return "";
    }

    public boolean isBooleanReturn() {
        return ArrayUtils.contains(booleanMethodNames, this.getName().toUpperCase());
    }

    private boolean needDomain2Dto = true;
    private String outParam;
    private String outParam2;

    public String getOutParam() {
        if (outParam == null) {
            String param = this.getClientEntity().getCodeName();

            if (getPSSubSysServiceAPIDEMethod().getPSSubSysServiceAPIMethodReturn() != null && getPSSubSysServiceAPIDEMethod().getPSSubSysServiceAPIMethodReturn().getPSSubSysServiceAPIDTO() != null)
                param = getPSSubSysServiceAPIDEMethod().getPSSubSysServiceAPIMethodReturn().getPSSubSysServiceAPIDTO().getName();

            if ("Remove".equalsIgnoreCase(getName())) {
                needDomain2Dto = false;
                param = "Boolean";
                outParam2 = "Boolean";
            } else if ("VOID".equalsIgnoreCase(getPSSubSysServiceAPIDEMethod().getPSSubSysServiceAPIMethodReturn().getType())) {
                needDomain2Dto = isNeedDto2Domain();
                param = getInParam();
                outParam2 = getInParam2();
            } else if ("SIMPLE".equalsIgnoreCase(getPSSubSysServiceAPIDEMethod().getPSSubSysServiceAPIMethodReturn().getType())) {
                needDomain2Dto = false;
                param = PropType.findType(this.getPSSubSysServiceAPIDEMethod().getPSSubSysServiceAPIMethodReturn().getStdDataType()).java;
                outParam2 = param;
            } else if ("SIMPLES".equalsIgnoreCase(getPSSubSysServiceAPIDEMethod().getPSSubSysServiceAPIMethodReturn().getType())) {
                needDomain2Dto = false;
                param = "List<" + PropType.findType(this.getPSSubSysServiceAPIDEMethod().getPSSubSysServiceAPIMethodReturn().getStdDataType()).java + ">";
                outParam2 = param;
            } else if ("DTO".equalsIgnoreCase(getPSSubSysServiceAPIDEMethod().getPSSubSysServiceAPIMethodReturn().getType())) {
                needDomain2Dto = false;
                outParam2 = clientEntity.getEntity().getCodeName();
            } else if ("DTOS".equalsIgnoreCase(getPSSubSysServiceAPIDEMethod().getPSSubSysServiceAPIMethodReturn().getType())
                    || "OBJECTS".equalsIgnoreCase(getPSSubSysServiceAPIDEMethod().getPSSubSysServiceAPIMethodReturn().getType())) {
                needDomain2Dto = false;
                param = "List<" + param + ">";
                outParam2 = "List<" + clientEntity.getEntity().getCodeName() + ">";
            }
            if ("FETCH".equalsIgnoreCase(getPSSubSysServiceAPIDEMethod().getMethodType())) {
                needDomain2Dto = false;
                outParam = "Page<" + param + ">";
            }
            else
                outParam = param;

            //
            outParam = outParam.replace("DTO","");
        }

        return outParam;
    }

}
