package cc.smtweb.system.bpm.web.engine.model.common;

import cc.smtweb.framework.core.cache.AbstractCache;
import cc.smtweb.framework.core.cache.CacheManager;
import cc.smtweb.framework.core.common.R;
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.jdbc.IDbWorker;
import cc.smtweb.framework.core.db.vo.ModelField;
import cc.smtweb.framework.core.db.vo.ModelIndex;
import cc.smtweb.framework.core.db.vo.ModelTable;
import cc.smtweb.framework.core.exception.BizException;
import cc.smtweb.framework.core.mvc.service.TreeHelper;
import cc.smtweb.framework.core.util.StringUtil;
import cc.smtweb.system.bpm.web.design.form.define.PageDataset;
import cc.smtweb.system.bpm.web.design.form.define.PageDatasetFilter;
import cc.smtweb.system.bpm.web.engine.dynPage.AbstractDynPageHandler;
import org.apache.commons.lang3.StringUtils;

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

/**
 * Created by Akmm at 2022/4/21 17:53
 * 模型保存handler
 * 入参：{pageId, data:}
 */
public class ModelSaveHandler<T extends DefaultEntity> extends AbstractDynPageHandler {
    private Map<String, List<? extends DefaultEntity>> mapTreeBean = new HashMap<>();
    protected T bean;
    private String cardDsName = ModelHelper.DATASET_NAME_CARD;

    public ModelSaveHandler() {
    }

    public ModelSaveHandler(String cardDsName) {
        this.cardDsName = cardDsName;
    }

    /**
     * 保存指定数据集操作，入参：{pageId,dataset:"", data:{form:{},list: {total:0,rows:[]}}, filter:{}}
     */
    public R save() {
        SwMap filter = params.readMap("filter");
        //待保存数据
        SwMap data = params.readMap("data");
        if (data == null) throw new BizException("没有收到待保存的的数据！");

        readFromPage(data, filter);
        checkValid();
        DbEngine.getInstance().doTrans(new IDbWorker() {
            @Override
            public void work() {
                doSave();
            }

            @Override
            public void doAfterDbCommit() {
                doAfterCommit();
            }

            @Override
            public void doAfterDbRollback() {
                doAfterRollback();
            }
        });
        bean.removeStatus();
        SwMap ret = ModelHelper.buildRetData(cardDsName, bean.getData());
        afterSave(ret);
        return R.success(ret);
    }

    protected void afterSave(SwMap ret) {
    }

    /**
     * 从页面获取待保存的bean
     *
     * @param pageDataSet
     * @param pageData
     * @return
     */
    protected void readFromPage(SwMap pageData, SwMap filter) {
        //读取待保存的bean
        bean = readBeanFromPage(cardDsName, pageData, filter);
    }

    //给子类使用的工具方法：从页面读取一个bean
    protected <E extends DefaultEntity> E readBeanFromPage(String dsName, SwMap pageData, SwMap filter) {
        //对应的数据集定义
        PageDataset pageDataSet = findCardDataset(dsName);

        ModelTable table = ModelTableCache.getInstance().get(pageDataSet.masterTable);
        if (table == null) throw new BizException("没有找到待保存的表定义：" + pageDataSet.name);

        SwMap data = pageData.readMap(pageDataSet.name);
        if (data == null) throw new BizException("没有找到待保存的表数据：" + pageDataSet.name);
        data = data.readMap("form");
        if (data == null) throw new BizException("没有找到待保存的表数据：" + pageDataSet.name);

        boolean isNew = data.readBool(DefaultEntity.statusKey);
        EntityDao<E> dao = DbEngine.getInstance().findDao(table.getName());
        E vo;
        if (isNew) {
            vo = dao.createBean();
            //暂时不考虑list保存的情况
            vo.getData().putAll(data);
        } else {
            long id = data.readLong(table.getIdField());
            vo = dao.queryEntity(id);
            if (vo == null) {
                throw new BizException("没有找到待保存的记录：" + table.getName() + "." + id);
            }
            //暂时不考虑list保存的情况
            vo.getData().putAll(data);
            vo.setIsNew(false);
        }
        if (filter != null && vo.isNew()) {//有过滤条件，将关联的值设上
            setLinkValue(pageDataSet, vo, f -> filter.get(f.name));
        }
        return vo;
    }
    /**
     * 保存校验
     *
     * @param bean
     */
    protected void checkValid() {
        checkValid(bean);
    }

    //给子类使用的工具方法：校验bean
    protected <E extends DefaultEntity> void checkValid(E vo) {
        ModelTable table = ModelTableCache.getInstance().getByName(vo.getTableName());
        for (ModelField field : table.getFields()) {
            String value = vo.getStr(field.getName());
            //非空校验
            if (field.isNotNull() && StringUtils.isEmpty(value)) {
                throw new BizException("字段不允许为空：" + field.getTitle());
            }

            //长度校验
            if (StringUtils.isNotEmpty(value)) {
                int len = SwEnum.DataType.instance.getByValue(field.getDataType()).dataLength;
                if (len > 0 && StringUtil.getStrLenB(value) > len) {
                    throw new BizException("字段值超长：" + field.getTitle());
                }
            }
        }
        //唯一键校验
        EntityDao<E> dao = DbEngine.getInstance().findDao(vo.getTableName());
        for (ModelIndex mi : table.getIndexes()) {
            if (mi.isUnique()) {
                dao.checkUnique(vo, mi.getFields().split(","));
            }
        }
    }

    protected void doSave() {
        saveBean(bean);
    }

    //给子类使用的工具方法：保存bean
    protected <E extends DefaultEntity> void saveBean(E entity) {
        final String tableName = entity.getTableName();
        EntityDao<E> dao = DbEngine.getInstance().findDao(tableName);
        if (entity.isNew()) {
            dao.insertEntity(entity);
        } else {
            ModelTable table = ModelTableCache.getInstance().getByName(tableName);
            ModelField field = table.findFieldByType(SwEnum.FieldType.UPDATE_USER.value);
            if (field != null) entity.put(field.getName(), us.getUserId());

            dao.updateEntity(entity);
            if (table.getType() == SwEnum.TableType.TYPE_TREE.value) {
                List<E> listTreeBean = TreeHelper.getTreeHelper(tableName).resetTreeLevel(entity);
                mapTreeBean.put(tableName, listTreeBean);
            }
        }
    }

    //保存后
    protected void doAfterCommit() {
        commitBean(bean);
    }

    //给子类使用的工具方法：提交后事件
    protected <E extends DefaultEntity> void commitBean(E entity) {
        final String tableName = entity.getTableName();
        ModelTable table = ModelTableCache.getInstance().getByName(tableName);
        if (table.isNeedCache()) {
            AbstractCache<DefaultEntity> cache = CacheManager.getIntance().getCache(tableName);
            List<E> listTreeBean = (List<E>)mapTreeBean.get(tableName);
            //树型表，父亲改变了，要多处理下缓存；还有个东东：级次码
            if (listTreeBean != null && !listTreeBean.isEmpty()) {
                for (DefaultEntity b : listTreeBean) {
                    cache.put(b);
                }
            } else {
                cache.put(entity);
            }
        }
    }

    //事务回滚
    protected void doAfterRollback() {
        rollBean(bean);
    }

    //给子类使用的工具方法：回滚指定的bean
    protected <E extends DefaultEntity> void rollBean(E bean) {
        final String tableName = bean.getTableName();
        ModelTable table = ModelTableCache.getInstance().getByName(tableName);
        if (table.isNeedCache()) {
            AbstractCache<E> cache = CacheManager.getIntance().getCache(tableName);
            cache.reset(bean);
        }
    }

    //将关联的值设上
    protected void setLinkValue(PageDataset pageDataSet, DefaultEntity bean, IGetValue iGetValue) {
        ModelTable table = ModelTableCache.getInstance().getByName(bean.getTableName());
        for (PageDatasetFilter f : pageDataSet.filters) {
            String v = bean.getStr(f.field);
            //有值，就不管
            if (v != null && !v.equals(table.findField(f.field).getDefaultValue())) continue;

            if (SwEnum.FilterType.CONST.value.equals(f.type)) {//常量
                bean.put(f.field, f.value);
            } else if (SwEnum.FilterType.PARAM.value.equals(f.type)) {//参数
                bean.put(f.field, f.value);
            } else if (SwEnum.FilterType.LINK.value.equals(f.type)) {//参数
                Object value = iGetValue.getValue(f);
                if (value != null) {
                    bean.put(f.field, value);
                }
            }
        }
    }

    public interface IGetValue {
        Object getValue(PageDatasetFilter f);
    }
}
