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.IPSDataEntity;
import net.ibizsys.model.dataentity.service.*;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.util.*;

@Getter
@Setter
@NoArgsConstructor
@Accessors(chain = true)
public class ApiMethodModel 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 ApiModel api;

    private ApiEntityModel apiEntity;

    private List<ApiEntityRSModel> parentApiEntities;

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

    private String notes;

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

    public ApiMethodModel(ApiEntityModel apiEntityModel, List<ApiEntityRSModel> parentApiEntities, IPSDEServiceAPIMethod iPSDEServiceAPIMethod) {
        this.opt = iPSDEServiceAPIMethod;
        this.apiEntity = apiEntityModel;
        this.api = apiEntityModel.getApi();
        this.parentApiEntities = parentApiEntities;
        this.setCodeName(iPSDEServiceAPIMethod.getCodeName());
        this.setName(iPSDEServiceAPIMethod.getName());
        this.apiName=ObjectUtils.isEmpty(iPSDEServiceAPIMethod.getLogicName())?iPSDEServiceAPIMethod.getName():iPSDEServiceAPIMethod.getLogicName();
        this.notes=apiEntityModel.getCodeName()+"-"+name;
    }

    public IPSDEServiceAPIMethod getPSDEServiceAPIMethod() {
        return (IPSDEServiceAPIMethod) opt;
    }

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

    private String requestPath;

    public String getRequestPath() {
        if(requestPath==null)
        {
            String path = "";
            if (!CollectionUtils.isEmpty(parentApiEntities)) {
                for (ApiEntityRSModel apiRs : parentApiEntities) {
                    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(apiEntity.getCodeName()).toLowerCase());
            if (getPSDEServiceAPIMethod().isNeedResourceKey()&&(!"save".equalsIgnoreCase(name))) {
                path = path + String.format("/%s/{%s}", strPlurlize, StringAdvUtils.camelcase(apiEntity.getEntity().getKeyField().getCodeName()));
            } else {
                path = path + String.format("/%s", strPlurlize);
            }

            //方法名
            if (!ArrayUtils.contains(ignoreMethodNames, this.getName().toUpperCase())) {
                path = path + String.format("/%s", this.getName().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(parentApiEntities)) {
                for (ApiEntityRSModel apiRs : parentApiEntities) {
                    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 (getPSDEServiceAPIMethod().isNeedResourceKey()&&(!"save".equalsIgnoreCase(name))) {
                JSONObject pathVariable = new JSONObject();
                pathVariable.put("name", apiEntity.getEntity().getKeyField().getCodeName());
                pathVariable.put("type", apiEntity.getEntity().getKeyField().getType());
                pathVariables.add(pathVariable);
            }
        }
        return pathVariables;
    }

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

    public IPSDEMethodDTO getInputDTO() {
        return getPSDEServiceAPIMethod().getPSDEServiceAPIMethodInput().getPSDEMethodDTO();
    }

    public IPSDEMethodDTO getReturnDTO() {
        if(getPSDEServiceAPIMethod().getPSDEServiceAPIMethodReturn()==null||getPSDEServiceAPIMethod().getPSDEServiceAPIMethodReturn().getPSDEMethodDTO()==null)
            return getInputDTO();
        return getPSDEServiceAPIMethod().getPSDEServiceAPIMethodReturn().getPSDEMethodDTO();
    }

    private String inParam;
    private String inParam2;
    public String getInParam()
    {
        if(inParam==null) {
            String param=this.getApiEntity().getCodeName()+"DTO";
            IPSDEServiceAPIMethodInput iPSDEServiceAPIMethodInput = getPSDEServiceAPIMethod().getPSDEServiceAPIMethodInput();
            if(iPSDEServiceAPIMethodInput!=null&&iPSDEServiceAPIMethodInput.getPSDEMethodDTO()!=null)
                param=iPSDEServiceAPIMethodInput.getPSDEMethodDTO().getName().replace("FilterDTO", "SearchContext");

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

    public boolean isNeedDto2Domain()
    {
        if("FETCH".equalsIgnoreCase(getPSDEServiceAPIMethod().getMethodType()))
            return false;
        IPSDEServiceAPIMethodInput iPSDEServiceAPIMethodInput = getPSDEServiceAPIMethod().getPSDEServiceAPIMethodInput();
        if(iPSDEServiceAPIMethodInput==null)
            return false;

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

    public boolean isListIn()
    {
        IPSDEServiceAPIMethodInput iPSDEServiceAPIMethodInput = getPSDEServiceAPIMethod().getPSDEServiceAPIMethodInput();
        if(iPSDEServiceAPIMethodInput==null)
            return false;
        return "KEYFIELDS".equalsIgnoreCase(iPSDEServiceAPIMethodInput.getType())||"DTOS".equalsIgnoreCase(iPSDEServiceAPIMethodInput.getType());
    }
    private String inParamName;
    private String inParamName2;



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

    public String typeReturn()
    {
        if(isListReturn()) {
            if ("SIMPLES".equalsIgnoreCase(getPSDEServiceAPIMethod().getPSDEServiceAPIMethodReturn().getType()))
                return PropType.findType(this.getPSDEServiceAPIMethod().getPSDEServiceAPIMethodReturn().getStdDataType()).java;
            else if ("DTOS".equalsIgnoreCase(getPSDEServiceAPIMethod().getPSDEServiceAPIMethodReturn().getType())
                    ||"OBJECTS".equalsIgnoreCase(getPSDEServiceAPIMethod().getPSDEServiceAPIMethodReturn().getType()))
                return this.getPSDEServiceAPIMethod().getPSDEServiceAPIMethodReturn().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.getApiEntity().getCodeName()+"DTO";

            if(getPSDEServiceAPIMethod().getPSDEServiceAPIMethodReturn()!=null&&getPSDEServiceAPIMethod().getPSDEServiceAPIMethodReturn().getPSDEMethodDTO()!=null)
                param=getPSDEServiceAPIMethod().getPSDEServiceAPIMethodReturn().getPSDEMethodDTO().getName();

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

        return outParam;
    }

    private Map permission;

    public Map getPermission()
    {
        if( this.getName().equalsIgnoreCase("CheckKey")||this.getName().equalsIgnoreCase("GetDraft")||
                (this.getPSDEServiceAPIMethod().getPSDEAction()!=null&&this.getPSDEServiceAPIMethod().getPSDEAction().getPSDEOPPriv()!=null&&
                "NONE".equalsIgnoreCase(this.getPSDEServiceAPIMethod().getPSDEAction().getPSDEOPPriv().getName()))||
                (this.getPSDEServiceAPIMethod().getPSDEDataSet()!=null&&this.getPSDEServiceAPIMethod().getPSDEDataSet().getPSDEOPPriv()!=null&&
                        "NONE".equalsIgnoreCase(this.getPSDEServiceAPIMethod().getPSDEDataSet().getPSDEOPPriv().getName()))  )
            return null;
        permission=new HashMap();
        permission.put("ano", "PreAuthorize");
        this.getInParam();
        if(this.getApiEntity()==null||this.getApiEntity().getEntity()==null||(!this.getApiEntity().getEntity().isHasScopes())) {
            if("FETCH".equalsIgnoreCase(getPSDEServiceAPIMethod().getMethodType())) {
                permission.put("cond","hasAnyAuthority('ROLE_SUPERADMIN','"+this.getApiEntity().getEntity().getSystem().getDeploySysId()+"-"+this.getApiEntity().getEntity().getCodeName()+"-"+this.getName().replace("Fetch","search")+"-all','"+this.getApiEntity().getEntity().getSystem().getDeploySysId()+"-"+this.getApiEntity().getEntity().getCodeName()+"-Get-all')");
            }
            else if (this.getPSDEServiceAPIMethod().getPSDEAction()!=null&&this.getPSDEServiceAPIMethod().getPSDEAction().getPSDEOPPriv()==null&&(!lang.containsKey(this.getName().toUpperCase())))
                permission.put("cond","hasAnyAuthority('ROLE_SUPERADMIN','"+this.getApiEntity().getEntity().getSystem().getDeploySysId()+"-"+this.getApiEntity().getEntity().getCodeName()+"-"+this.getName()+"-all','"+this.getApiEntity().getEntity().getSystem().getDeploySysId()+"-"+this.getApiEntity().getEntity().getCodeName()+"-Get-all')");
            else
                permission.put("cond","hasAnyAuthority('ROLE_SUPERADMIN','"+this.getApiEntity().getEntity().getSystem().getDeploySysId()+"-"+this.getApiEntity().getEntity().getCodeName()+"-"+this.getName()+"-all')");
        }
        else if("FETCH".equalsIgnoreCase(getPSDEServiceAPIMethod().getMethodType()))
        {
            permission.put("cond","hasAnyAuthority('ROLE_SUPERADMIN','"+this.getApiEntity().getEntity().getSystem().getDeploySysId()+"-"+this.getApiEntity().getEntity().getCodeName()+"-"+this.getName().replace("Fetch","search")+"-all','"+this.getApiEntity().getEntity().getSystem().getDeploySysId()+"-"+this.getApiEntity().getEntity().getCodeName()+"-Get-all')"+
                    " or hasPermission(#"+this.getInParamName()+",'"+this.getApiEntity().getEntity().getSystem().getDeploySysId()+"-"+this.getApiEntity().getEntity().getCodeName()+"-Get')");

        }
        else if(this.getName().equalsIgnoreCase("Get"))
        {
            permission.put("ano", "PostAuthorize");
            permission.put("cond","hasAnyAuthority('ROLE_SUPERADMIN','"+this.getApiEntity().getEntity().getSystem().getDeploySysId()+"-"+this.getApiEntity().getEntity().getCodeName()+"-"+this.getName()+"-all')" +
                    " or hasPermission(this."+StringAdvUtils.camelcase(this.getApiEntity().getDefaultDto().getCodeName())+"Mapping.toDomain(returnObject.body),'"+this.getApiEntity().getEntity().getSystem().getDeploySysId()+"-"+this.getApiEntity().getEntity().getCodeName()+"-"+this.getName()+"')");

        }
        else if(this.getName().equalsIgnoreCase("Update")||this.getName().equalsIgnoreCase("Remove")||ObjectUtils.isEmpty(this.getInParam()))
        {
            permission.put("cond","hasAnyAuthority('ROLE_SUPERADMIN','"+this.getApiEntity().getEntity().getSystem().getDeploySysId()+"-"+this.getApiEntity().getEntity().getCodeName()+"-"+this.getName()+"-all')" +
                    " or hasPermission(this."+StringAdvUtils.camelcase(this.getApiEntity().getEntity().getCodeName())+"Service.get(#"+StringAdvUtils.camelcase(apiEntity.getEntity().getKeyField().getCodeName())+"),'"+this.getApiEntity().getEntity().getSystem().getDeploySysId()+"-"+this.getApiEntity().getEntity().getCodeName()+"-"+this.getName()+"')");
        }
        else if(this.getName().equalsIgnoreCase("Create")||this.getName().equalsIgnoreCase("Save")||this.isNeedDto2Domain())
        {
            permission.put("cond","hasAnyAuthority('ROLE_SUPERADMIN','"+this.getApiEntity().getEntity().getSystem().getDeploySysId()+"-"+this.getApiEntity().getEntity().getCodeName()+"-"+this.getName()+"-all')" +
                    " or hasPermission(this."+StringAdvUtils.camelcase(this.getApiEntity().getDefaultDto().getCodeName())+"Mapping.toDomain(#"+this.getInParamName()+"),'"+this.getApiEntity().getEntity().getSystem().getDeploySysId()+"-"+this.getApiEntity().getEntity().getCodeName()+"-"+this.getName()+"')");
        }
        return permission;
    }


}
