package cn.ibizlab.codegen.model;

import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.Accessors;
import net.ibizsys.model.dataentity.action.IPSDEAction;
import net.ibizsys.model.dataentity.action.IPSDEActionLogic;
import net.ibizsys.model.dataentity.action.IPSDELogicAction;
import net.ibizsys.model.dataentity.action.IPSDEScriptAction;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.util.*;

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

    public ActionModel(EntityModel entityModel, IPSDEAction action) {
        this.opt = action;
        this.entity = entityModel;
        this.setCodeName(action.getCodeName());
        this.setName(action.getName());
        this.setId(String.format("%1$s-%2$s", entity.getCodeName(), action.getCodeName()));

        if (!CollectionUtils.isEmpty(this.getDEAction().getBeforePSDEActionLogics())) {
            for (int i = 0; i < action.getBeforePSDEActionLogics().size(); i++) {
                IPSDEActionLogic iPSDEActionLogic = action.getBeforePSDEActionLogics().get(i);
                if ((iPSDEActionLogic.getPSDELogic() != null && iPSDEActionLogic.getPSDELogic().isEnableBackend())
                        || iPSDEActionLogic.getDstPSDEAction() != null && iPSDEActionLogic.getDstPSDEAction().isEnableBackend()) {
                    beforeActionLogics.add(new ActionLogicModel(this, iPSDEActionLogic, i));
                }
            }
        }

        if (!CollectionUtils.isEmpty(this.getDEAction().getAfterPSDEActionLogics())) {
            for (int i = 0; i < action.getAfterPSDEActionLogics().size(); i++) {
                IPSDEActionLogic iPSDEActionLogic = action.getAfterPSDEActionLogics().get(i);
                if ((iPSDEActionLogic.getPSDELogic() != null && iPSDEActionLogic.getPSDELogic().isEnableBackend())
                        || iPSDEActionLogic.getDstPSDEAction() != null && iPSDEActionLogic.getDstPSDEAction().isEnableBackend()) {
                    afterActionLogics.add(new ActionLogicModel(this, iPSDEActionLogic, i));
                }
            }
        }
    }

    private List<ActionLogicModel> beforeActionLogics = new ArrayList<>();

    private List<ActionLogicModel> afterActionLogics = new ArrayList<>();

    public IPSDEAction getDEAction() {
        return (IPSDEAction) opt;
    }

    private EntityModel entity;

    public boolean isGetAction() {
        return codeName.toLowerCase().startsWith("get");
    }

    public boolean isEnableBackend() {
        return this.getDEAction().isEnableBackend();
    }

    public boolean hasBeforeLogics() {
        return beforeActionLogics.size() > 0;
    }

    public boolean hasBeforeLogicsDEAction() {
        return beforeActionLogics.stream().anyMatch(actionLogicModel -> actionLogicModel.getPSDEActionLogic().getDstPSDEAction() != null);
    }

    public List<String> getBeforeLogicParams() {
        List<String> params = new ArrayList<>();
        if (hasBeforeLogics()) {
            Map<String, String> map = new HashMap<>();
            for (ActionLogicModel actionLogicModel : beforeActionLogics) {
                IPSDEActionLogic iPSDEActionLogic = actionLogicModel.getPSDEActionLogic();
                if (iPSDEActionLogic.getDstPSDE() != null && iPSDEActionLogic.getDstPSDEAction() != null) {
                    if (!map.containsKey(iPSDEActionLogic.getDstPSDE().getCodeName())) {
                        String param = String.format("<tns:metaData express=\"T(cn.ibizlab.util.security.SpringContextHolder).getBean(T(%s.core.%s.service.%sService))\" name=\"%sService\" type=\"service\"/>",
                                entity.getSystem().getPackageName(),
                                iPSDEActionLogic.getDstPSDE().getPSSystemModule().getCodeName().toLowerCase(),
                                iPSDEActionLogic.getDstPSDE().getCodeName(),
                                iPSDEActionLogic.getDstPSDE().getCodeName().toLowerCase()
                        );
                        params.add(param);
                        map.put(iPSDEActionLogic.getDstPSDE().getCodeName(), "");
                    }
                    if (!map.containsKey("srf_entity")) {
                        params.add("<tns:metaData express=\"\" name=\"et\" type=\"entity\"/>");
                        map.put("srf_entity", "");
                    }
                }
            }
        }
        return params;
    }

    public List<String> getBeforeLogicSequenceFlows() {
        List<String> params = new ArrayList<>();
        if (hasBeforeLogics()) {
            String source = "begin";
            for (int i = 0; i < beforeActionLogics.size(); i++) {
                ActionLogicModel actionLogicModel = beforeActionLogics.get(i);
                String target = actionLogicModel.getId();
                params.add(String.format("<sequenceFlow id=\"%1$s_%2$s\" sourceRef=\"%1$s\" targetRef=\"%2$s\"/>", source, target));
                source = target;
                if (i == beforeActionLogics.size() - 1) {
                    params.add(String.format("<sequenceFlow id=\"%1$s_%2$s\" sourceRef=\"%1$s\" targetRef=\"%2$s\"/>", source, "prepareparam1_end"));
                }
            }
        }
        return params;
    }

    public List<String>  getBeforeGlobalParams(){
        List<String> params = new ArrayList<>();
        if (hasBeforeLogicsDEAction()) {
            Map<String, String> map = new HashMap<>();
            for (ActionLogicModel actionLogicModel : beforeActionLogics) {
                IPSDEActionLogic iPSDEActionLogic = actionLogicModel.getPSDEActionLogic();
                if (iPSDEActionLogic.getDstPSDE() != null && iPSDEActionLogic.getDstPSDEAction() != null) {
                    if (!map.containsKey(iPSDEActionLogic.getDstPSDE().getCodeName())) {
                        String param = String.format("global %s.core.%s.service.%sService %sService;",
                                entity.getSystem().getPackageName(),
                                iPSDEActionLogic.getDstPSDE().getPSSystemModule().getCodeName().toLowerCase(),
                                iPSDEActionLogic.getDstPSDE().getCodeName(),
                                iPSDEActionLogic.getDstPSDE().getCodeName().toLowerCase()
                        );
                        params.add(param);
                        map.put(iPSDEActionLogic.getDstPSDE().getCodeName(), "");
                    }
                }
            }
        }
        return params;
    }

    public boolean hasAfterLogics() {
        return afterActionLogics.size() > 0;
    }

    public boolean hasAfterLogicsDEAction() {
        return afterActionLogics.stream().anyMatch(actionLogicModel -> actionLogicModel.getPSDEActionLogic().getDstPSDEAction() != null);
    }

    public List<String> getAfterLogicParams() {
        List<String> params = new ArrayList<>();
        if (hasAfterLogics()) {
            Map<String, String> map = new HashMap<>();
            for (ActionLogicModel actionLogicModel : afterActionLogics) {
                IPSDEActionLogic iPSDEActionLogic = actionLogicModel.getPSDEActionLogic();
                if (iPSDEActionLogic.getDstPSDE() != null && iPSDEActionLogic.getDstPSDEAction() != null) {
                    if (!map.containsKey(iPSDEActionLogic.getDstPSDE().getCodeName())) {
                        String param = String.format("<tns:metaData express=\"T(cn.ibizlab.util.security.SpringContextHolder).getBean(T(%s.core.%s.service.%sService))\" name=\"%sService\" type=\"service\"/>",
                                entity.getSystem().getPackageName(),
                                iPSDEActionLogic.getDstPSDE().getPSSystemModule().getCodeName().toLowerCase(),
                                iPSDEActionLogic.getDstPSDE().getCodeName(),
                                iPSDEActionLogic.getDstPSDE().getCodeName().toLowerCase()
                        );
                        params.add(param);
                        map.put(iPSDEActionLogic.getDstPSDE().getCodeName(), "");
                    }
                    if (!map.containsKey("srf_entity")) {
                        params.add("<tns:metaData express=\"\" name=\"et\" type=\"entity\"/>");
                        map.put("srf_entity", "");
                    }
                }
            }
        }
        return params;
    }

    public List<String> getAfterLogicSequenceFlows() {
        List<String> params = new ArrayList<>();
        if (hasAfterLogics()) {
            String source = "begin";
            for (int i = 0; i < afterActionLogics.size(); i++) {
                ActionLogicModel actionLogicModel = afterActionLogics.get(i);
                String target = actionLogicModel.getId();
                params.add(String.format("<sequenceFlow id=\"%1$s_%2$s\" sourceRef=\"%1$s\" targetRef=\"%2$s\"/>", source, target));
                source = target;
                if (i == afterActionLogics.size() - 1) {
                    params.add(String.format("<sequenceFlow id=\"%1$s_%2$s\" sourceRef=\"%1$s\" targetRef=\"%2$s\"/>", source, "prepareparam1_end"));
                }
            }
        }
        return params;
    }

    public List<String>  getAfterGlobalParams(){
        List<String> params = new ArrayList<>();
        if (hasAfterLogicsDEAction()) {
            Map<String, String> map = new HashMap<>();
            for (ActionLogicModel actionLogicModel : afterActionLogics) {
                IPSDEActionLogic iPSDEActionLogic = actionLogicModel.getPSDEActionLogic();
                if (iPSDEActionLogic.getDstPSDE() != null && iPSDEActionLogic.getDstPSDEAction() != null) {
                    if (!map.containsKey(iPSDEActionLogic.getDstPSDE().getCodeName())) {
                        String param = String.format("global %s.core.%s.service.%sService %sService;",
                                entity.getSystem().getPackageName(),
                                iPSDEActionLogic.getDstPSDE().getPSSystemModule().getCodeName().toLowerCase(),
                                iPSDEActionLogic.getDstPSDE().getCodeName(),
                                iPSDEActionLogic.getDstPSDE().getCodeName().toLowerCase()
                        );
                        params.add(param);
                        map.put(iPSDEActionLogic.getDstPSDE().getCodeName(), "");
                    }
                }
            }
        }
        return params;
    }



    public String getInParam() {
        String param = this.getEntity().getCodeName();
        if (getDEAction().getPSDEActionInput() == null)
            return param;
        if ("KEYFIELD".equalsIgnoreCase(getDEAction().getPSDEActionInput().getType()))
            param = this.getEntity().getKeyField().getType().java;
        else if ("KEYFIELDS".equalsIgnoreCase(getDEAction().getPSDEActionInput().getType()))
            param = "List<" + this.getEntity().getKeyField().getType().java + ">";
        else if ("DTOS".equalsIgnoreCase(getDEAction().getPSDEActionInput().getType()))
            param = "List<" + param + ">";
        return param;
    }

    public String getInParamName() {
        String param = "dto";
        if (getDEAction().getPSDEActionInput() == null)
            return param;
        if ("KEYFIELD".equalsIgnoreCase(getDEAction().getPSDEActionInput().getType()))
            param = "key";
        else if ("KEYFIELDS".equalsIgnoreCase(getDEAction().getPSDEActionInput().getType()))
            param = "keys";
        return param;
    }

    public boolean isVoidReturn() {
        if (getDEAction().getPSDEActionReturn() == null)
            return true;
        if (!"VOID".equalsIgnoreCase(getDEAction().getPSDEActionReturn().getType()))
            return false;
        return true;
    }

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

    public String typeReturn() {
        if (isListReturn()) {
            if ("SIMPLES".equalsIgnoreCase(getDEAction().getPSDEActionReturn().getType()))
                return PropType.findType(this.getDEAction().getPSDEActionReturn().getStdDataType()).java;
            else if ("DTOS".equalsIgnoreCase(getDEAction().getPSDEActionReturn().getType())
                    || "OBJECTS".equalsIgnoreCase(getDEAction().getPSDEActionReturn().getType()))
                return this.getEntity().getCodeName();
        }
        return "";
    }

    public String getOutParam() {
        String param = this.getEntity().getCodeName();
        if (getDEAction().getPSDEActionReturn() == null)
            return param;
        if ("VOID".equalsIgnoreCase(getDEAction().getPSDEActionReturn().getType()))
            return getInParam();
        if ("SIMPLE".equalsIgnoreCase(getDEAction().getPSDEActionReturn().getType()))
            param = PropType.findType(this.getDEAction().getPSDEActionReturn().getStdDataType()).java;
        else if ("SIMPLES".equalsIgnoreCase(getDEAction().getPSDEActionReturn().getType()))
            param = "List<" + PropType.findType(this.getDEAction().getPSDEActionReturn().getStdDataType()).java + ">";
        else if ("DTOS".equalsIgnoreCase(getDEAction().getPSDEActionReturn().getType())
                || "OBJECTS".equalsIgnoreCase(getDEAction().getPSDEActionReturn().getType()))
            param = "List<" + param + ">";
        return param;
    }

    public Set<String> getLogics() {
        Set<String> validLogic = new HashSet<>();
        if (!ObjectUtils.isEmpty(getDEAction().getBeforePSDEActionLogics())) {
            getDEAction().getBeforePSDEActionLogics().forEach(logic -> {
                if ((logic.isValid() && logic.isInternalLogic() && logic.getPSDELogic().isEnableBackend()) ||
                        (logic.getDstPSDE() != null && logic.getDstPSDEAction() != null && (!(logic.getDstPSDEAction() instanceof IPSDEScriptAction))))
                    validLogic.add((entity.codeName + this.codeName).toLowerCase() + "before.bpmn");
            });
        }
        if (!ObjectUtils.isEmpty(getDEAction().getAfterPSDEActionLogics())) {
            getDEAction().getAfterPSDEActionLogics().forEach(logic -> {
                if ((logic.isValid() && logic.isInternalLogic() && logic.getPSDELogic().isEnableBackend()) ||
                        (logic.getDstPSDE() != null && logic.getDstPSDEAction() != null && (!(logic.getDstPSDEAction() instanceof IPSDEScriptAction))))
                    validLogic.add((entity.codeName + this.codeName).toLowerCase() + "after.bpmn");
            });
        }
        if ("DELOGIC".equalsIgnoreCase(getDEAction().getActionType()) && getDEAction() instanceof IPSDELogicAction) {
            validLogic.add((entity.codeName + this.codeName).toLowerCase() + "exec.bpmn");
        }
        return validLogic;
    }

}
