package cc.smtweb.system.bpm.web.design.db;

import cc.smtweb.framework.core.common.SwEnum;
import cc.smtweb.framework.core.common.SwMap;
import cc.smtweb.framework.core.db.DbEngine;
import cc.smtweb.framework.core.db.EntityDao;
import cc.smtweb.framework.core.db.cache.ModelTableCache;
import cc.smtweb.framework.core.db.impl.DefaultEntity;
import cc.smtweb.framework.core.db.vo.ModelCatalog;
import cc.smtweb.framework.core.db.vo.ModelTable;
import cc.smtweb.framework.core.mvc.service.AbstractTreeHandler;
import cc.smtweb.framework.core.mvc.service.TreeHelper;
import cc.smtweb.framework.core.session.UserSession;
import cc.smtweb.framework.core.util.CommUtil;
import cc.smtweb.framework.core.util.StringUtil;
import cc.smtweb.system.bpm.web.design.flow.ModelProc;
import cc.smtweb.system.bpm.web.design.flow.ModelProcCache;
import cc.smtweb.system.bpm.web.design.form.ModelForm;
import cc.smtweb.system.bpm.web.design.form.ModelFormCache;

import java.util.*;

/**
 * Created by Akmm at 2022/3/21 18:22
 */
public class ModelCatalogTreeHandler extends AbstractTreeHandler<DefaultEntity> {
    //查询类型：0-目录；1-表定义;2-页面；3-控件；4-流程定义 23-页面和控件
    private final static int TYPE_CATALOG = 0;
    private final static int TYPE_TABLE = 1;
    private final static int TYPE_PAGE = 2;
    private final static int TYPE_WIDGET = 3;
    private final static int TYPE_PROC = 4;
    private final static int TYPE_FORM = 23;

    private long prj_id;//所属项目
    private int type;//查询类型：0-目录；1-表定义;2-页面定义
    private boolean exc_empty;//排除空目录，type非目录时有效
    private boolean exc_depend;//排除依赖项目的目录
    private boolean only_bill;//仅限单据页面（billType>0）
    private ModelCatalogTreeHelper mcTreeHelper = null;

    //模块子页面，暂存
    private Map<Long, List<DefaultEntity>> mapFormChild = new HashMap<>();

    @Override
    public void init(SwMap params, UserSession us) {
        super.init(params, us);
        type = params.readInt("type");
        prj_id = params.readLong("prj_id");
        exc_empty = params.readBool("exc_empty");
        exc_depend = params.readBool("exc_depend");
        only_bill = params.readBool("only_bill");
        if (only_bill) exc_empty = true;
        mcTreeHelper = (ModelCatalogTreeHelper) TreeHelper.getTreeHelper(ModelCatalog.ENTITY_NAME);
    }

    @Override
    protected List<DefaultEntity> getChildren(DefaultEntity bean) {
        if (bean instanceof ModelCatalog) {
            return super.getChildren(bean);
        }
        return null;
    }

    @Override
    protected List<DefaultEntity> filterData() {
        Set<Long> setId = exc_depend ? new HashSet<>(Arrays.asList(prj_id)): ModelProjectCache.getInstance().getDependsPrjIds(prj_id);
        if (setId.isEmpty()) return new ArrayList<>();
        String sqlPrjId = CommUtil.getSqlInIds(setId);

        EntityDao<ModelCatalog> dao = DbEngine.getInstance().findDao(ModelCatalog.ENTITY_NAME);
        String text = "%" + params.readString("text") + "%";
        List<ModelCatalog> list = dao.queryWhere(" mc_prj_id in (" + sqlPrjId + ") and (mc_name like ? or mc_code like ?) order by mc_name", text, text);
        List<DefaultEntity> listRet = new ArrayList<>(list);

        switch (type) {
            case TYPE_TABLE:
                EntityDao<ModelTable> tabledao = DbEngine.getInstance().findDao(ModelTable.class);
                List<ModelTable> l = tabledao.queryWhere(" tb_prj_id in (" + sqlPrjId + ") and (tb_name like ? or tb_title like ?) order by tb_name", text, text);
                listRet.addAll(l);
                break;
            case TYPE_PROC:
                EntityDao<ModelProc> procDao = DbEngine.getInstance().findDao(ModelProc.class);
                List<ModelProc> lp = procDao.queryWhere(" tb_prj_id in (" + sqlPrjId + ") and (prc_name like ? or prc_code like ?) order by prc_name", text, text);
                listRet.addAll(lp);
                break;
            case TYPE_PAGE:
            case TYPE_WIDGET:
            case TYPE_FORM:
                EntityDao<ModelForm> formdao = DbEngine.getInstance().findDao(ModelForm.class);
                List<ModelForm> lf;
                switch (type) {
                    case TYPE_PAGE:
                        lf = formdao.queryWhere(" mf_prj_id in (" + sqlPrjId + ") and mf_type<>? and (mf_name like ? or mf_title like ?) order by tb_name", SwEnum.FormType.WIDGET.value, text, text);
                        break;
                    case TYPE_WIDGET:
                        lf = formdao.queryWhere(" mf_prj_id in (" + sqlPrjId + ") and mf_type=? and (mf_name like ? or mf_title like ?) order by tb_name", SwEnum.FormType.WIDGET.value, text, text);
                        break;
                    default:
                        lf = formdao.queryWhere(" mf_prj_id in (" + sqlPrjId + ") and (mf_name like ? or mf_title like ?) order by tb_name", text, text);
                }
                listRet.addAll(lf);
        }
        return listRet;
    }

    @Override
    protected List<DefaultEntity> getChildren(long id) {
        List<ModelCatalog> list = mcTreeHelper.getChildren(id, prj_id, exc_depend, (o1, o2) -> StringUtil.chineseCompare(o1.getName(), o2.getName()));
        List<DefaultEntity> listRet;
        if (type != TYPE_CATALOG && exc_empty) {//排除空目录
            listRet = cleanEmpty(list);
        } else {
            listRet = new ArrayList<>(list);
        }

        switch (type) {
            case TYPE_TABLE:
                addTableChildren(listRet, id);
                break;
            case TYPE_PROC:
                addProcChildren(listRet, id);
                break;
            case TYPE_PAGE:
            case TYPE_WIDGET:
            case TYPE_FORM:
                addPageChildren(listRet, id, type);
        }
        return listRet;
    }

    /**
     * 去掉没有叶子的空目录
     *
     * @param list
     * @return
     */
    private List<DefaultEntity> cleanEmpty(List<ModelCatalog> list) {
        if (list.isEmpty()) return new ArrayList<>(list);
        List<DefaultEntity> lret = new ArrayList<>();
        for (ModelCatalog mc : list) {
            if (hasChildren(mc)) lret.add(mc);
        }
        return lret;
    }

    //递归判断，目录是否有儿子
    private boolean hasChildren(ModelCatalog mc) {
        List<DefaultEntity> listRet = new ArrayList<>();
        switch (type) {
            case TYPE_TABLE:
                addTableChildren(listRet, mc.getId());
                break;
            case TYPE_PROC:
                addProcChildren(listRet, mc.getId());
                break;
            case TYPE_PAGE:
            case TYPE_WIDGET:
            case TYPE_FORM:
                addPageChildren(listRet, mc.getId(), type);
        }
        if (!listRet.isEmpty()) return true;
        List<ModelCatalog> list = mcTreeHelper.getChildren(mc.getId(), prj_id, exc_depend, null);
        if (list == null || list.isEmpty()) return false;
        for (ModelCatalog c : list) {
            if (hasChildren(c)) return true;
        }
        return false;
    }

    //增加表
    private void addTableChildren(List<DefaultEntity> listRet, long mcid) {
        Collection<ModelTable> set = ModelTableCache.getInstance().getTablesByMc(mcid, (o1, o2) -> StringUtil.chineseCompare(o1.getName(), o2.getName()));
        if (set == null || set.isEmpty()) return;

        listRet.addAll(set);
    }

    //增加工作流
    private void addProcChildren(List<DefaultEntity> listRet, long mcid) {
        Collection<ModelProc> set = ModelProcCache.getInstance().getProcByMc(mcid, (o1, o2) -> StringUtil.chineseCompare(o1.getName(), o2.getName()));
        if (set == null || set.isEmpty()) return;

        listRet.addAll(set);
    }

    //添加页面，将子页面单独清出来
    private void addForm(List<DefaultEntity> listRet, List<ModelForm> lf, boolean exc_widget) {
        for (ModelForm mf : lf) {
            if (exc_widget && mf.getType() == SwEnum.FormType.WIDGET.value) continue;
            if (only_bill && mf.getBillType() <= 0L) {//清除非单据页面
                continue;
            }
            if (mf.getParent() > 0) {
                List<DefaultEntity> ch = mapFormChild.computeIfAbsent(mf.getParent(), k -> new ArrayList<>());
                ch.add(mf);
            } else {
                listRet.add(mf);
            }
        }
    }

    //增加页面定义
    private void addPageChildren(List<DefaultEntity> listRet, long mcid, int type) {
        List<ModelForm> set = ModelFormCache.getInstance().getFormsByMc(mcid, (o1, o2) -> {
            if (o1.getType() != o2.getType()) return o1.getType() - o2.getType();
            return StringUtil.chineseCompare(o1.getTitle(), o2.getTitle());
        });
        if (set == null || set.isEmpty()) return;
        switch (type) {
            case TYPE_PAGE:
                addForm(listRet, set, true);
                break;
            case TYPE_WIDGET:
                for (ModelForm form : set) {
                    if (form.getType() == SwEnum.FormType.WIDGET.value) {
                        listRet.add(form);
                    }
                }
                break;
            default:
                addForm(listRet, set, false);
        }
    }

    @Override
    protected long getId(DefaultEntity bean) {
        return bean.getEntityId();
    }

    @Override
    protected String getText(DefaultEntity bean) {
        if (bean instanceof ModelCatalog) {
            return ((ModelCatalog) bean).getName();
        }
        if (bean instanceof ModelTable) {
            return ((ModelTable) bean).getTitle();
        }

        if (bean instanceof ModelForm) {
            return ((ModelForm) bean).getTitle();
        }
        if (bean instanceof ModelProc) {
            return ((ModelProc) bean).getName();
        }
        return null;
    }

    @Override
    protected void buildNode(SwMap node, DefaultEntity bean) {
        super.buildNode(node, bean);
        if (bean instanceof ModelCatalog) {
            node.put("type", TYPE_CATALOG);
        } else if (bean instanceof ModelTable) {
            node.put("type", TYPE_TABLE);
        } else if (bean instanceof ModelProc) {
            node.put("type", TYPE_PROC);
        } else if (bean instanceof ModelForm) {
            final ModelForm form = (ModelForm) bean;
            node.put("type", form.getType() + 2);
            // 返回页面名称
            bean.put("pageName", ModelProjectCache.getInstance().getModule(((ModelForm) bean).getPrjId()) + "." + ((ModelForm) bean).getName());
            //是模块，需要加子页面
            if (form.getType() == SwEnum.FormType.MODULE.value) {
                List<DefaultEntity> lf = mapFormChild.get(form.getEntityId());
                if (lf != null && !lf.isEmpty()) {
                    List<SwMap> list = buildNodes(lf, true);
                    node.put("children", list);
                    node.put("leaf", false);
                }
            }
        }
    }
}
